Merge pi-dev-plus-aosp-without-vendor into stage-aosp-master

Bug: 79597307
Change-Id: I6d6bee71b9424eb478780bbfc06b830eb8ded342
diff --git a/libs/arect/include/android/rect.h b/libs/arect/include/android/rect.h
index 80741c0..b36728e 100644
--- a/libs/arect/include/android/rect.h
+++ b/libs/arect/include/android/rect.h
@@ -33,23 +33,26 @@
 #endif
 
 /**
- * {@link ARect} is a struct that represents a rectangular window area.
+ * Rectangular window area.
  *
- * It is used with {@link
- * ANativeActivityCallbacks::onContentRectChanged} event callback and
- * ANativeWindow_lock() function.
+ * This is the NDK equivalent of the android.graphics.Rect class in Java. It is
+ * used with {@link ANativeActivityCallbacks::onContentRectChanged} event
+ * callback and the ANativeWindow_lock() function.
+ *
+ * In a valid ARect, left <= right and top <= bottom. ARect with left=0, top=10,
+ * right=1, bottom=11 contains only one pixel at x=0, y=10.
  */
 typedef struct ARect {
 #ifdef __cplusplus
     typedef int32_t value_type;
 #endif
-    /** left position */
+    /// Minimum X coordinate of the rectangle.
     int32_t left;
-    /** top position */
+    /// Minimum Y coordinate of the rectangle.
     int32_t top;
-    /** left position */
+    /// Maximum X coordinate of the rectangle.
     int32_t right;
-    /** bottom position */
+    /// Maximum Y coordinate of the rectangle.
     int32_t bottom;
 } ARect;
 
diff --git a/libs/binder/ActivityManager.cpp b/libs/binder/ActivityManager.cpp
new file mode 100644
index 0000000..2728f35
--- /dev/null
+++ b/libs/binder/ActivityManager.cpp
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <mutex>
+#include <unistd.h>
+
+#include <binder/ActivityManager.h>
+#include <binder/Binder.h>
+#include <binder/IServiceManager.h>
+
+#include <utils/SystemClock.h>
+
+namespace android {
+
+ActivityManager::ActivityManager()
+{
+}
+
+sp<IActivityManager> ActivityManager::getService()
+{
+    std::lock_guard<Mutex> scoped_lock(mLock);
+    int64_t startTime = 0;
+    sp<IActivityManager> service = mService;
+    while (service == NULL || !IInterface::asBinder(service)->isBinderAlive()) {
+        sp<IBinder> binder = defaultServiceManager()->checkService(String16("activity"));
+        if (binder == NULL) {
+            // Wait for the activity service to come back...
+            if (startTime == 0) {
+                startTime = uptimeMillis();
+                ALOGI("Waiting for activity service");
+            } else if ((uptimeMillis() - startTime) > 1000000) {
+                ALOGW("Waiting too long for activity service, giving up");
+                service = NULL;
+                break;
+            }
+            usleep(25000);
+        } else {
+            service = interface_cast<IActivityManager>(binder);
+            mService = service;
+        }
+    }
+    return service;
+}
+
+int ActivityManager::openContentUri(const String16& stringUri)
+{
+    sp<IActivityManager> service = getService();
+    return service != NULL ? service->openContentUri(stringUri) : -1;
+}
+
+void ActivityManager::registerUidObserver(const sp<IUidObserver>& observer,
+                                          const int32_t event,
+                                          const int32_t cutpoint,
+                                          const String16& callingPackage)
+{
+    sp<IActivityManager> service = getService();
+    if (service != NULL) {
+        service->registerUidObserver(observer, event, cutpoint, callingPackage);
+    }
+}
+
+void ActivityManager::unregisterUidObserver(const sp<IUidObserver>& observer)
+{
+    sp<IActivityManager> service = getService();
+    if (service != NULL) {
+        service->unregisterUidObserver(observer);
+    }
+}
+
+bool ActivityManager::isUidActive(const uid_t uid, const String16& callingPackage)
+{
+    sp<IActivityManager> service = getService();
+    if (service != NULL) {
+        return service->isUidActive(uid, callingPackage);
+    }
+    return false;
+}
+
+status_t ActivityManager::linkToDeath(const sp<IBinder::DeathRecipient>& recipient) {
+    sp<IActivityManager> service = getService();
+    if (service != NULL) {
+        return IInterface::asBinder(service)->linkToDeath(recipient);
+    }
+    return INVALID_OPERATION;
+}
+
+status_t ActivityManager::unlinkToDeath(const sp<IBinder::DeathRecipient>& recipient) {
+    sp<IActivityManager> service = getService();
+    if (service != NULL) {
+        return IInterface::asBinder(service)->unlinkToDeath(recipient);
+    }
+    return INVALID_OPERATION;
+}
+
+}; // namespace android
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index d4db8c8..b8d6c78 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -39,6 +39,7 @@
     double_loadable: true,
 
     srcs: [
+        "ActivityManager.cpp",
         "AppOpsManager.cpp",
         "Binder.cpp",
         "BpBinder.cpp",
@@ -57,11 +58,13 @@
         "IResultReceiver.cpp",
         "IServiceManager.cpp",
         "IShellCallback.cpp",
+        "IUidObserver.cpp",
         "MemoryBase.cpp",
         "MemoryDealer.cpp",
         "MemoryHeapBase.cpp",
         "Parcel.cpp",
         "PermissionCache.cpp",
+        "PermissionController.cpp",
         "PersistableBundle.cpp",
         "ProcessInfoService.cpp",
         "ProcessState.cpp",
@@ -73,6 +76,28 @@
         ":libbinder_aidl",
     ],
 
+    target: {
+        vendor: {
+            exclude_srcs: [
+                "ActivityManager.cpp",
+                "AppOpsManager.cpp",
+                "IActivityManager.cpp",
+                "IAppOpsCallback.cpp",
+                "IAppOpsService.cpp",
+                "IBatteryStats.cpp",
+                "IMediaResourceMonitor.cpp",
+                "IPermissionController.cpp",
+                "IProcessInfoService.cpp",
+                "IUidObserver.cpp",
+                "PermissionCache.cpp",
+                "PermissionController.cpp",
+                "ProcessInfoService.cpp",
+                "IpPrefix.cpp",
+                ":libbinder_aidl",
+            ],
+        },
+    },
+
     aidl: {
         export_aidl_headers: true,
     },
diff --git a/libs/binder/AppOpsManager.cpp b/libs/binder/AppOpsManager.cpp
index 4a9b9a7..a494e22 100644
--- a/libs/binder/AppOpsManager.cpp
+++ b/libs/binder/AppOpsManager.cpp
@@ -100,11 +100,12 @@
             : APP_OPS_MANAGER_UNAVAILABLE_MODE;
 }
 
-int32_t AppOpsManager::startOp(int32_t op, int32_t uid, const String16& callingPackage) {
+int32_t AppOpsManager::startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage,
+        bool startIfModeDefault) {
     sp<IAppOpsService> service = getService();
     return service != nullptr
-            ? service->startOperation(getToken(service), op, uid, callingPackage)
-            : APP_OPS_MANAGER_UNAVAILABLE_MODE;
+            ? service->startOperation(getToken(service), op, uid, callingPackage,
+                    startIfModeDefault) : APP_OPS_MANAGER_UNAVAILABLE_MODE;
 }
 
 void AppOpsManager::finishOp(int32_t op, int32_t uid, const String16& callingPackage) {
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
index 49ff460..7342126 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -21,6 +21,7 @@
 
 #include <binder/IPCThreadState.h>
 #include <binder/IResultReceiver.h>
+#include <cutils/compiler.h>
 #include <utils/Log.h>
 
 #include <stdio.h>
@@ -32,6 +33,23 @@
 
 // ---------------------------------------------------------------------------
 
+Mutex BpBinder::sTrackingLock;
+std::unordered_map<int32_t,uint32_t> BpBinder::sTrackingMap;
+int BpBinder::sNumTrackedUids = 0;
+std::atomic_bool BpBinder::sCountByUidEnabled(false);
+binder_proxy_limit_callback BpBinder::sLimitCallback;
+bool BpBinder::sBinderProxyThrottleCreate = false;
+
+// Arbitrarily high value that probably distinguishes a bad behaving app
+uint32_t BpBinder::sBinderProxyCountHighWatermark = 2500;
+// Another arbitrary value a binder count needs to drop below before another callback will be called
+uint32_t BpBinder::sBinderProxyCountLowWatermark = 2000;
+
+enum {
+    LIMIT_REACHED_MASK = 0x80000000,        // A flag denoting that the limit has been reached
+    COUNTING_VALUE_MASK = 0x7FFFFFFF,       // A mask of the remaining bits for the count value
+};
+
 BpBinder::ObjectManager::ObjectManager()
 {
 }
@@ -87,16 +105,47 @@
 
 // ---------------------------------------------------------------------------
 
-BpBinder::BpBinder(int32_t handle)
+
+BpBinder* BpBinder::create(int32_t handle) {
+    int32_t trackedUid = -1;
+    if (sCountByUidEnabled) {
+        trackedUid = IPCThreadState::self()->getCallingUid();
+        AutoMutex _l(sTrackingLock);
+        uint32_t trackedValue = sTrackingMap[trackedUid];
+        if (CC_UNLIKELY(trackedValue & LIMIT_REACHED_MASK)) {
+            if (sBinderProxyThrottleCreate) {
+                return nullptr;
+            }
+        } else {
+            if ((trackedValue & COUNTING_VALUE_MASK) >= sBinderProxyCountHighWatermark) {
+                ALOGE("Too many binder proxy objects sent to uid %d from uid %d (%d proxies held)",
+                      getuid(), trackedUid, trackedValue);
+                sTrackingMap[trackedUid] |= LIMIT_REACHED_MASK;
+                if (sLimitCallback) sLimitCallback(trackedUid);
+                if (sBinderProxyThrottleCreate) {
+                    ALOGI("Throttling binder proxy creates from uid %d in uid %d until binder proxy"
+                          " count drops below %d",
+                          trackedUid, getuid(), sBinderProxyCountLowWatermark);
+                    return nullptr;
+                }
+            }
+        }
+        sTrackingMap[trackedUid]++;
+    }
+    return new BpBinder(handle, trackedUid);
+}
+
+BpBinder::BpBinder(int32_t handle, int32_t trackedUid)
     : mHandle(handle)
     , mAlive(1)
     , mObitsSent(0)
     , mObituaries(nullptr)
+    , mTrackedUid(trackedUid)
 {
     ALOGV("Creating BpBinder %p handle %d\n", this, mHandle);
 
     extendObjectLifetime(OBJECT_LIFETIME_WEAK);
-    IPCThreadState::self()->incWeakHandle(handle);
+    IPCThreadState::self()->incWeakHandle(handle, this);
 }
 
 bool BpBinder::isDescriptorCached() const {
@@ -315,6 +364,26 @@
 
     IPCThreadState* ipc = IPCThreadState::self();
 
+    if (mTrackedUid >= 0) {
+        AutoMutex _l(sTrackingLock);
+        uint32_t trackedValue = sTrackingMap[mTrackedUid];
+        if (CC_UNLIKELY((trackedValue & COUNTING_VALUE_MASK) == 0)) {
+            ALOGE("Unexpected Binder Proxy tracking decrement in %p handle %d\n", this, mHandle);
+        } else {
+            if (CC_UNLIKELY(
+                (trackedValue & LIMIT_REACHED_MASK) &&
+                ((trackedValue & COUNTING_VALUE_MASK) <= sBinderProxyCountLowWatermark)
+                )) {
+                ALOGI("Limit reached bit reset for uid %d (fewer than %d proxies from uid %d held)",
+                                   getuid(), mTrackedUid, sBinderProxyCountLowWatermark);
+                sTrackingMap[mTrackedUid] &= ~LIMIT_REACHED_MASK;
+            }
+            if (--sTrackingMap[mTrackedUid] == 0) {
+                sTrackingMap.erase(mTrackedUid);
+            }
+        }
+    }
+
     mLock.lock();
     Vector<Obituary>* obits = mObituaries;
     if(obits != nullptr) {
@@ -340,7 +409,7 @@
 {
     ALOGV("onFirstRef BpBinder %p handle %d\n", this, mHandle);
     IPCThreadState* ipc = IPCThreadState::self();
-    if (ipc) ipc->incStrongHandle(mHandle);
+    if (ipc) ipc->incStrongHandle(mHandle, this);
 }
 
 void BpBinder::onLastStrongRef(const void* /*id*/)
@@ -360,6 +429,42 @@
     return ipc ? ipc->attemptIncStrongHandle(mHandle) == NO_ERROR : false;
 }
 
+uint32_t BpBinder::getBinderProxyCount(uint32_t uid)
+{
+    AutoMutex _l(sTrackingLock);
+    auto it = sTrackingMap.find(uid);
+    if (it != sTrackingMap.end()) {
+        return it->second & COUNTING_VALUE_MASK;
+    }
+    return 0;
+}
+
+void BpBinder::getCountByUid(Vector<uint32_t>& uids, Vector<uint32_t>& counts)
+{
+    AutoMutex _l(sTrackingLock);
+    uids.setCapacity(sTrackingMap.size());
+    counts.setCapacity(sTrackingMap.size());
+    for (const auto& it : sTrackingMap) {
+        uids.push_back(it.first);
+        counts.push_back(it.second & COUNTING_VALUE_MASK);
+    }
+}
+
+void BpBinder::enableCountByUid() { sCountByUidEnabled.store(true); }
+void BpBinder::disableCountByUid() { sCountByUidEnabled.store(false); }
+void BpBinder::setCountByUidEnabled(bool enable) { sCountByUidEnabled.store(enable); }
+
+void BpBinder::setLimitCallback(binder_proxy_limit_callback cb) {
+    AutoMutex _l(sTrackingLock);
+    sLimitCallback = cb;
+}
+
+void BpBinder::setBinderProxyCountWatermarks(int high, int low) {
+    AutoMutex _l(sTrackingLock);
+    sBinderProxyCountHighWatermark = high;
+    sBinderProxyCountLowWatermark = low;
+}
+
 // ---------------------------------------------------------------------------
 
 }; // namespace android
diff --git a/libs/binder/IActivityManager.cpp b/libs/binder/IActivityManager.cpp
index 50a8b28..428db4d 100644
--- a/libs/binder/IActivityManager.cpp
+++ b/libs/binder/IActivityManager.cpp
@@ -56,6 +56,40 @@
         }
         return fd;
     }
+
+    virtual void registerUidObserver(const sp<IUidObserver>& observer,
+                                     const int32_t event,
+                                     const int32_t cutpoint,
+                                     const String16& callingPackage)
+    {
+         Parcel data, reply;
+         data.writeInterfaceToken(IActivityManager::getInterfaceDescriptor());
+         data.writeStrongBinder(IInterface::asBinder(observer));
+         data.writeInt32(event);
+         data.writeInt32(cutpoint);
+         data.writeString16(callingPackage);
+         remote()->transact(REGISTER_UID_OBSERVER_TRANSACTION, data, &reply);
+    }
+
+    virtual void unregisterUidObserver(const sp<IUidObserver>& observer)
+    {
+         Parcel data, reply;
+         data.writeInterfaceToken(IActivityManager::getInterfaceDescriptor());
+         data.writeStrongBinder(IInterface::asBinder(observer));
+         remote()->transact(UNREGISTER_UID_OBSERVER_TRANSACTION, data, &reply);
+    }
+
+    virtual bool isUidActive(const uid_t uid, const String16& callingPackage)
+    {
+         Parcel data, reply;
+         data.writeInterfaceToken(IActivityManager::getInterfaceDescriptor());
+         data.writeInt32(uid);
+         data.writeString16(callingPackage);
+         remote()->transact(IS_UID_ACTIVE_TRANSACTION, data, &reply);
+         // fail on exception
+         if (reply.readExceptionCode() != 0) return false;
+         return reply.readInt32() == 1;
+    }
 };
 
 // ------------------------------------------------------------------------------------
diff --git a/libs/binder/IAppOpsService.cpp b/libs/binder/IAppOpsService.cpp
index c38568c..068664b 100644
--- a/libs/binder/IAppOpsService.cpp
+++ b/libs/binder/IAppOpsService.cpp
@@ -61,13 +61,14 @@
     }
 
     virtual int32_t startOperation(const sp<IBinder>& token, int32_t code, int32_t uid,
-                const String16& packageName) {
+                const String16& packageName, bool startIfModeDefault) {
         Parcel data, reply;
         data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor());
         data.writeStrongBinder(token);
         data.writeInt32(code);
         data.writeInt32(uid);
         data.writeString16(packageName);
+        data.writeInt32(startIfModeDefault ? 1 : 0);
         remote()->transact(START_OPERATION_TRANSACTION, data, &reply);
         // fail on exception
         if (reply.readExceptionCode() != 0) return MODE_ERRORED;
@@ -159,7 +160,8 @@
             int32_t code = data.readInt32();
             int32_t uid = data.readInt32();
             String16 packageName = data.readString16();
-            int32_t res = startOperation(token, code, uid, packageName);
+            bool startIfModeDefault = data.readInt32() == 1;
+            int32_t res = startOperation(token, code, uid, packageName, startIfModeDefault);
             reply->writeNoException();
             reply->writeInt32(res);
             return NO_ERROR;
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index 33ec65f..b2217b5 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -409,6 +409,15 @@
     if (mProcess->mDriverFD <= 0)
         return;
     talkWithDriver(false);
+    // The flush could have caused post-write refcount decrements to have
+    // been executed, which in turn could result in BC_RELEASE/BC_DECREFS
+    // being queued in mOut. So flush again, if we need to.
+    if (mOut.dataSize() > 0) {
+        talkWithDriver(false);
+    }
+    if (mOut.dataSize() > 0) {
+        ALOGW("mOut.dataSize() > 0 after flushCommands()");
+    }
 }
 
 void IPCThreadState::blockUntilThreadAvailable()
@@ -501,6 +510,21 @@
     }
 }
 
+void IPCThreadState::processPostWriteDerefs()
+{
+    for (size_t i = 0; i < mPostWriteWeakDerefs.size(); i++) {
+        RefBase::weakref_type* refs = mPostWriteWeakDerefs[i];
+        refs->decWeak(mProcess.get());
+    }
+    mPostWriteWeakDerefs.clear();
+
+    for (size_t i = 0; i < mPostWriteStrongDerefs.size(); i++) {
+        RefBase* obj = mPostWriteStrongDerefs[i];
+        obj->decStrong(mProcess.get());
+    }
+    mPostWriteStrongDerefs.clear();
+}
+
 void IPCThreadState::joinThreadPool(bool isMain)
 {
     LOG_THREADPOOL("**** THREAD %p (PID %d) IS JOINING THE THREAD POOL\n", (void*)pthread_self(), getpid());
@@ -627,11 +651,14 @@
     return err;
 }
 
-void IPCThreadState::incStrongHandle(int32_t handle)
+void IPCThreadState::incStrongHandle(int32_t handle, BpBinder *proxy)
 {
     LOG_REMOTEREFS("IPCThreadState::incStrongHandle(%d)\n", handle);
     mOut.writeInt32(BC_ACQUIRE);
     mOut.writeInt32(handle);
+    // Create a temp reference until the driver has handled this command.
+    proxy->incStrong(mProcess.get());
+    mPostWriteStrongDerefs.push(proxy);
 }
 
 void IPCThreadState::decStrongHandle(int32_t handle)
@@ -641,11 +668,14 @@
     mOut.writeInt32(handle);
 }
 
-void IPCThreadState::incWeakHandle(int32_t handle)
+void IPCThreadState::incWeakHandle(int32_t handle, BpBinder *proxy)
 {
     LOG_REMOTEREFS("IPCThreadState::incWeakHandle(%d)\n", handle);
     mOut.writeInt32(BC_INCREFS);
     mOut.writeInt32(handle);
+    // Create a temp reference until the driver has handled this command.
+    proxy->getWeakRefs()->incWeak(mProcess.get());
+    mPostWriteWeakDerefs.push(proxy->getWeakRefs());
 }
 
 void IPCThreadState::decWeakHandle(int32_t handle)
@@ -897,8 +927,10 @@
         if (bwr.write_consumed > 0) {
             if (bwr.write_consumed < mOut.dataSize())
                 mOut.remove(0, bwr.write_consumed);
-            else
+            else {
                 mOut.setDataSize(0);
+                processPostWriteDerefs();
+            }
         }
         if (bwr.read_consumed > 0) {
             mIn.setDataSize(bwr.read_consumed);
diff --git a/libs/binder/IPermissionController.cpp b/libs/binder/IPermissionController.cpp
index 674bddf..89ebc6c 100644
--- a/libs/binder/IPermissionController.cpp
+++ b/libs/binder/IPermissionController.cpp
@@ -49,6 +49,19 @@
         return reply.readInt32() != 0;
     }
 
+    virtual int32_t noteOp(const String16& op, int32_t uid, const String16& packageName)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IPermissionController::getInterfaceDescriptor());
+        data.writeString16(op);
+        data.writeInt32(uid);
+        data.writeString16(packageName);
+        remote()->transact(NOTE_OP_TRANSACTION, data, &reply);
+        // fail on exception
+        if (reply.readExceptionCode() != 0) return 2; // MODE_ERRORED
+        return reply.readInt32();
+    }
+
     virtual void getPackagesForUid(const uid_t uid, Vector<String16>& packages)
     {
         Parcel data, reply;
@@ -78,6 +91,18 @@
         if (reply.readExceptionCode() != 0) return false;
         return reply.readInt32() != 0;
     }
+
+    virtual int getPackageUid(const String16& package, int flags)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IPermissionController::getInterfaceDescriptor());
+        data.writeString16(package);
+        data.writeInt32(flags);
+        remote()->transact(GET_PACKAGE_UID_TRANSACTION, data, &reply);
+        // fail on exception
+        if (reply.readExceptionCode() != 0) return false;
+        return reply.readInt32();
+    }
 };
 
 IMPLEMENT_META_INTERFACE(PermissionController, "android.os.IPermissionController");
@@ -99,6 +124,17 @@
             return NO_ERROR;
         } break;
 
+        case NOTE_OP_TRANSACTION: {
+            CHECK_INTERFACE(IPermissionController, data, reply);
+            String16 op = data.readString16();
+            int32_t uid = data.readInt32();
+            String16 packageName = data.readString16();
+            int32_t res = noteOp(op, uid, packageName);
+            reply->writeNoException();
+            reply->writeInt32(res);
+            return NO_ERROR;
+        } break;
+
         case GET_PACKAGES_FOR_UID_TRANSACTION: {
             CHECK_INTERFACE(IPermissionController, data, reply);
             int32_t uid = data.readInt32();
@@ -122,6 +158,16 @@
             return NO_ERROR;
         } break;
 
+        case GET_PACKAGE_UID_TRANSACTION: {
+            CHECK_INTERFACE(IPermissionController, data, reply);
+            String16 package = data.readString16();
+            int flags = data.readInt32();
+            const int uid = getPackageUid(package, flags);
+            reply->writeNoException();
+            reply->writeInt32(uid);
+            return NO_ERROR;
+        } break;
+
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index 001dc9e..17e098c 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -20,7 +20,11 @@
 
 #include <utils/Log.h>
 #include <binder/IPCThreadState.h>
+#ifndef __ANDROID_VNDK__
+#include <binder/IPermissionController.h>
+#endif
 #include <binder/Parcel.h>
+#include <cutils/properties.h>
 #include <utils/String8.h>
 #include <utils/SystemClock.h>
 #include <utils/CallStack.h>
@@ -48,6 +52,9 @@
     return gDefaultServiceManager;
 }
 
+#ifndef __ANDROID_VNDK__
+// IPermissionController is not accessible to vendors
+
 bool checkCallingPermission(const String16& permission)
 {
     return checkCallingPermission(permission, nullptr, nullptr);
@@ -122,6 +129,8 @@
     }
 }
 
+#endif //__ANDROID_VNDK__
+
 // ----------------------------------------------------------------------
 
 class BpServiceManager : public BpInterface<IServiceManager>
@@ -134,20 +143,35 @@
 
     virtual sp<IBinder> getService(const String16& name) const
     {
-        unsigned n;
-        for (n = 0; n < 5; n++){
-            if (n > 0) {
-                if (!strcmp(ProcessState::self()->getDriverName().c_str(), "/dev/vndbinder")) {
-                    ALOGI("Waiting for vendor service %s...", String8(name).string());
-                    CallStack stack(LOG_TAG);
-                } else {
-                    ALOGI("Waiting for service %s...", String8(name).string());
-                }
-                sleep(1);
+        sp<IBinder> svc = checkService(name);
+        if (svc != nullptr) return svc;
+
+        const bool isVendorService =
+            strcmp(ProcessState::self()->getDriverName().c_str(), "/dev/vndbinder") == 0;
+        const long timeout = uptimeMillis() + 5000;
+        if (!gSystemBootCompleted) {
+            char bootCompleted[PROPERTY_VALUE_MAX];
+            property_get("sys.boot_completed", bootCompleted, "0");
+            gSystemBootCompleted = strcmp(bootCompleted, "1") == 0 ? true : false;
+        }
+        // retry interval in millisecond.
+        const long sleepTime = gSystemBootCompleted ? 1000 : 100;
+
+        int n = 0;
+        while (uptimeMillis() < timeout) {
+            n++;
+            if (isVendorService) {
+                ALOGI("Waiting for vendor service %s...", String8(name).string());
+                CallStack stack(LOG_TAG);
+            } else if (n%10 == 0) {
+                ALOGI("Waiting for service %s...", String8(name).string());
             }
+            usleep(1000*sleepTime);
+
             sp<IBinder> svc = checkService(name);
             if (svc != nullptr) return svc;
         }
+        ALOGW("Service %s didn't start. Returning NULL", String8(name).string());
         return nullptr;
     }
 
@@ -161,19 +185,18 @@
     }
 
     virtual status_t addService(const String16& name, const sp<IBinder>& service,
-            bool allowIsolated)
-    {
+                                bool allowIsolated, int dumpsysPriority) {
         Parcel data, reply;
         data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
         data.writeString16(name);
         data.writeStrongBinder(service);
         data.writeInt32(allowIsolated ? 1 : 0);
+        data.writeInt32(dumpsysPriority);
         status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
         return err == NO_ERROR ? reply.readExceptionCode() : err;
     }
 
-    virtual Vector<String16> listServices()
-    {
+    virtual Vector<String16> listServices(int dumpsysPriority) {
         Vector<String16> res;
         int n = 0;
 
@@ -181,6 +204,7 @@
             Parcel data, reply;
             data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
             data.writeInt32(n++);
+            data.writeInt32(dumpsysPriority);
             status_t err = remote()->transact(LIST_SERVICES_TRANSACTION, data, &reply);
             if (err != NO_ERROR)
                 break;
diff --git a/libs/binder/IShellCallback.cpp b/libs/binder/IShellCallback.cpp
index 4568a42..dd4a65e 100644
--- a/libs/binder/IShellCallback.cpp
+++ b/libs/binder/IShellCallback.cpp
@@ -39,11 +39,13 @@
     {
     }
 
-    virtual int openOutputFile(const String16& path, const String16& seLinuxContext) {
+    virtual int openFile(const String16& path, const String16& seLinuxContext,
+            const String16& mode) {
         Parcel data, reply;
         data.writeInterfaceToken(IShellCallback::getInterfaceDescriptor());
         data.writeString16(path);
         data.writeString16(seLinuxContext);
+        data.writeString16(mode);
         remote()->transact(OP_OPEN_OUTPUT_FILE, data, &reply, 0);
         reply.readExceptionCode();
         int fd = reply.readParcelFileDescriptor();
@@ -64,7 +66,8 @@
             CHECK_INTERFACE(IShellCallback, data, reply);
             String16 path(data.readString16());
             String16 seLinuxContext(data.readString16());
-            int fd = openOutputFile(path, seLinuxContext);
+            String16 mode(data.readString16());
+            int fd = openFile(path, seLinuxContext, mode);
             if (reply != nullptr) {
                 reply->writeNoException();
                 if (fd >= 0) {
diff --git a/libs/binder/IUidObserver.cpp b/libs/binder/IUidObserver.cpp
new file mode 100644
index 0000000..697e948
--- /dev/null
+++ b/libs/binder/IUidObserver.cpp
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <binder/IUidObserver.h>
+
+#include <binder/Parcel.h>
+
+namespace android {
+
+// ------------------------------------------------------------------------------------
+
+class BpUidObserver : public BpInterface<IUidObserver>
+{
+public:
+    explicit BpUidObserver(const sp<IBinder>& impl)
+        : BpInterface<IUidObserver>(impl)
+    {
+    }
+
+    virtual void onUidGone(uid_t uid, bool disabled)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IUidObserver::getInterfaceDescriptor());
+        data.writeInt32((int32_t) uid);
+        data.writeInt32(disabled ? 1 : 0);
+        remote()->transact(ON_UID_GONE_TRANSACTION, data, &reply, IBinder::FLAG_ONEWAY);
+    }
+
+    virtual void onUidActive(uid_t uid)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IUidObserver::getInterfaceDescriptor());
+        data.writeInt32((int32_t) uid);
+        remote()->transact(ON_UID_ACTIVE_TRANSACTION, data, &reply, IBinder::FLAG_ONEWAY);
+    }
+
+    virtual void onUidIdle(uid_t uid, bool disabled)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IUidObserver::getInterfaceDescriptor());
+        data.writeInt32((int32_t) uid);
+        data.writeInt32(disabled ? 1 : 0);
+        remote()->transact(ON_UID_IDLE_TRANSACTION, data, &reply, IBinder::FLAG_ONEWAY);
+    }
+};
+
+// ----------------------------------------------------------------------
+
+IMPLEMENT_META_INTERFACE(UidObserver, "android.app.IUidObserver");
+
+// ----------------------------------------------------------------------
+
+status_t BnUidObserver::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    switch(code) {
+        case ON_UID_GONE_TRANSACTION: {
+            CHECK_INTERFACE(IUidObserver, data, reply);
+            uid_t uid = data.readInt32();
+            bool disabled = data.readInt32() == 1;
+            onUidGone(uid, disabled);
+            return NO_ERROR;
+        } break;
+
+        case ON_UID_ACTIVE_TRANSACTION: {
+            CHECK_INTERFACE(IUidObserver, data, reply);
+            uid_t uid = data.readInt32();
+            onUidActive(uid);
+            return NO_ERROR;
+        } break;
+
+        case ON_UID_IDLE_TRANSACTION: {
+            CHECK_INTERFACE(IUidObserver, data, reply);
+            uid_t uid = data.readInt32();
+            bool disabled = data.readInt32() == 1;
+            onUidIdle(uid, disabled);
+            return NO_ERROR;
+        } break;
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+}; // namespace android
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 03aef17..eb8188b 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -433,6 +433,7 @@
 
     mDataPos = pos;
     mNextObjectHint = 0;
+    mObjectsSorted = false;
 }
 
 status_t Parcel::setDataCapacity(size_t size)
@@ -1276,7 +1277,7 @@
     if (err) return err;
 
     // payload
-    void* const buf = this->writeInplace(pad_size(len));
+    void* const buf = this->writeInplace(len);
     if (buf == nullptr)
         return BAD_VALUE;
 
@@ -1469,6 +1470,59 @@
     LOG_ALWAYS_FATAL("Parcel::remove() not yet implemented!");
 }
 
+status_t Parcel::validateReadData(size_t upperBound) const
+{
+    // Don't allow non-object reads on object data
+    if (mObjectsSorted || mObjectsSize <= 1) {
+data_sorted:
+        // Expect to check only against the next object
+        if (mNextObjectHint < mObjectsSize && upperBound > mObjects[mNextObjectHint]) {
+            // For some reason the current read position is greater than the next object
+            // hint. Iterate until we find the right object
+            size_t nextObject = mNextObjectHint;
+            do {
+                if (mDataPos < mObjects[nextObject] + sizeof(flat_binder_object)) {
+                    // Requested info overlaps with an object
+                    ALOGE("Attempt to read from protected data in Parcel %p", this);
+                    return PERMISSION_DENIED;
+                }
+                nextObject++;
+            } while (nextObject < mObjectsSize && upperBound > mObjects[nextObject]);
+            mNextObjectHint = nextObject;
+        }
+        return NO_ERROR;
+    }
+    // Quickly determine if mObjects is sorted.
+    binder_size_t* currObj = mObjects + mObjectsSize - 1;
+    binder_size_t* prevObj = currObj;
+    while (currObj > mObjects) {
+        prevObj--;
+        if(*prevObj > *currObj) {
+            goto data_unsorted;
+        }
+        currObj--;
+    }
+    mObjectsSorted = true;
+    goto data_sorted;
+
+data_unsorted:
+    // Insertion Sort mObjects
+    // Great for mostly sorted lists. If randomly sorted or reverse ordered mObjects become common,
+    // switch to std::sort(mObjects, mObjects + mObjectsSize);
+    for (binder_size_t* iter0 = mObjects + 1; iter0 < mObjects + mObjectsSize; iter0++) {
+        binder_size_t temp = *iter0;
+        binder_size_t* iter1 = iter0 - 1;
+        while (iter1 >= mObjects && *iter1 > temp) {
+            *(iter1 + 1) = *iter1;
+            iter1--;
+        }
+        *(iter1 + 1) = temp;
+    }
+    mNextObjectHint = 0;
+    mObjectsSorted = true;
+    goto data_sorted;
+}
+
 status_t Parcel::read(void* outData, size_t len) const
 {
     if (len > INT32_MAX) {
@@ -1479,6 +1533,15 @@
 
     if ((mDataPos+pad_size(len)) >= mDataPos && (mDataPos+pad_size(len)) <= mDataSize
             && len <= pad_size(len)) {
+        if (mObjectsSize > 0) {
+            status_t err = validateReadData(mDataPos + pad_size(len));
+            if(err != NO_ERROR) {
+                // Still increment the data position by the expected length
+                mDataPos += pad_size(len);
+                ALOGV("read Setting data pos of %p to %zu", this, mDataPos);
+                return err;
+            }
+        }
         memcpy(outData, mData+mDataPos, len);
         mDataPos += pad_size(len);
         ALOGV("read Setting data pos of %p to %zu", this, mDataPos);
@@ -1497,6 +1560,16 @@
 
     if ((mDataPos+pad_size(len)) >= mDataPos && (mDataPos+pad_size(len)) <= mDataSize
             && len <= pad_size(len)) {
+        if (mObjectsSize > 0) {
+            status_t err = validateReadData(mDataPos + pad_size(len));
+            if(err != NO_ERROR) {
+                // Still increment the data position by the expected length
+                mDataPos += pad_size(len);
+                ALOGV("readInplace Setting data pos of %p to %zu", this, mDataPos);
+                return nullptr;
+            }
+        }
+
         const void* data = mData+mDataPos;
         mDataPos += pad_size(len);
         ALOGV("readInplace Setting data pos of %p to %zu", this, mDataPos);
@@ -1510,6 +1583,15 @@
     COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE_UNSAFE(sizeof(T)) == sizeof(T));
 
     if ((mDataPos+sizeof(T)) <= mDataSize) {
+        if (mObjectsSize > 0) {
+            status_t err = validateReadData(mDataPos + sizeof(T));
+            if(err != NO_ERROR) {
+                // Still increment the data position by the expected length
+                mDataPos += sizeof(T);
+                return err;
+            }
+        }
+
         const void* data = mData+mDataPos;
         mDataPos += sizeof(T);
         *pArg =  *reinterpret_cast<const T*>(data);
@@ -2366,6 +2448,7 @@
     mObjects = const_cast<binder_size_t*>(objects);
     mObjectsSize = mObjectsCapacity = objectsCount;
     mNextObjectHint = 0;
+    mObjectsSorted = false;
     mOwner = relFunc;
     mOwnerCookie = relCookie;
     for (size_t i = 0; i < mObjectsSize; i++) {
@@ -2524,6 +2607,7 @@
     mObjects = nullptr;
     mObjectsSize = mObjectsCapacity = 0;
     mNextObjectHint = 0;
+    mObjectsSorted = false;
     mHasFds = false;
     mFdsKnown = true;
     mAllowFds = true;
@@ -2610,6 +2694,7 @@
         mDataCapacity = desired;
         mObjectsSize = mObjectsCapacity = objectsSize;
         mNextObjectHint = 0;
+        mObjectsSorted = false;
 
     } else if (mData) {
         if (objectsSize < mObjectsSize) {
@@ -2631,6 +2716,7 @@
             }
             mObjectsSize = objectsSize;
             mNextObjectHint = 0;
+            mObjectsSorted = false;
         }
 
         // We own the data, so we can just do a realloc().
@@ -2703,6 +2789,7 @@
     mObjectsSize = 0;
     mObjectsCapacity = 0;
     mNextObjectHint = 0;
+    mObjectsSorted = false;
     mHasFds = false;
     mFdsKnown = true;
     mAllowFds = true;
diff --git a/libs/binder/PermissionController.cpp b/libs/binder/PermissionController.cpp
new file mode 100644
index 0000000..96df33c
--- /dev/null
+++ b/libs/binder/PermissionController.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <mutex>
+#include <binder/PermissionController.h>
+#include <binder/Binder.h>
+#include <binder/IServiceManager.h>
+
+#include <utils/SystemClock.h>
+
+namespace android {
+
+PermissionController::PermissionController()
+{
+}
+
+sp<IPermissionController> PermissionController::getService()
+{
+    std::lock_guard<Mutex> scoped_lock(mLock);
+    int64_t startTime = 0;
+    sp<IPermissionController> service = mService;
+    while (service == nullptr || !IInterface::asBinder(service)->isBinderAlive()) {
+        sp<IBinder> binder = defaultServiceManager()->checkService(String16("permission"));
+        if (binder == nullptr) {
+            // Wait for the activity service to come back...
+            if (startTime == 0) {
+                startTime = uptimeMillis();
+                ALOGI("Waiting for permission service");
+            } else if ((uptimeMillis() - startTime) > 10000) {
+                ALOGW("Waiting too long for permission service, giving up");
+                service = NULL;
+                break;
+            }
+            sleep(1);
+        } else {
+            service = interface_cast<IPermissionController>(binder);
+            mService = service;
+        }
+    }
+    return service;
+}
+
+bool PermissionController::checkPermission(const String16& permission, int32_t pid, int32_t uid)
+{
+    sp<IPermissionController> service = getService();
+    return service != NULL ? service->checkPermission(permission, pid, uid) : false;
+}
+
+int32_t PermissionController::noteOp(const String16& op, int32_t uid, const String16& packageName)
+{
+    sp<IPermissionController> service = getService();
+    return service != NULL ? service->noteOp(op, uid, packageName) : MODE_ERRORED;
+}
+
+void PermissionController::getPackagesForUid(const uid_t uid, Vector<String16> &packages)
+{
+    sp<IPermissionController> service = getService();
+    if (service != nullptr) {
+        service->getPackagesForUid(uid, packages);
+    }
+}
+
+bool PermissionController::isRuntimePermission(const String16& permission)
+{
+    sp<IPermissionController> service = getService();
+    return service != nullptr ? service->isRuntimePermission(permission) : false;
+}
+
+int PermissionController::getPackageUid(const String16& package, int flags)
+{
+    sp<IPermissionController> service = getService();
+    return service != nullptr ? service->getPackageUid(package, flags) : -1;
+}
+
+}; // namespace android
diff --git a/libs/binder/PersistableBundle.cpp b/libs/binder/PersistableBundle.cpp
index d617b5a..c0aec0a 100644
--- a/libs/binder/PersistableBundle.cpp
+++ b/libs/binder/PersistableBundle.cpp
@@ -39,8 +39,9 @@
 using namespace ::android::binder;
 
 enum {
-    // Keep in sync with BUNDLE_MAGIC in frameworks/base/core/java/android/os/BaseBundle.java.
+    // Keep them in sync with BUNDLE_MAGIC* in frameworks/base/core/java/android/os/BaseBundle.java.
     BUNDLE_MAGIC = 0x4C444E42,
+    BUNDLE_MAGIC_NATIVE = 0x4C444E44,
 };
 
 namespace {
@@ -99,7 +100,7 @@
 
     size_t length_pos = parcel->dataPosition();
     RETURN_IF_FAILED(parcel->writeInt32(1));  // dummy, will hold length
-    RETURN_IF_FAILED(parcel->writeInt32(BUNDLE_MAGIC));
+    RETURN_IF_FAILED(parcel->writeInt32(BUNDLE_MAGIC_NATIVE));
 
     size_t start_pos = parcel->dataPosition();
     RETURN_IF_FAILED(writeToParcelInner(parcel));
@@ -392,7 +393,7 @@
 
     int32_t magic;
     RETURN_IF_FAILED(parcel->readInt32(&magic));
-    if (magic != BUNDLE_MAGIC) {
+    if (magic != BUNDLE_MAGIC && magic != BUNDLE_MAGIC_NATIVE) {
         ALOGE("Bad magic number for PersistableBundle: 0x%08x", magic);
         return BAD_VALUE;
     }
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index 6e7c427..3e871f8 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -282,7 +282,7 @@
                    return nullptr;
             }
 
-            b = new BpBinder(handle); 
+            b = BpBinder::create(handle);
             e->binder = b;
             if (b) e->refs = b->getWeakRefs();
             result = b;
@@ -316,7 +316,7 @@
         // arriving from the driver.
         IBinder* b = e->binder;
         if (b == nullptr || !e->refs->attemptIncWeak(this)) {
-            b = new BpBinder(handle);
+            b = BpBinder::create(handle);
             result = b;
             e->binder = b;
             if (b) e->refs = b->getWeakRefs();
diff --git a/libs/binder/Static.cpp b/libs/binder/Static.cpp
index c3ba5a2..bd0e6f9 100644
--- a/libs/binder/Static.cpp
+++ b/libs/binder/Static.cpp
@@ -72,13 +72,16 @@
 
 // ------------ ProcessState.cpp
 
-Mutex gProcessMutex;
+Mutex& gProcessMutex = *new Mutex;
 sp<ProcessState> gProcess;
 
 // ------------ IServiceManager.cpp
 
 Mutex gDefaultServiceManagerLock;
 sp<IServiceManager> gDefaultServiceManager;
+#ifndef __ANDROID_VNDK__
 sp<IPermissionController> gPermissionController;
+#endif
+bool gSystemBootCompleted = false;
 
 }   // namespace android
diff --git a/libs/binder/Status.cpp b/libs/binder/Status.cpp
index 006f7f9..a9d5055 100644
--- a/libs/binder/Status.cpp
+++ b/libs/binder/Status.cpp
@@ -102,6 +102,15 @@
     }
     mMessage = String8(message);
 
+    // Skip over the remote stack trace data
+    int32_t remote_stack_trace_header_size;
+    status = parcel.readInt32(&remote_stack_trace_header_size);
+    if (status != OK) {
+        setFromStatusT(status);
+        return status;
+    }
+    parcel.setDataPosition(parcel.dataPosition() + remote_stack_trace_header_size);
+
     if (mException == EX_SERVICE_SPECIFIC) {
         status = parcel.readInt32(&mErrorCode);
     } else if (mException == EX_PARCELABLE) {
@@ -137,6 +146,7 @@
         return status;
     }
     status = parcel->writeString16(String16(mMessage));
+    status = parcel->writeInt32(0); // Empty remote stack trace header
     if (mException == EX_SERVICE_SPECIFIC) {
         status = parcel->writeInt32(mErrorCode);
     } else if (mException == EX_PARCELABLE) {
diff --git a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
index 3264666..5b66b92 100644
--- a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
+++ b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
@@ -52,6 +52,6 @@
      * Unknown or unknowable versions are returned as 0.
      */
 
-    int getVersionCodeForPackage(in String packageName);
+    long getVersionCodeForPackage(in String packageName);
 
 }
diff --git a/libs/binder/include/binder/ActivityManager.h b/libs/binder/include/binder/ActivityManager.h
new file mode 100644
index 0000000..b8db091
--- /dev/null
+++ b/libs/binder/include/binder/ActivityManager.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_ACTIVITY_MANAGER_H
+#define ANDROID_ACTIVITY_MANAGER_H
+
+#ifndef __ANDROID_VNDK__
+
+#include <binder/IActivityManager.h>
+
+#include <utils/threads.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+
+class ActivityManager
+{
+public:
+
+    enum {
+        // Flag for registerUidObserver: report uid gone
+        UID_OBSERVER_GONE = 1<<1,
+        // Flag for registerUidObserver: report uid has become idle
+        UID_OBSERVER_IDLE = 1<<2,
+        // Flag for registerUidObserver: report uid has become active
+        UID_OBSERVER_ACTIVE = 1<<3
+    };
+
+    enum {
+        // Not a real process state
+        PROCESS_STATE_UNKNOWN = -1
+    };
+
+    ActivityManager();
+
+    int openContentUri(const String16& stringUri);
+    void registerUidObserver(const sp<IUidObserver>& observer,
+                             const int32_t event,
+                             const int32_t cutpoint,
+                             const String16& callingPackage);
+    void unregisterUidObserver(const sp<IUidObserver>& observer);
+    bool isUidActive(const uid_t uid, const String16& callingPackage);
+
+    status_t linkToDeath(const sp<IBinder::DeathRecipient>& recipient);
+    status_t unlinkToDeath(const sp<IBinder::DeathRecipient>& recipient);
+
+private:
+    Mutex mLock;
+    sp<IActivityManager> mService;
+    sp<IActivityManager> getService();
+};
+
+
+}; // namespace android
+// ---------------------------------------------------------------------------
+#else // __ANDROID_VNDK__
+#error "This header is not visible to vendors"
+#endif // __ANDROID_VNDK__
+
+#endif // ANDROID_ACTIVITY_MANAGER_H
diff --git a/libs/binder/include/binder/AppOpsManager.h b/libs/binder/include/binder/AppOpsManager.h
index 4212776..c5b57c7 100644
--- a/libs/binder/include/binder/AppOpsManager.h
+++ b/libs/binder/include/binder/AppOpsManager.h
@@ -17,6 +17,8 @@
 #ifndef ANDROID_APP_OPS_MANAGER_H
 #define ANDROID_APP_OPS_MANAGER_H
 
+#ifndef __ANDROID_VNDK__
+
 #include <binder/IAppOpsService.h>
 
 #include <utils/threads.h>
@@ -99,7 +101,8 @@
 
     int32_t checkOp(int32_t op, int32_t uid, const String16& callingPackage);
     int32_t noteOp(int32_t op, int32_t uid, const String16& callingPackage);
-    int32_t startOp(int32_t op, int32_t uid, const String16& callingPackage);
+    int32_t startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage,
+            bool startIfModeDefault);
     void finishOp(int32_t op, int32_t uid, const String16& callingPackage);
     void startWatchingMode(int32_t op, const String16& packageName,
             const sp<IAppOpsCallback>& callback);
@@ -116,4 +119,8 @@
 
 }; // namespace android
 // ---------------------------------------------------------------------------
+#else // __ANDROID_VNDK__
+#error "This header is not visible to vendors"
+#endif // __ANDROID_VNDK__
+
 #endif // ANDROID_APP_OPS_MANAGER_H
diff --git a/libs/binder/include/binder/BinderService.h b/libs/binder/include/binder/BinderService.h
index ef703bd..9230e89 100644
--- a/libs/binder/include/binder/BinderService.h
+++ b/libs/binder/include/binder/BinderService.h
@@ -34,15 +34,17 @@
 class BinderService
 {
 public:
-    static status_t publish(bool allowIsolated = false) {
+    static status_t publish(bool allowIsolated = false,
+                            int dumpFlags = IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT) {
         sp<IServiceManager> sm(defaultServiceManager());
-        return sm->addService(
-                String16(SERVICE::getServiceName()),
-                new SERVICE(), allowIsolated);
+        return sm->addService(String16(SERVICE::getServiceName()), new SERVICE(), allowIsolated,
+                              dumpFlags);
     }
 
-    static void publishAndJoinThreadPool(bool allowIsolated = false) {
-        publish(allowIsolated);
+    static void publishAndJoinThreadPool(
+            bool allowIsolated = false,
+            int dumpFlags = IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT) {
+        publish(allowIsolated, dumpFlags);
         joinThreadPool();
     }
 
diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h
index 7ef93aa..8bd297b 100644
--- a/libs/binder/include/binder/BpBinder.h
+++ b/libs/binder/include/binder/BpBinder.h
@@ -19,15 +19,20 @@
 
 #include <binder/IBinder.h>
 #include <utils/KeyedVector.h>
+#include <utils/Mutex.h>
 #include <utils/threads.h>
 
+#include <unordered_map>
+
 // ---------------------------------------------------------------------------
 namespace android {
 
+using binder_proxy_limit_callback = void(*)(int);
+
 class BpBinder : public IBinder
 {
 public:
-                        BpBinder(int32_t handle);
+    static BpBinder*    create(int32_t handle);
 
     inline  int32_t     handle() const { return mHandle; }
 
@@ -61,6 +66,14 @@
             status_t    setConstantData(const void* data, size_t size);
             void        sendObituary();
 
+    static uint32_t     getBinderProxyCount(uint32_t uid);
+    static void         getCountByUid(Vector<uint32_t>& uids, Vector<uint32_t>& counts);
+    static void         enableCountByUid();
+    static void         disableCountByUid();
+    static void         setCountByUidEnabled(bool enable);
+    static void         setLimitCallback(binder_proxy_limit_callback cb);
+    static void         setBinderProxyCountWatermarks(int high, int low);
+
     class ObjectManager
     {
     public:
@@ -91,6 +104,7 @@
     };
 
 protected:
+                        BpBinder(int32_t handle,int32_t trackedUid);
     virtual             ~BpBinder();
     virtual void        onFirstRef();
     virtual void        onLastStrongRef(const void* id);
@@ -115,6 +129,16 @@
             ObjectManager       mObjects;
             Parcel*             mConstantData;
     mutable String16            mDescriptorCache;
+            int32_t             mTrackedUid;
+
+    static Mutex                                sTrackingLock;
+    static std::unordered_map<int32_t,uint32_t> sTrackingMap;
+    static int                                  sNumTrackedUids;
+    static std::atomic_bool                     sCountByUidEnabled;
+    static binder_proxy_limit_callback          sLimitCallback;
+    static uint32_t                             sBinderProxyCountHighWatermark;
+    static uint32_t                             sBinderProxyCountLowWatermark;
+    static bool                                 sBinderProxyThrottleCreate;
 };
 
 }; // namespace android
diff --git a/libs/binder/include/binder/IActivityManager.h b/libs/binder/include/binder/IActivityManager.h
index 5ad2180..f34969b 100644
--- a/libs/binder/include/binder/IActivityManager.h
+++ b/libs/binder/include/binder/IActivityManager.h
@@ -17,7 +17,10 @@
 #ifndef ANDROID_IACTIVITY_MANAGER_H
 #define ANDROID_IACTIVITY_MANAGER_H
 
+#ifndef __ANDROID_VNDK__
+
 #include <binder/IInterface.h>
+#include <binder/IUidObserver.h>
 
 namespace android {
 
@@ -28,10 +31,19 @@
 public:
     DECLARE_META_INTERFACE(ActivityManager)
 
-    virtual int openContentUri(const String16& /* stringUri */) = 0;
+    virtual int openContentUri(const String16& stringUri) = 0;
+    virtual void registerUidObserver(const sp<IUidObserver>& observer,
+                                     const int32_t event,
+                                     const int32_t cutpoint,
+                                     const String16& callingPackage) = 0;
+    virtual void unregisterUidObserver(const sp<IUidObserver>& observer) = 0;
+    virtual bool isUidActive(const uid_t uid, const String16& callingPackage) = 0;
 
     enum {
-        OPEN_CONTENT_URI_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION
+        OPEN_CONTENT_URI_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
+        REGISTER_UID_OBSERVER_TRANSACTION,
+        UNREGISTER_UID_OBSERVER_TRANSACTION,
+        IS_UID_ACTIVE_TRANSACTION
     };
 };
 
@@ -39,4 +51,8 @@
 
 }; // namespace android
 
-#endif // ANDROID_IACTIVITY_MANAGER_H
\ No newline at end of file
+#else // __ANDROID_VNDK__
+#error "This header is not visible to vendors"
+#endif // __ANDROID_VNDK__
+
+#endif // ANDROID_IACTIVITY_MANAGER_H
diff --git a/libs/binder/include/binder/IAppOpsCallback.h b/libs/binder/include/binder/IAppOpsCallback.h
index b62e9e2..e5b12a9 100644
--- a/libs/binder/include/binder/IAppOpsCallback.h
+++ b/libs/binder/include/binder/IAppOpsCallback.h
@@ -18,6 +18,8 @@
 #ifndef ANDROID_IAPP_OPS_CALLBACK_H
 #define ANDROID_IAPP_OPS_CALLBACK_H
 
+#ifndef __ANDROID_VNDK__
+
 #include <binder/IInterface.h>
 
 namespace android {
@@ -51,5 +53,9 @@
 
 }; // namespace android
 
+#else // __ANDROID_VNDK__
+#error "This header is not visible to vendors"
+#endif // __ANDROID_VNDK__
+
 #endif // ANDROID_IAPP_OPS_CALLBACK_H
 
diff --git a/libs/binder/include/binder/IAppOpsService.h b/libs/binder/include/binder/IAppOpsService.h
index dc18045..f0c5e17 100644
--- a/libs/binder/include/binder/IAppOpsService.h
+++ b/libs/binder/include/binder/IAppOpsService.h
@@ -18,6 +18,8 @@
 #ifndef ANDROID_IAPP_OPS_SERVICE_H
 #define ANDROID_IAPP_OPS_SERVICE_H
 
+#ifndef __ANDROID_VNDK__
+
 #include <binder/IAppOpsCallback.h>
 #include <binder/IInterface.h>
 
@@ -33,7 +35,7 @@
     virtual int32_t checkOperation(int32_t code, int32_t uid, const String16& packageName) = 0;
     virtual int32_t noteOperation(int32_t code, int32_t uid, const String16& packageName) = 0;
     virtual int32_t startOperation(const sp<IBinder>& token, int32_t code, int32_t uid,
-            const String16& packageName) = 0;
+            const String16& packageName, bool startIfModeDefault) = 0;
     virtual void finishOperation(const sp<IBinder>& token, int32_t code, int32_t uid,
             const String16& packageName) = 0;
     virtual void startWatchingMode(int32_t op, const String16& packageName,
@@ -75,4 +77,8 @@
 
 }; // namespace android
 
+#else // __ANDROID_VNDK__
+#error "This header is not visible to vendors"
+#endif // __ANDROID_VNDK__
+
 #endif // ANDROID_IAPP_OPS_SERVICE_H
diff --git a/libs/binder/include/binder/IBatteryStats.h b/libs/binder/include/binder/IBatteryStats.h
index e15d6f0..59e806c 100644
--- a/libs/binder/include/binder/IBatteryStats.h
+++ b/libs/binder/include/binder/IBatteryStats.h
@@ -17,6 +17,8 @@
 #ifndef ANDROID_IBATTERYSTATS_H
 #define ANDROID_IBATTERYSTATS_H
 
+#ifndef __ANDROID_VNDK__
+
 #include <binder/IInterface.h>
 
 namespace android {
@@ -76,4 +78,8 @@
 
 }; // namespace android
 
+#else // __ANDROID_VNDK__
+#error "This header is not visible to vendors"
+#endif // __ANDROID_VNDK__
+
 #endif // ANDROID_IBATTERYSTATS_H
diff --git a/libs/binder/include/binder/IMediaResourceMonitor.h b/libs/binder/include/binder/IMediaResourceMonitor.h
index b21047f..213ee63 100644
--- a/libs/binder/include/binder/IMediaResourceMonitor.h
+++ b/libs/binder/include/binder/IMediaResourceMonitor.h
@@ -17,6 +17,8 @@
 #ifndef ANDROID_I_MEDIA_RESOURCE_MONITOR_H
 #define ANDROID_I_MEDIA_RESOURCE_MONITOR_H
 
+#ifndef __ANDROID_VNDK__
+
 #include <binder/IInterface.h>
 
 namespace android {
@@ -52,4 +54,8 @@
 
 }; // namespace android
 
+#else // __ANDROID_VNDK__
+#error "This header is not visible to vendors"
+#endif // __ANDROID_VNDK__
+
 #endif // ANDROID_I_MEDIA_RESOURCE_MONITOR_H
diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h
index 245607e..c1d9a9a 100644
--- a/libs/binder/include/binder/IPCThreadState.h
+++ b/libs/binder/include/binder/IPCThreadState.h
@@ -64,9 +64,9 @@
                                          uint32_t code, const Parcel& data,
                                          Parcel* reply, uint32_t flags);
 
-            void                incStrongHandle(int32_t handle);
+            void                incStrongHandle(int32_t handle, BpBinder *proxy);
             void                decStrongHandle(int32_t handle);
-            void                incWeakHandle(int32_t handle);
+            void                incWeakHandle(int32_t handle, BpBinder *proxy);
             void                decWeakHandle(int32_t handle);
             status_t            attemptIncStrongHandle(int32_t handle);
     static  void                expungeHandle(int32_t handle, IBinder* binder);
@@ -106,6 +106,7 @@
             status_t            getAndExecuteCommand();
             status_t            executeCommand(int32_t command);
             void                processPendingDerefs();
+            void                processPostWriteDerefs();
 
             void                clearCaller();
 
@@ -118,7 +119,8 @@
     const   sp<ProcessState>    mProcess;
             Vector<BBinder*>    mPendingStrongDerefs;
             Vector<RefBase::weakref_type*> mPendingWeakDerefs;
-
+            Vector<RefBase*>    mPostWriteStrongDerefs;
+            Vector<RefBase::weakref_type*> mPostWriteWeakDerefs;
             Parcel              mIn;
             Parcel              mOut;
             status_t            mLastError;
diff --git a/libs/binder/include/binder/IPermissionController.h b/libs/binder/include/binder/IPermissionController.h
index 25f3431..3ec459f 100644
--- a/libs/binder/include/binder/IPermissionController.h
+++ b/libs/binder/include/binder/IPermissionController.h
@@ -18,6 +18,8 @@
 #ifndef ANDROID_IPERMISSION_CONTROLLER_H
 #define ANDROID_IPERMISSION_CONTROLLER_H
 
+#ifndef __ANDROID_VNDK__
+
 #include <binder/IInterface.h>
 #include <stdlib.h>
 
@@ -32,14 +34,20 @@
 
     virtual bool checkPermission(const String16& permission, int32_t pid, int32_t uid) = 0;
 
+    virtual int32_t noteOp(const String16& op, int32_t uid, const String16& packageName) = 0;
+
     virtual void getPackagesForUid(const uid_t uid, Vector<String16> &packages) = 0;
 
     virtual bool isRuntimePermission(const String16& permission) = 0;
 
+    virtual int getPackageUid(const String16& package, int flags) = 0;
+
     enum {
         CHECK_PERMISSION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
-        GET_PACKAGES_FOR_UID_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + 1,
-        IS_RUNTIME_PERMISSION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + 2
+        NOTE_OP_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + 1,
+        GET_PACKAGES_FOR_UID_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + 2,
+        IS_RUNTIME_PERMISSION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + 3,
+        GET_PACKAGE_UID_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + 4
     };
 };
 
@@ -58,5 +66,9 @@
 
 }; // namespace android
 
+#else // __ANDROID_VNDK__
+#error "This header is not visible to vendors"
+#endif // __ANDROID_VNDK__
+
 #endif // ANDROID_IPERMISSION_CONTROLLER_H
 
diff --git a/libs/binder/include/binder/IProcessInfoService.h b/libs/binder/include/binder/IProcessInfoService.h
index 2669f91..033c145 100644
--- a/libs/binder/include/binder/IProcessInfoService.h
+++ b/libs/binder/include/binder/IProcessInfoService.h
@@ -17,6 +17,8 @@
 #ifndef ANDROID_I_PROCESS_INFO_SERVICE_H
 #define ANDROID_I_PROCESS_INFO_SERVICE_H
 
+#ifndef __ANDROID_VNDK__
+
 #include <binder/IInterface.h>
 
 namespace android {
@@ -46,4 +48,8 @@
 
 }; // namespace android
 
+#else // __ANDROID_VNDK__
+#error "This header is not visible to vendors"
+#endif // __ANDROID_VNDK__
+
 #endif // ANDROID_I_PROCESS_INFO_SERVICE_H
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index 3b23f81..197026d 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -19,7 +19,6 @@
 #define ANDROID_ISERVICE_MANAGER_H
 
 #include <binder/IInterface.h>
-#include <binder/IPermissionController.h>
 #include <utils/Vector.h>
 #include <utils/String16.h>
 
@@ -31,6 +30,22 @@
 {
 public:
     DECLARE_META_INTERFACE(ServiceManager)
+    /**
+     * Must match values in IServiceManager.java
+     */
+    /* Allows services to dump sections according to priorities. */
+    static const int DUMP_FLAG_PRIORITY_CRITICAL = 1 << 0;
+    static const int DUMP_FLAG_PRIORITY_HIGH = 1 << 1;
+    static const int DUMP_FLAG_PRIORITY_NORMAL = 1 << 2;
+    /**
+     * Services are by default registered with a DEFAULT dump priority. DEFAULT priority has the
+     * same priority as NORMAL priority but the services are not called with dump priority
+     * arguments.
+     */
+    static const int DUMP_FLAG_PRIORITY_DEFAULT = 1 << 3;
+    static const int DUMP_FLAG_PRIORITY_ALL = DUMP_FLAG_PRIORITY_CRITICAL |
+            DUMP_FLAG_PRIORITY_HIGH | DUMP_FLAG_PRIORITY_NORMAL | DUMP_FLAG_PRIORITY_DEFAULT;
+    static const int DUMP_FLAG_PROTO = 1 << 4;
 
     /**
      * Retrieve an existing service, blocking for a few seconds
@@ -46,14 +61,14 @@
     /**
      * Register a service.
      */
-    virtual status_t            addService( const String16& name,
-                                            const sp<IBinder>& service,
-                                            bool allowIsolated = false) = 0;
+    virtual status_t addService(const String16& name, const sp<IBinder>& service,
+                                bool allowIsolated = false,
+                                int dumpsysFlags = DUMP_FLAG_PRIORITY_DEFAULT) = 0;
 
     /**
      * Return list of all existing services.
      */
-    virtual Vector<String16>    listServices() = 0;
+    virtual Vector<String16> listServices(int dumpsysFlags = DUMP_FLAG_PRIORITY_ALL) = 0;
 
     enum {
         GET_SERVICE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
diff --git a/libs/binder/include/binder/IShellCallback.h b/libs/binder/include/binder/IShellCallback.h
index fda9ee6..b47e995 100644
--- a/libs/binder/include/binder/IShellCallback.h
+++ b/libs/binder/include/binder/IShellCallback.h
@@ -29,7 +29,8 @@
 public:
     DECLARE_META_INTERFACE(ShellCallback);
 
-    virtual int openOutputFile(const String16& path, const String16& seLinuxContext) = 0;
+    virtual int openFile(const String16& path, const String16& seLinuxContext,
+            const String16& mode) = 0;
 
     enum {
         OP_OPEN_OUTPUT_FILE = IBinder::FIRST_CALL_TRANSACTION
diff --git a/libs/binder/include/binder/IUidObserver.h b/libs/binder/include/binder/IUidObserver.h
new file mode 100644
index 0000000..d81789e
--- /dev/null
+++ b/libs/binder/include/binder/IUidObserver.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+#ifndef ANDROID_IUID_OBSERVER_H
+#define ANDROID_IUID_OBSERVER_H
+
+#ifndef __ANDROID_VNDK__
+
+#include <binder/IInterface.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------
+
+class IUidObserver : public IInterface
+{
+public:
+    DECLARE_META_INTERFACE(UidObserver)
+
+    virtual void onUidGone(uid_t uid, bool disabled) = 0;
+    virtual void onUidActive(uid_t uid) = 0;
+    virtual void onUidIdle(uid_t uid, bool disabled) = 0;
+
+    enum {
+        ON_UID_GONE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
+        ON_UID_ACTIVE_TRANSACTION,
+        ON_UID_IDLE_TRANSACTION
+    };
+};
+
+// ----------------------------------------------------------------------
+
+class BnUidObserver : public BnInterface<IUidObserver>
+{
+public:
+    virtual status_t  onTransact(uint32_t code,
+                                 const Parcel& data,
+                                 Parcel* reply,
+                                 uint32_t flags = 0);
+};
+
+// ----------------------------------------------------------------------
+
+}; // namespace android
+
+#else // __ANDROID_VNDK__
+#error "This header is not visible to vendors"
+#endif // __ANDROID_VNDK__
+
+#endif // ANDROID_IUID_OBSERVER_H
diff --git a/libs/binder/include/binder/IpPrefix.h b/libs/binder/include/binder/IpPrefix.h
index 96ebaac..dd5bc3a 100644
--- a/libs/binder/include/binder/IpPrefix.h
+++ b/libs/binder/include/binder/IpPrefix.h
@@ -17,6 +17,8 @@
 #ifndef ANDROID_IP_PREFIX_H
 #define ANDROID_IP_PREFIX_H
 
+#ifndef __ANDROID_VNDK__
+
 #include <netinet/in.h>
 
 #include <binder/Parcelable.h>
@@ -85,4 +87,8 @@
 
 }  // namespace android
 
+#else // __ANDROID_VNDK__
+#error "This header is not visible to vendors"
+#endif // __ANDROID_VNDK__
+
 #endif  // ANDROID_IP_PREFIX_H
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index 5d36526..dede78f 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -417,6 +417,7 @@
     void                freeDataNoInit();
     void                initState();
     void                scanForFds() const;
+    status_t            validateReadData(size_t len) const;
                         
     template<class T>
     status_t            readAligned(T *pArg) const;
@@ -463,6 +464,7 @@
     size_t              mObjectsSize;
     size_t              mObjectsCapacity;
     mutable size_t      mNextObjectHint;
+    mutable bool        mObjectsSorted;
 
     mutable bool        mFdsKnown;
     mutable bool        mHasFds;
diff --git a/libs/binder/include/binder/PermissionCache.h b/libs/binder/include/binder/PermissionCache.h
index bcdf0c2..95eabff 100644
--- a/libs/binder/include/binder/PermissionCache.h
+++ b/libs/binder/include/binder/PermissionCache.h
@@ -17,6 +17,8 @@
 #ifndef BINDER_PERMISSION_H
 #define BINDER_PERMISSION_H
 
+#ifndef __ANDROID_VNDK__
+
 #include <stdint.h>
 #include <unistd.h>
 
@@ -77,4 +79,8 @@
 // ---------------------------------------------------------------------------
 }; // namespace android
 
+#else // __ANDROID_VNDK__
+#error "This header is not visible to vendors"
+#endif // __ANDROID_VNDK__
+
 #endif /* BINDER_PERMISSION_H */
diff --git a/libs/binder/include/binder/PermissionController.h b/libs/binder/include/binder/PermissionController.h
new file mode 100644
index 0000000..d81f514
--- /dev/null
+++ b/libs/binder/include/binder/PermissionController.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_PERMISSION_CONTROLLER_H
+#define ANDROID_PERMISSION_CONTROLLER_H
+
+#ifndef __ANDROID_VNDK__
+
+#include <binder/IPermissionController.h>
+
+#include <utils/threads.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+
+class PermissionController
+{
+public:
+
+    enum {
+        MATCH_SYSTEM_ONLY = 1<<16,
+        MATCH_UNINSTALLED_PACKAGES = 1<<13,
+        MATCH_FACTORY_ONLY = 1<<21,
+        MATCH_INSTANT = 1<<23
+    };
+
+    enum {
+        MODE_ALLOWED = 0,
+        MODE_IGNORED = 1,
+        MODE_ERRORED = 2,
+        MODE_DEFAULT = 3,
+    };
+
+    PermissionController();
+
+    bool checkPermission(const String16& permission, int32_t pid, int32_t uid);
+    int32_t noteOp(const String16& op, int32_t uid, const String16& packageName);
+    void getPackagesForUid(const uid_t uid, Vector<String16>& packages);
+    bool isRuntimePermission(const String16& permission);
+    int getPackageUid(const String16& package, int flags);
+
+private:
+    Mutex mLock;
+    sp<IPermissionController> mService;
+
+    sp<IPermissionController> getService();
+};
+
+
+}; // namespace android
+// ---------------------------------------------------------------------------
+#else // __ANDROID_VNDK__
+#error "This header is not visible to vendors"
+#endif // __ANDROID_VNDK__
+
+#endif // ANDROID_PERMISSION_CONTROLLER_H
diff --git a/libs/binder/include/binder/ProcessInfoService.h b/libs/binder/include/binder/ProcessInfoService.h
index 0da61ee..a03aae9 100644
--- a/libs/binder/include/binder/ProcessInfoService.h
+++ b/libs/binder/include/binder/ProcessInfoService.h
@@ -17,6 +17,8 @@
 #ifndef ANDROID_PROCESS_INFO_SERVICE_H
 #define ANDROID_PROCESS_INFO_SERVICE_H
 
+#ifndef __ANDROID_VNDK__
+
 #include <binder/IProcessInfoService.h>
 #include <utils/Errors.h>
 #include <utils/Singleton.h>
@@ -78,5 +80,9 @@
 
 }; // namespace android
 
+#else // __ANDROID_VNDK__
+#error "This header is not visible to vendors"
+#endif // __ANDROID_VNDK__
+
 #endif // ANDROID_PROCESS_INFO_SERVICE_H
 
diff --git a/libs/binder/include/private/binder/Static.h b/libs/binder/include/private/binder/Static.h
index 3d10456..171be77 100644
--- a/libs/binder/include/private/binder/Static.h
+++ b/libs/binder/include/private/binder/Static.h
@@ -21,7 +21,9 @@
 
 #include <binder/IBinder.h>
 #include <binder/ProcessState.h>
+#ifndef __ANDROID_VNDK__
 #include <binder/IPermissionController.h>
+#endif
 #include <binder/IServiceManager.h>
 
 namespace android {
@@ -30,12 +32,15 @@
 extern Vector<int32_t> gTextBuffers;
 
 // For ProcessState.cpp
-extern Mutex gProcessMutex;
+extern Mutex& gProcessMutex;
 extern sp<ProcessState> gProcess;
 
 // For IServiceManager.cpp
 extern Mutex gDefaultServiceManagerLock;
 extern sp<IServiceManager> gDefaultServiceManager;
+#ifndef __ANDROID_VNDK__
 extern sp<IPermissionController> gPermissionController;
+#endif
+extern bool gSystemBootCompleted;
 
 }   // namespace android
diff --git a/libs/binder/tests/binderThroughputTest.cpp b/libs/binder/tests/binderThroughputTest.cpp
index da7fc39..b790997 100644
--- a/libs/binder/tests/binderThroughputTest.cpp
+++ b/libs/binder/tests/binderThroughputTest.cpp
@@ -215,7 +215,7 @@
         int target = cs_pair ? num % server_count : rand() % workers.size();
         int sz = payload_size;
 
-        while (sz > sizeof(uint32_t)) {
+        while (sz >= sizeof(uint32_t)) {
             data.writeInt32(0);
             sz -= sizeof(uint32_t);
         }
@@ -381,6 +381,7 @@
             // No need to run training round in this case.
             if (atoi(argv[i+1]) > 0) {
                 max_time_bucket = strtoull(argv[i+1], (char **)nullptr, 10) * 1000;
+                time_per_bucket = max_time_bucket / num_buckets;
                 i++;
             } else {
                 cout << "Max latency -m must be positive." << endl;
diff --git a/libs/dumputils/Android.bp b/libs/dumputils/Android.bp
new file mode 100644
index 0000000..3412e14
--- /dev/null
+++ b/libs/dumputils/Android.bp
@@ -0,0 +1,34 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library {
+    name: "libdumputils",
+
+    shared_libs: [
+        "libbase",
+        "libbinder",
+        "libhidlbase",
+        "libhidltransport",
+        "liblog",
+        "libutils",
+    ],
+
+    srcs: ["dump_utils.cpp"],
+
+    cflags: ["-Wall", "-Werror"],
+
+    export_include_dirs: [
+        "include",
+    ],
+}
diff --git a/libs/dumputils/dump_utils.cpp b/libs/dumputils/dump_utils.cpp
new file mode 100644
index 0000000..8b2f842
--- /dev/null
+++ b/libs/dumputils/dump_utils.cpp
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <set>
+
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
+#include <android/hidl/manager/1.0/IServiceManager.h>
+#include <dumputils/dump_utils.h>
+#include <log/log.h>
+
+/* list of native processes to include in the native dumps */
+// This matches the /proc/pid/exe link instead of /proc/pid/cmdline.
+static const char* native_processes_to_dump[] = {
+        "/system/bin/audioserver",
+        "/system/bin/cameraserver",
+        "/system/bin/drmserver",
+        "/system/bin/mediadrmserver",
+        "/system/bin/mediaextractor", // media.extractor
+        "/system/bin/mediametrics", // media.metrics
+        "/system/bin/mediaserver",
+        "/system/bin/sdcard",
+        "/system/bin/statsd",
+        "/system/bin/surfaceflinger",
+        "/system/bin/vehicle_network_service",
+        "/vendor/bin/hw/android.hardware.media.omx@1.0-service", // media.codec
+        NULL,
+};
+
+/* list of hal interface to dump containing process during native dumps */
+static const char* hal_interfaces_to_dump[] {
+        "android.hardware.audio@2.0::IDevicesFactory",
+        "android.hardware.audio@4.0::IDevicesFactory",
+        "android.hardware.bluetooth@1.0::IBluetoothHci",
+        "android.hardware.camera.provider@2.4::ICameraProvider",
+        "android.hardware.drm@1.0::IDrmFactory",
+        "android.hardware.graphics.composer@2.1::IComposer",
+        "android.hardware.media.omx@1.0::IOmx",
+        "android.hardware.media.omx@1.0::IOmxStore",
+        "android.hardware.sensors@1.0::ISensors",
+        "android.hardware.vr@1.0::IVr",
+        NULL,
+};
+
+bool should_dump_hal_interface(const char* interface) {
+    for (const char** i = hal_interfaces_to_dump; *i; i++) {
+        if (!strcmp(*i, interface)) {
+            return true;
+        }
+    }
+    return false;
+}
+
+bool should_dump_native_traces(const char* path) {
+    for (const char** p = native_processes_to_dump; *p; p++) {
+        if (!strcmp(*p, path)) {
+            return true;
+        }
+    }
+    return false;
+}
+
+std::set<int> get_interesting_hal_pids() {
+    using android::hidl::manager::V1_0::IServiceManager;
+    using android::sp;
+    using android::hardware::Return;
+
+    sp<IServiceManager> manager = IServiceManager::getService();
+    std::set<int> pids;
+
+    Return<void> ret = manager->debugDump([&](auto& hals) {
+        for (const auto &info : hals) {
+            if (info.pid == static_cast<int>(IServiceManager::PidConstant::NO_PID)) {
+                continue;
+            }
+
+            if (!should_dump_hal_interface(info.interfaceName.c_str())) {
+                continue;
+            }
+
+            pids.insert(info.pid);
+        }
+    });
+
+    if (!ret.isOk()) {
+        ALOGE("Could not get list of HAL PIDs: %s\n", ret.description().c_str());
+    }
+
+    return pids; // whether it was okay or not
+}
+
+bool IsZygote(int pid) {
+    static const std::string kZygotePrefix = "zygote";
+
+    std::string cmdline;
+    if (!android::base::ReadFileToString(android::base::StringPrintf("/proc/%d/cmdline", pid),
+                                         &cmdline)) {
+        return true;
+    }
+
+    return (cmdline.find(kZygotePrefix) == 0);
+}
diff --git a/libs/dumputils/include/dumputils/dump_utils.h b/libs/dumputils/include/dumputils/dump_utils.h
new file mode 100644
index 0000000..25f7127
--- /dev/null
+++ b/libs/dumputils/include/dumputils/dump_utils.h
@@ -0,0 +1,28 @@
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef DUMPUTILS_H_
+#define DUMPUTILS_H_
+
+#include <set>
+
+bool should_dump_native_traces(const char* path);
+
+std::set<int> get_interesting_hal_pids();
+
+bool IsZygote(int pid);
+
+#endif  // DUMPUTILS_H_
diff --git a/libs/graphicsenv/Android.bp b/libs/graphicsenv/Android.bp
index 9f99538..4da30e9 100644
--- a/libs/graphicsenv/Android.bp
+++ b/libs/graphicsenv/Android.bp
@@ -22,7 +22,6 @@
     cflags: ["-Wall", "-Werror"],
 
     shared_libs: [
-        "libnativeloader",
         "liblog",
     ],
 
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index 39b5829..961f101 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -20,12 +20,23 @@
 
 #include <mutex>
 
+#include <android/dlext.h>
 #include <log/log.h>
-#include <nativeloader/dlext_namespaces.h>
 
 // TODO(b/37049319) Get this from a header once one exists
 extern "C" {
   android_namespace_t* android_get_exported_namespace(const char*);
+  android_namespace_t* android_create_namespace(const char* name,
+                                                const char* ld_library_path,
+                                                const char* default_library_path,
+                                                uint64_t type,
+                                                const char* permitted_when_isolated_path,
+                                                android_namespace_t* parent);
+
+  enum {
+     ANDROID_NAMESPACE_TYPE_ISOLATED = 1,
+     ANDROID_NAMESPACE_TYPE_SHARED = 2,
+  };
 }
 
 namespace android {
@@ -45,6 +56,32 @@
     mDriverPath = path;
 }
 
+void GraphicsEnv::setLayerPaths(android_namespace_t* appNamespace, const std::string layerPaths) {
+    if (mLayerPaths.empty()) {
+        mLayerPaths = layerPaths;
+        mAppNamespace = appNamespace;
+    } else {
+        ALOGV("Vulkan layer search path already set, not clobbering with '%s' for namespace %p'",
+                layerPaths.c_str(), appNamespace);
+    }
+}
+
+android_namespace_t* GraphicsEnv::getAppNamespace() {
+    return mAppNamespace;
+}
+
+const std::string GraphicsEnv::getLayerPaths(){
+    return mLayerPaths;
+}
+
+const std::string GraphicsEnv::getDebugLayers() {
+    return mDebugLayers;
+}
+
+void GraphicsEnv::setDebugLayers(const std::string layers) {
+    mDebugLayers = layers;
+}
+
 android_namespace_t* GraphicsEnv::getDriverNamespace() {
     static std::once_flag once;
     std::call_once(once, [this]() {
diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
index 7817076..213580c 100644
--- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
+++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
@@ -35,10 +35,20 @@
     void setDriverPath(const std::string path);
     android_namespace_t* getDriverNamespace();
 
+    void setLayerPaths(android_namespace_t* appNamespace, const std::string layerPaths);
+    android_namespace_t* getAppNamespace();
+    const std::string getLayerPaths();
+
+    void setDebugLayers(const std::string layers);
+    const std::string getDebugLayers();
+
 private:
     GraphicsEnv() = default;
     std::string mDriverPath;
+    std::string mDebugLayers;
+    std::string mLayerPaths;
     android_namespace_t* mDriverNamespace = nullptr;
+    android_namespace_t* mAppNamespace = nullptr;
 };
 
 } // namespace android
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 02d29a3..b29c1d5 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -19,7 +19,7 @@
 
 cc_library_shared {
     name: "libgui",
-    vendor_available: true,
+    vendor_available: false,
     vndk: {
         enabled: true,
     },
@@ -63,6 +63,12 @@
         // Allow documentation warnings
         "-Wno-documentation",
 
+        // Allow implicit instantiation for templated class function
+        "-Wno-undefined-func-template",
+
+        // Allow explicitly marking struct as packed even when unnecessary
+        "-Wno-packed",
+
         "-DDEBUG_ONLY_CODE=0",
     ],
 
@@ -77,6 +83,8 @@
 
     srcs: [
         "BitTube.cpp",
+        "BufferHubConsumer.cpp",
+        "BufferHubProducer.cpp",
         "BufferItem.cpp",
         "BufferItemConsumer.cpp",
         "BufferQueue.cpp",
@@ -90,6 +98,7 @@
         "FrameTimestamps.cpp",
         "GLConsumer.cpp",
         "GuiConfig.cpp",
+        "HdrMetadata.cpp",
         "IDisplayEventConnection.cpp",
         "IConsumerListener.cpp",
         "IGraphicBufferConsumer.cpp",
@@ -111,8 +120,11 @@
     ],
 
     shared_libs: [
+        "android.hardware.graphics.common@1.1",
         "libsync",
         "libbinder",
+        "libbufferhubqueue",  // TODO(b/70046255): Remove this once BufferHub is integrated into libgui.
+        "libpdx_default_transport",
         "libcutils",
         "libEGL",
         "libGLESv2",
@@ -128,9 +140,26 @@
         "android.hardware.configstore-utils",
     ],
 
+    // bufferhub is not used when building libgui for vendors
+    target: {
+        vendor: {
+            cflags: ["-DNO_BUFFERHUB"],
+            exclude_srcs: [
+                "BufferHubConsumer.cpp",
+                "BufferHubProducer.cpp",
+            ],
+            exclude_shared_libs: [
+                "libbufferhubqueue",
+                "libpdx_default_transport",
+            ],
+        },
+    },
+
     header_libs: [
+        "libdvr_headers",
         "libnativebase_headers",
         "libgui_headers",
+        "libpdx_headers",
     ],
 
     export_shared_lib_headers: [
@@ -140,6 +169,7 @@
         "libui",
         "android.hidl.token@1.0-utils",
         "android.hardware.graphics.bufferqueue@1.0",
+        "android.hardware.graphics.common@1.1",
     ],
 
     export_header_lib_headers: [
diff --git a/libs/gui/BufferHubConsumer.cpp b/libs/gui/BufferHubConsumer.cpp
new file mode 100644
index 0000000..b5cdeb2
--- /dev/null
+++ b/libs/gui/BufferHubConsumer.cpp
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gui/BufferHubConsumer.h>
+
+namespace android {
+
+using namespace dvr;
+
+/* static */
+sp<BufferHubConsumer> BufferHubConsumer::Create(const std::shared_ptr<ConsumerQueue>& queue) {
+    sp<BufferHubConsumer> consumer = new BufferHubConsumer;
+    consumer->mQueue = queue;
+    return consumer;
+}
+
+/* static */ sp<BufferHubConsumer> BufferHubConsumer::Create(ConsumerQueueParcelable parcelable) {
+    if (!parcelable.IsValid()) {
+        ALOGE("BufferHubConsumer::Create: Invalid consumer parcelable.");
+        return nullptr;
+    }
+
+    sp<BufferHubConsumer> consumer = new BufferHubConsumer;
+    consumer->mQueue = ConsumerQueue::Import(parcelable.TakeChannelHandle());
+    return consumer;
+}
+
+status_t BufferHubConsumer::acquireBuffer(BufferItem* /*buffer*/, nsecs_t /*presentWhen*/,
+                                          uint64_t /*maxFrameNumber*/) {
+    ALOGE("BufferHubConsumer::acquireBuffer: not implemented.");
+    return INVALID_OPERATION;
+}
+
+status_t BufferHubConsumer::detachBuffer(int /*slot*/) {
+    ALOGE("BufferHubConsumer::detachBuffer: not implemented.");
+    return INVALID_OPERATION;
+}
+
+status_t BufferHubConsumer::attachBuffer(int* /*outSlot*/, const sp<GraphicBuffer>& /*buffer*/) {
+    ALOGE("BufferHubConsumer::attachBuffer: not implemented.");
+    return INVALID_OPERATION;
+}
+
+status_t BufferHubConsumer::releaseBuffer(int /*buf*/, uint64_t /*frameNumber*/,
+                                          EGLDisplay /*display*/, EGLSyncKHR /*fence*/,
+                                          const sp<Fence>& /*releaseFence*/) {
+    ALOGE("BufferHubConsumer::releaseBuffer: not implemented.");
+    return INVALID_OPERATION;
+}
+
+status_t BufferHubConsumer::consumerConnect(const sp<IConsumerListener>& /*consumer*/,
+                                            bool /*controlledByApp*/) {
+    ALOGE("BufferHubConsumer::consumerConnect: not implemented.");
+
+    // TODO(b/73267953): Make BufferHub honor producer and consumer connection. Returns NO_ERROR to
+    // make IGraphicBufferConsumer_test happy.
+    return NO_ERROR;
+}
+
+status_t BufferHubConsumer::consumerDisconnect() {
+    ALOGE("BufferHubConsumer::consumerDisconnect: not implemented.");
+
+    // TODO(b/73267953): Make BufferHub honor producer and consumer connection. Returns NO_ERROR to
+    // make IGraphicBufferConsumer_test happy.
+    return NO_ERROR;
+}
+
+status_t BufferHubConsumer::getReleasedBuffers(uint64_t* /*slotMask*/) {
+    ALOGE("BufferHubConsumer::getReleasedBuffers: not implemented.");
+    return INVALID_OPERATION;
+}
+
+status_t BufferHubConsumer::setDefaultBufferSize(uint32_t /*w*/, uint32_t /*h*/) {
+    ALOGE("BufferHubConsumer::setDefaultBufferSize: not implemented.");
+    return INVALID_OPERATION;
+}
+
+status_t BufferHubConsumer::setMaxBufferCount(int /*bufferCount*/) {
+    ALOGE("BufferHubConsumer::setMaxBufferCount: not implemented.");
+    return INVALID_OPERATION;
+}
+
+status_t BufferHubConsumer::setMaxAcquiredBufferCount(int /*maxAcquiredBuffers*/) {
+    ALOGE("BufferHubConsumer::setMaxAcquiredBufferCount: not implemented.");
+
+    // TODO(b/73267953): Make BufferHub honor producer and consumer connection. Returns NO_ERROR to
+    // make IGraphicBufferConsumer_test happy.
+    return NO_ERROR;
+}
+
+status_t BufferHubConsumer::setConsumerName(const String8& /*name*/) {
+    ALOGE("BufferHubConsumer::setConsumerName: not implemented.");
+    return INVALID_OPERATION;
+}
+
+status_t BufferHubConsumer::setDefaultBufferFormat(PixelFormat /*defaultFormat*/) {
+    ALOGE("BufferHubConsumer::setDefaultBufferFormat: not implemented.");
+    return INVALID_OPERATION;
+}
+
+status_t BufferHubConsumer::setDefaultBufferDataSpace(android_dataspace /*defaultDataSpace*/) {
+    ALOGE("BufferHubConsumer::setDefaultBufferDataSpace: not implemented.");
+    return INVALID_OPERATION;
+}
+
+status_t BufferHubConsumer::setConsumerUsageBits(uint64_t /*usage*/) {
+    ALOGE("BufferHubConsumer::setConsumerUsageBits: not implemented.");
+    return INVALID_OPERATION;
+}
+
+status_t BufferHubConsumer::setConsumerIsProtected(bool /*isProtected*/) {
+    ALOGE("BufferHubConsumer::setConsumerIsProtected: not implemented.");
+    return INVALID_OPERATION;
+}
+
+status_t BufferHubConsumer::setTransformHint(uint32_t /*hint*/) {
+    ALOGE("BufferHubConsumer::setTransformHint: not implemented.");
+    return INVALID_OPERATION;
+}
+
+status_t BufferHubConsumer::getSidebandStream(sp<NativeHandle>* /*outStream*/) const {
+    ALOGE("BufferHubConsumer::getSidebandStream: not implemented.");
+    return INVALID_OPERATION;
+}
+
+status_t BufferHubConsumer::getOccupancyHistory(
+        bool /*forceFlush*/, std::vector<OccupancyTracker::Segment>* /*outHistory*/) {
+    ALOGE("BufferHubConsumer::getOccupancyHistory: not implemented.");
+    return INVALID_OPERATION;
+}
+
+status_t BufferHubConsumer::discardFreeBuffers() {
+    ALOGE("BufferHubConsumer::discardFreeBuffers: not implemented.");
+    return INVALID_OPERATION;
+}
+
+status_t BufferHubConsumer::dumpState(const String8& /*prefix*/, String8* /*outResult*/) const {
+    ALOGE("BufferHubConsumer::dumpState: not implemented.");
+    return INVALID_OPERATION;
+}
+
+IBinder* BufferHubConsumer::onAsBinder() {
+    ALOGE("BufferHubConsumer::onAsBinder: BufferHubConsumer should never be used as an Binder "
+          "object.");
+    return nullptr;
+}
+
+} // namespace android
diff --git a/libs/gui/BufferHubProducer.cpp b/libs/gui/BufferHubProducer.cpp
new file mode 100644
index 0000000..ae5cca2
--- /dev/null
+++ b/libs/gui/BufferHubProducer.cpp
@@ -0,0 +1,717 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <dvr/dvr_api.h>
+#include <gui/BufferHubProducer.h>
+#include <inttypes.h>
+#include <log/log.h>
+#include <system/window.h>
+
+namespace android {
+
+using namespace dvr;
+
+/* static */
+sp<BufferHubProducer> BufferHubProducer::Create(const std::shared_ptr<ProducerQueue>& queue) {
+    sp<BufferHubProducer> producer = new BufferHubProducer;
+    producer->queue_ = queue;
+    return producer;
+}
+
+/* static */
+sp<BufferHubProducer> BufferHubProducer::Create(ProducerQueueParcelable parcelable) {
+    if (!parcelable.IsValid()) {
+        ALOGE("BufferHubProducer::Create: Invalid producer parcelable.");
+        return nullptr;
+    }
+
+    sp<BufferHubProducer> producer = new BufferHubProducer;
+    producer->queue_ = ProducerQueue::Import(parcelable.TakeChannelHandle());
+    return producer;
+}
+
+status_t BufferHubProducer::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
+    ALOGV("requestBuffer: slot=%d", slot);
+
+    std::unique_lock<std::mutex> lock(mutex_);
+
+    if (connected_api_ == kNoConnectedApi) {
+        ALOGE("requestBuffer: BufferHubProducer has no connected producer");
+        return NO_INIT;
+    }
+
+    if (slot < 0 || slot >= max_buffer_count_) {
+        ALOGE("requestBuffer: slot index %d out of range [0, %d)", slot, max_buffer_count_);
+        return BAD_VALUE;
+    } else if (!buffers_[slot].mBufferState.isDequeued()) {
+        ALOGE("requestBuffer: slot %d is not owned by the producer (state = %s)", slot,
+              buffers_[slot].mBufferState.string());
+        return BAD_VALUE;
+    } else if (buffers_[slot].mGraphicBuffer != nullptr) {
+        ALOGE("requestBuffer: slot %d is not empty.", slot);
+        return BAD_VALUE;
+    } else if (buffers_[slot].mBufferProducer == nullptr) {
+        ALOGE("requestBuffer: slot %d is not dequeued.", slot);
+        return BAD_VALUE;
+    }
+
+    const auto& buffer_producer = buffers_[slot].mBufferProducer;
+    sp<GraphicBuffer> graphic_buffer = buffer_producer->buffer()->buffer();
+
+    buffers_[slot].mGraphicBuffer = graphic_buffer;
+    buffers_[slot].mRequestBufferCalled = true;
+
+    *buf = graphic_buffer;
+    return NO_ERROR;
+}
+
+status_t BufferHubProducer::setMaxDequeuedBufferCount(int max_dequeued_buffers) {
+    ALOGV("setMaxDequeuedBufferCount: max_dequeued_buffers=%d", max_dequeued_buffers);
+
+    std::unique_lock<std::mutex> lock(mutex_);
+
+    if (max_dequeued_buffers <= 0 ||
+        max_dequeued_buffers >
+                int(BufferHubQueue::kMaxQueueCapacity - kDefaultUndequeuedBuffers)) {
+        ALOGE("setMaxDequeuedBufferCount: %d out of range (0, %zu]", max_dequeued_buffers,
+              BufferHubQueue::kMaxQueueCapacity);
+        return BAD_VALUE;
+    }
+
+    // The new dequeued_buffers count should not be violated by the number
+    // of currently dequeued buffers.
+    int dequeued_count = 0;
+    for (const auto& buf : buffers_) {
+        if (buf.mBufferState.isDequeued()) {
+            dequeued_count++;
+        }
+    }
+    if (dequeued_count > max_dequeued_buffers) {
+        ALOGE("setMaxDequeuedBufferCount: the requested dequeued_buffers"
+              "count (%d) exceeds the current dequeued buffer count (%d)",
+              max_dequeued_buffers, dequeued_count);
+        return BAD_VALUE;
+    }
+
+    max_dequeued_buffer_count_ = max_dequeued_buffers;
+    return NO_ERROR;
+}
+
+status_t BufferHubProducer::setAsyncMode(bool async) {
+    if (async) {
+        // TODO(b/36724099) BufferHubQueue's consumer end always acquires the buffer
+        // automatically and behaves differently from IGraphicBufferConsumer. Thus,
+        // android::BufferQueue's async mode (a.k.a. allocating an additional buffer
+        // to prevent dequeueBuffer from being blocking) technically does not apply
+        // here.
+        //
+        // In Daydream, non-blocking producer side dequeue is guaranteed by careful
+        // buffer consumer implementations. In another word, BufferHubQueue based
+        // dequeueBuffer should never block whether setAsyncMode(true) is set or
+        // not.
+        //
+        // See: IGraphicBufferProducer::setAsyncMode and
+        // BufferQueueProducer::setAsyncMode for more about original implementation.
+        ALOGW("BufferHubProducer::setAsyncMode: BufferHubQueue should always be "
+              "asynchronous. This call makes no effact.");
+        return NO_ERROR;
+    }
+    return NO_ERROR;
+}
+
+status_t BufferHubProducer::dequeueBuffer(int* out_slot, sp<Fence>* out_fence, uint32_t width,
+                                          uint32_t height, PixelFormat format, uint64_t usage,
+                                          uint64_t* /*outBufferAge*/,
+                                          FrameEventHistoryDelta* /* out_timestamps */) {
+    ALOGV("dequeueBuffer: w=%u, h=%u, format=%d, usage=%" PRIu64, width, height, format, usage);
+
+    status_t ret;
+    std::unique_lock<std::mutex> lock(mutex_);
+
+    if (connected_api_ == kNoConnectedApi) {
+        ALOGE("dequeueBuffer: BufferQueue has no connected producer");
+        return NO_INIT;
+    }
+
+    const uint32_t kLayerCount = 1;
+    if (int32_t(queue_->capacity()) < max_dequeued_buffer_count_ + kDefaultUndequeuedBuffers) {
+        // Lazy allocation. When the capacity of |queue_| has not reached
+        // |max_dequeued_buffer_count_|, allocate new buffer.
+        // TODO(jwcai) To save memory, the really reasonable thing to do is to go
+        // over existing slots and find first existing one to dequeue.
+        ret = AllocateBuffer(width, height, kLayerCount, format, usage);
+        if (ret < 0) return ret;
+    }
+
+    size_t slot = 0;
+    std::shared_ptr<BufferProducer> buffer_producer;
+
+    for (size_t retry = 0; retry < BufferHubQueue::kMaxQueueCapacity; retry++) {
+        LocalHandle fence;
+        auto buffer_status = queue_->Dequeue(dequeue_timeout_ms_, &slot, &fence);
+        if (!buffer_status) return NO_MEMORY;
+
+        buffer_producer = buffer_status.take();
+        if (!buffer_producer) return NO_MEMORY;
+
+        if (width == buffer_producer->width() && height == buffer_producer->height() &&
+            uint32_t(format) == buffer_producer->format()) {
+            // The producer queue returns a buffer producer matches the request.
+            break;
+        }
+
+        // Needs reallocation.
+        // TODO(jwcai) Consider use VLOG instead if we find this log is not useful.
+        ALOGI("dequeueBuffer: requested buffer (w=%u, h=%u, format=%u) is different "
+              "from the buffer returned at slot: %zu (w=%u, h=%u, format=%u). Need "
+              "re-allocattion.",
+              width, height, format, slot, buffer_producer->width(), buffer_producer->height(),
+              buffer_producer->format());
+        // Mark the slot as reallocating, so that later we can set
+        // BUFFER_NEEDS_REALLOCATION when the buffer actually get dequeued.
+        buffers_[slot].mIsReallocating = true;
+
+        // Remove the old buffer once the allocation before allocating its
+        // replacement.
+        RemoveBuffer(slot);
+
+        // Allocate a new producer buffer with new buffer configs. Note that if
+        // there are already multiple buffers in the queue, the next one returned
+        // from |queue_->Dequeue| may not be the new buffer we just reallocated.
+        // Retry up to BufferHubQueue::kMaxQueueCapacity times.
+        ret = AllocateBuffer(width, height, kLayerCount, format, usage);
+        if (ret < 0) return ret;
+    }
+
+    // With the BufferHub backed solution. Buffer slot returned from
+    // |queue_->Dequeue| is guaranteed to avaiable for producer's use.
+    // It's either in free state (if the buffer has never been used before) or
+    // in queued state (if the buffer has been dequeued and queued back to
+    // BufferHubQueue).
+    LOG_ALWAYS_FATAL_IF((!buffers_[slot].mBufferState.isFree() &&
+                         !buffers_[slot].mBufferState.isQueued()),
+                        "dequeueBuffer: slot %zu is not free or queued, actual state: %s.", slot,
+                        buffers_[slot].mBufferState.string());
+
+    buffers_[slot].mBufferState.freeQueued();
+    buffers_[slot].mBufferState.dequeue();
+    ALOGV("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.
+    *out_fence = Fence::NO_FENCE;
+    *out_slot = int(slot);
+    ret = NO_ERROR;
+
+    if (buffers_[slot].mIsReallocating) {
+        ret |= BUFFER_NEEDS_REALLOCATION;
+        buffers_[slot].mIsReallocating = false;
+    }
+
+    return ret;
+}
+
+status_t BufferHubProducer::detachBuffer(int /* slot */) {
+    ALOGE("BufferHubProducer::detachBuffer not implemented.");
+    return INVALID_OPERATION;
+}
+
+status_t BufferHubProducer::detachNextBuffer(sp<GraphicBuffer>* /* out_buffer */,
+                                             sp<Fence>* /* out_fence */) {
+    ALOGE("BufferHubProducer::detachNextBuffer not implemented.");
+    return INVALID_OPERATION;
+}
+
+status_t BufferHubProducer::attachBuffer(int* /* out_slot */,
+                                         const sp<GraphicBuffer>& /* buffer */) {
+    // With this BufferHub backed implementation, we assume (for now) all buffers
+    // are allocated and owned by the BufferHub. Thus the attempt of transfering
+    // ownership of a buffer to the buffer queue is intentionally unsupported.
+    LOG_ALWAYS_FATAL("BufferHubProducer::attachBuffer not supported.");
+    return INVALID_OPERATION;
+}
+
+status_t BufferHubProducer::queueBuffer(int slot, const QueueBufferInput& input,
+                                        QueueBufferOutput* output) {
+    ALOGV("queueBuffer: slot %d", slot);
+
+    if (output == nullptr) {
+        return BAD_VALUE;
+    }
+
+    int64_t timestamp;
+    bool is_auto_timestamp;
+    android_dataspace dataspace;
+    Rect crop(Rect::EMPTY_RECT);
+    int scaling_mode;
+    uint32_t transform;
+    sp<Fence> fence;
+
+    input.deflate(&timestamp, &is_auto_timestamp, &dataspace, &crop, &scaling_mode, &transform,
+                  &fence);
+
+    // Check input scaling mode is valid.
+    switch (scaling_mode) {
+        case NATIVE_WINDOW_SCALING_MODE_FREEZE:
+        case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW:
+        case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP:
+        case NATIVE_WINDOW_SCALING_MODE_NO_SCALE_CROP:
+            break;
+        default:
+            ALOGE("queueBuffer: unknown scaling mode %d", scaling_mode);
+            return BAD_VALUE;
+    }
+
+    // Check input fence is valid.
+    if (fence == nullptr) {
+        ALOGE("queueBuffer: fence is NULL");
+        return BAD_VALUE;
+    }
+
+    std::unique_lock<std::mutex> lock(mutex_);
+
+    if (connected_api_ == kNoConnectedApi) {
+        ALOGE("queueBuffer: BufferQueue has no connected producer");
+        return NO_INIT;
+    }
+
+    if (slot < 0 || slot >= max_buffer_count_) {
+        ALOGE("queueBuffer: slot index %d out of range [0, %d)", slot, max_buffer_count_);
+        return BAD_VALUE;
+    } else if (!buffers_[slot].mBufferState.isDequeued()) {
+        ALOGE("queueBuffer: slot %d is not owned by the producer (state = %s)", slot,
+              buffers_[slot].mBufferState.string());
+        return BAD_VALUE;
+    } else if ((!buffers_[slot].mRequestBufferCalled || buffers_[slot].mGraphicBuffer == nullptr)) {
+        ALOGE("queueBuffer: slot %d is not requested (mRequestBufferCalled=%d, "
+              "mGraphicBuffer=%p)",
+              slot, buffers_[slot].mRequestBufferCalled, buffers_[slot].mGraphicBuffer.get());
+        return BAD_VALUE;
+    }
+
+    // Post the buffer producer with timestamp in the metadata.
+    const auto& buffer_producer = buffers_[slot].mBufferProducer;
+
+    // Check input crop is not out of boundary of current buffer.
+    Rect buffer_rect(buffer_producer->width(), buffer_producer->height());
+    Rect cropped_rect(Rect::EMPTY_RECT);
+    crop.intersect(buffer_rect, &cropped_rect);
+    if (cropped_rect != crop) {
+        ALOGE("queueBuffer: slot %d has out-of-boundary crop.", slot);
+        return BAD_VALUE;
+    }
+
+    LocalHandle fence_fd(fence->isValid() ? fence->dup() : -1);
+
+    DvrNativeBufferMetadata meta_data;
+    meta_data.timestamp = timestamp;
+    meta_data.is_auto_timestamp = int32_t(is_auto_timestamp);
+    meta_data.dataspace = int32_t(dataspace);
+    meta_data.crop_left = crop.left;
+    meta_data.crop_top = crop.top;
+    meta_data.crop_right = crop.right;
+    meta_data.crop_bottom = crop.bottom;
+    meta_data.scaling_mode = int32_t(scaling_mode);
+    meta_data.transform = int32_t(transform);
+
+    buffer_producer->PostAsync(&meta_data, fence_fd);
+    buffers_[slot].mBufferState.queue();
+
+    output->width = buffer_producer->width();
+    output->height = buffer_producer->height();
+    output->transformHint = 0; // default value, we don't use it yet.
+
+    // |numPendingBuffers| counts of the number of buffers that has been enqueued
+    // by the producer but not yet acquired by the consumer. Due to the nature
+    // of BufferHubQueue design, this is hard to trace from the producer's client
+    // side, but it's safe to assume it's zero.
+    output->numPendingBuffers = 0;
+
+    // Note that we are not setting nextFrameNumber here as it seems to be only
+    // used by surface flinger. See more at b/22802885, ag/791760.
+    output->nextFrameNumber = 0;
+
+    return NO_ERROR;
+}
+
+status_t BufferHubProducer::cancelBuffer(int slot, const sp<Fence>& fence) {
+    ALOGV(__FUNCTION__);
+
+    std::unique_lock<std::mutex> lock(mutex_);
+
+    if (connected_api_ == kNoConnectedApi) {
+        ALOGE("cancelBuffer: BufferQueue has no connected producer");
+        return NO_INIT;
+    }
+
+    if (slot < 0 || slot >= max_buffer_count_) {
+        ALOGE("cancelBuffer: slot index %d out of range [0, %d)", slot, max_buffer_count_);
+        return BAD_VALUE;
+    } else if (!buffers_[slot].mBufferState.isDequeued()) {
+        ALOGE("cancelBuffer: slot %d is not owned by the producer (state = %s)", slot,
+              buffers_[slot].mBufferState.string());
+        return BAD_VALUE;
+    } else if (fence == nullptr) {
+        ALOGE("cancelBuffer: fence is NULL");
+        return BAD_VALUE;
+    }
+
+    auto buffer_producer = buffers_[slot].mBufferProducer;
+    queue_->Enqueue(buffer_producer, size_t(slot), 0ULL);
+    buffers_[slot].mBufferState.cancel();
+    buffers_[slot].mFence = fence;
+    ALOGV("cancelBuffer: slot %d", slot);
+
+    return NO_ERROR;
+}
+
+status_t BufferHubProducer::query(int what, int* out_value) {
+    ALOGV(__FUNCTION__);
+
+    std::unique_lock<std::mutex> lock(mutex_);
+
+    if (out_value == nullptr) {
+        ALOGE("query: out_value was NULL");
+        return BAD_VALUE;
+    }
+
+    int value = 0;
+    switch (what) {
+        case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
+            // TODO(b/36187402) This should be the maximum number of buffers that this
+            // producer queue's consumer can acquire. Set to be at least one. Need to
+            // find a way to set from the consumer side.
+            value = kDefaultUndequeuedBuffers;
+            break;
+        case NATIVE_WINDOW_BUFFER_AGE:
+            value = 0;
+            break;
+        case NATIVE_WINDOW_WIDTH:
+            value = int32_t(queue_->default_width());
+            break;
+        case NATIVE_WINDOW_HEIGHT:
+            value = int32_t(queue_->default_height());
+            break;
+        case NATIVE_WINDOW_FORMAT:
+            value = int32_t(queue_->default_format());
+            break;
+        case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND:
+            // BufferHubQueue is always operating in async mode, thus semantically
+            // consumer can never be running behind. See BufferQueueCore.cpp core
+            // for more information about the original meaning of this flag.
+            value = 0;
+            break;
+        case NATIVE_WINDOW_CONSUMER_USAGE_BITS:
+            // TODO(jwcai) This is currently not implement as we don't need
+            // IGraphicBufferConsumer parity.
+            value = 0;
+            break;
+        case NATIVE_WINDOW_DEFAULT_DATASPACE:
+            // TODO(jwcai) Return the default value android::BufferQueue is using as
+            // there is no way dvr::ConsumerQueue can set it.
+            value = 0; // HAL_DATASPACE_UNKNOWN
+            break;
+        case NATIVE_WINDOW_STICKY_TRANSFORM:
+            // TODO(jwcai) Return the default value android::BufferQueue is using as
+            // there is no way dvr::ConsumerQueue can set it.
+            value = 0;
+            break;
+        case NATIVE_WINDOW_CONSUMER_IS_PROTECTED:
+            // In Daydream's implementation, the consumer end (i.e. VR Compostior)
+            // knows how to handle protected buffers.
+            value = 1;
+            break;
+        default:
+            return BAD_VALUE;
+    }
+
+    ALOGV("query: key=%d, v=%d", what, value);
+    *out_value = value;
+    return NO_ERROR;
+}
+
+status_t BufferHubProducer::connect(const sp<IProducerListener>& /* listener */, int api,
+                                    bool /* producer_controlled_by_app */,
+                                    QueueBufferOutput* output) {
+    // Consumer interaction are actually handled by buffer hub, and we need
+    // to maintain consumer operations here. We only need to perform basic input
+    // parameter checks here.
+    ALOGV(__FUNCTION__);
+
+    if (output == nullptr) {
+        return BAD_VALUE;
+    }
+
+    std::unique_lock<std::mutex> lock(mutex_);
+
+    if (connected_api_ != kNoConnectedApi) {
+        return BAD_VALUE;
+    }
+
+    if (!queue_->is_connected()) {
+        ALOGE("BufferHubProducer::connect: This BufferHubProducer is not "
+              "connected to bufferhud. Has it been taken out as a parcelable?");
+        return BAD_VALUE;
+    }
+
+    switch (api) {
+        case NATIVE_WINDOW_API_EGL:
+        case NATIVE_WINDOW_API_CPU:
+        case NATIVE_WINDOW_API_MEDIA:
+        case NATIVE_WINDOW_API_CAMERA:
+            connected_api_ = api;
+
+            output->width = queue_->default_width();
+            output->height = queue_->default_height();
+
+            // default values, we don't use them yet.
+            output->transformHint = 0;
+            output->numPendingBuffers = 0;
+            output->nextFrameNumber = 0;
+            output->bufferReplaced = false;
+
+            break;
+        default:
+            ALOGE("BufferHubProducer::connect: unknow API %d", api);
+            return BAD_VALUE;
+    }
+
+    return NO_ERROR;
+}
+
+status_t BufferHubProducer::disconnect(int api, DisconnectMode /*mode*/) {
+    // Consumer interaction are actually handled by buffer hub, and we need
+    // to maintain consumer operations here.  We only need to perform basic input
+    // parameter checks here.
+    ALOGV(__FUNCTION__);
+
+    std::unique_lock<std::mutex> lock(mutex_);
+
+    if (kNoConnectedApi == connected_api_) {
+        return NO_INIT;
+    } else if (api != connected_api_) {
+        return BAD_VALUE;
+    }
+
+    FreeAllBuffers();
+    connected_api_ = kNoConnectedApi;
+    return NO_ERROR;
+}
+
+status_t BufferHubProducer::setSidebandStream(const sp<NativeHandle>& stream) {
+    if (stream != nullptr) {
+        // TODO(jwcai) Investigate how is is used, maybe use BufferHubBuffer's
+        // metadata.
+        ALOGE("SidebandStream is not currently supported.");
+        return INVALID_OPERATION;
+    }
+    return NO_ERROR;
+}
+
+void BufferHubProducer::allocateBuffers(uint32_t /* width */, uint32_t /* height */,
+                                        PixelFormat /* format */, uint64_t /* usage */) {
+    // TODO(jwcai) |allocateBuffers| aims to preallocate up to the maximum number
+    // of buffers permitted by the current BufferQueue configuration (aka
+    // |max_buffer_count_|).
+    ALOGE("BufferHubProducer::allocateBuffers not implemented.");
+}
+
+status_t BufferHubProducer::allowAllocation(bool /* allow */) {
+    ALOGE("BufferHubProducer::allowAllocation not implemented.");
+    return INVALID_OPERATION;
+}
+
+status_t BufferHubProducer::setGenerationNumber(uint32_t generation_number) {
+    ALOGV(__FUNCTION__);
+
+    std::unique_lock<std::mutex> lock(mutex_);
+    generation_number_ = generation_number;
+    return NO_ERROR;
+}
+
+String8 BufferHubProducer::getConsumerName() const {
+    // BufferHub based implementation could have one to many producer/consumer
+    // relationship, thus |getConsumerName| from the producer side does not
+    // make any sense.
+    ALOGE("BufferHubProducer::getConsumerName not supported.");
+    return String8("BufferHubQueue::DummyConsumer");
+}
+
+status_t BufferHubProducer::setSharedBufferMode(bool shared_buffer_mode) {
+    if (shared_buffer_mode) {
+        ALOGE("BufferHubProducer::setSharedBufferMode(true) is not supported.");
+        // TODO(b/36373181) Front buffer mode for buffer hub queue as ANativeWindow.
+        return INVALID_OPERATION;
+    }
+    // Setting to default should just work as a no-op.
+    return NO_ERROR;
+}
+
+status_t BufferHubProducer::setAutoRefresh(bool auto_refresh) {
+    if (auto_refresh) {
+        ALOGE("BufferHubProducer::setAutoRefresh(true) is not supported.");
+        return INVALID_OPERATION;
+    }
+    // Setting to default should just work as a no-op.
+    return NO_ERROR;
+}
+
+status_t BufferHubProducer::setDequeueTimeout(nsecs_t timeout) {
+    ALOGV(__FUNCTION__);
+
+    std::unique_lock<std::mutex> lock(mutex_);
+    dequeue_timeout_ms_ = static_cast<int>(timeout / (1000 * 1000));
+    return NO_ERROR;
+}
+
+status_t BufferHubProducer::getLastQueuedBuffer(sp<GraphicBuffer>* /* out_buffer */,
+                                                sp<Fence>* /* out_fence */,
+                                                float /*out_transform_matrix*/[16]) {
+    ALOGE("BufferHubProducer::getLastQueuedBuffer not implemented.");
+    return INVALID_OPERATION;
+}
+
+void BufferHubProducer::getFrameTimestamps(FrameEventHistoryDelta* /*outDelta*/) {
+    ALOGE("BufferHubProducer::getFrameTimestamps not implemented.");
+}
+
+status_t BufferHubProducer::getUniqueId(uint64_t* out_id) const {
+    ALOGV(__FUNCTION__);
+
+    *out_id = unique_id_;
+    return NO_ERROR;
+}
+
+status_t BufferHubProducer::getConsumerUsage(uint64_t* out_usage) const {
+    ALOGV(__FUNCTION__);
+
+    // same value as returned by querying NATIVE_WINDOW_CONSUMER_USAGE_BITS
+    *out_usage = 0;
+    return NO_ERROR;
+}
+
+status_t BufferHubProducer::TakeAsParcelable(ProducerQueueParcelable* out_parcelable) {
+    if (!out_parcelable || out_parcelable->IsValid()) return BAD_VALUE;
+
+    if (connected_api_ != kNoConnectedApi) {
+        ALOGE("BufferHubProducer::TakeAsParcelable: BufferHubProducer has "
+              "connected client. Must disconnect first.");
+        return BAD_VALUE;
+    }
+
+    if (!queue_->is_connected()) {
+        ALOGE("BufferHubProducer::TakeAsParcelable: This BufferHubProducer "
+              "is not connected to bufferhud. Has it been taken out as a "
+              "parcelable?");
+        return BAD_VALUE;
+    }
+
+    auto status = queue_->TakeAsParcelable();
+    if (!status) {
+        ALOGE("BufferHubProducer::TakeAsParcelable: Failed to take out "
+              "ProducuerQueueParcelable from the producer queue, error: %s.",
+              status.GetErrorMessage().c_str());
+        return BAD_VALUE;
+    }
+
+    *out_parcelable = status.take();
+    return NO_ERROR;
+}
+
+status_t BufferHubProducer::AllocateBuffer(uint32_t width, uint32_t height, uint32_t layer_count,
+                                           PixelFormat format, uint64_t usage) {
+    auto status = queue_->AllocateBuffer(width, height, layer_count, uint32_t(format), usage);
+    if (!status) {
+        ALOGE("BufferHubProducer::AllocateBuffer: Failed to allocate buffer: %s",
+              status.GetErrorMessage().c_str());
+        return NO_MEMORY;
+    }
+
+    size_t slot = status.get();
+    auto buffer_producer = queue_->GetBuffer(slot);
+
+    LOG_ALWAYS_FATAL_IF(buffer_producer == nullptr, "Failed to get buffer producer at slot: %zu",
+                        slot);
+
+    buffers_[slot].mBufferProducer = buffer_producer;
+
+    return NO_ERROR;
+}
+
+status_t BufferHubProducer::RemoveBuffer(size_t slot) {
+    auto status = queue_->RemoveBuffer(slot);
+    if (!status) {
+        ALOGE("BufferHubProducer::RemoveBuffer: Failed to remove buffer: %s",
+              status.GetErrorMessage().c_str());
+        return INVALID_OPERATION;
+    }
+
+    // Reset in memory objects related the the buffer.
+    buffers_[slot].mBufferProducer = nullptr;
+    buffers_[slot].mGraphicBuffer = nullptr;
+    buffers_[slot].mBufferState.detachProducer();
+    return NO_ERROR;
+}
+
+status_t BufferHubProducer::FreeAllBuffers() {
+    for (size_t slot = 0; slot < BufferHubQueue::kMaxQueueCapacity; slot++) {
+        // Reset in memory objects related the the buffer.
+        buffers_[slot].mGraphicBuffer = nullptr;
+        buffers_[slot].mBufferState.reset();
+        buffers_[slot].mRequestBufferCalled = false;
+        buffers_[slot].mBufferProducer = nullptr;
+        buffers_[slot].mFence = Fence::NO_FENCE;
+    }
+
+    auto status = queue_->FreeAllBuffers();
+    if (!status) {
+        ALOGE("BufferHubProducer::FreeAllBuffers: Failed to free all buffers on "
+              "the queue: %s",
+              status.GetErrorMessage().c_str());
+    }
+
+    if (queue_->capacity() != 0 || queue_->count() != 0) {
+        LOG_ALWAYS_FATAL("BufferHubProducer::FreeAllBuffers: Not all buffers are freed.");
+    }
+
+    return NO_ERROR;
+}
+
+status_t BufferHubProducer::exportToParcel(Parcel* parcel) {
+    status_t res = TakeAsParcelable(&pending_producer_parcelable_);
+    if (res != NO_ERROR) return res;
+
+    if (!pending_producer_parcelable_.IsValid()) {
+        ALOGE("BufferHubProducer::exportToParcel: Invalid parcelable object.");
+        return BAD_VALUE;
+    }
+
+    res = parcel->writeUint32(USE_BUFFER_HUB);
+    if (res != NO_ERROR) {
+        ALOGE("BufferHubProducer::exportToParcel: Cannot write magic, res=%d.", res);
+        return res;
+    }
+
+    return pending_producer_parcelable_.writeToParcel(parcel);
+}
+
+IBinder* BufferHubProducer::onAsBinder() {
+    ALOGE("BufferHubProducer::onAsBinder: BufferHubProducer should never be used as an Binder "
+          "object.");
+    return nullptr;
+}
+
+} // namespace android
diff --git a/libs/gui/BufferItem.cpp b/libs/gui/BufferItem.cpp
index 9da4ea8..f50379b 100644
--- a/libs/gui/BufferItem.cpp
+++ b/libs/gui/BufferItem.cpp
@@ -39,8 +39,8 @@
 }
 
 BufferItem::BufferItem() :
-    mGraphicBuffer(nullptr),
-    mFence(nullptr),
+    mGraphicBuffer(NULL),
+    mFence(NULL),
     mCrop(Rect::INVALID_RECT),
     mTransform(0),
     mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
@@ -55,7 +55,8 @@
     mSurfaceDamage(),
     mAutoRefresh(false),
     mQueuedBuffer(true),
-    mIsStale(false) {
+    mIsStale(false),
+    mApi(0) {
 }
 
 BufferItem::~BufferItem() {}
@@ -84,30 +85,32 @@
     addAligned(size, mAutoRefresh);
     addAligned(size, mQueuedBuffer);
     addAligned(size, mIsStale);
+    addAligned(size, mApi);
     return size;
 }
 
 size_t BufferItem::getFlattenedSize() const {
     size_t size = sizeof(uint32_t); // Flags
-    if (mGraphicBuffer != nullptr) {
+    if (mGraphicBuffer != 0) {
         size += mGraphicBuffer->getFlattenedSize();
         size = FlattenableUtils::align<4>(size);
     }
-    if (mFence != nullptr) {
+    if (mFence != 0) {
         size += mFence->getFlattenedSize();
         size = FlattenableUtils::align<4>(size);
     }
     size += mSurfaceDamage.getFlattenedSize();
+    size += mHdrMetadata.getFlattenedSize();
     size = FlattenableUtils::align<8>(size);
     return size + getPodSize();
 }
 
 size_t BufferItem::getFdCount() const {
     size_t count = 0;
-    if (mGraphicBuffer != nullptr) {
+    if (mGraphicBuffer != 0) {
         count += mGraphicBuffer->getFdCount();
     }
-    if (mFence != nullptr) {
+    if (mFence != 0) {
         count += mFence->getFdCount();
     }
     return count;
@@ -134,13 +137,13 @@
     FlattenableUtils::advance(buffer, size, sizeof(uint32_t));
 
     flags = 0;
-    if (mGraphicBuffer != nullptr) {
+    if (mGraphicBuffer != 0) {
         status_t err = mGraphicBuffer->flatten(buffer, size, fds, count);
         if (err) return err;
         size -= FlattenableUtils::align<4>(buffer);
         flags |= 1;
     }
-    if (mFence != nullptr) {
+    if (mFence != 0) {
         status_t err = mFence->flatten(buffer, size, fds, count);
         if (err) return err;
         size -= FlattenableUtils::align<4>(buffer);
@@ -151,6 +154,10 @@
     if (err) return err;
     FlattenableUtils::advance(buffer, size, mSurfaceDamage.getFlattenedSize());
 
+    err = mHdrMetadata.flatten(buffer, size);
+    if (err) return err;
+    FlattenableUtils::advance(buffer, size, mHdrMetadata.getFlattenedSize());
+
     // Check we still have enough space
     if (size < getPodSize()) {
         return NO_MEMORY;
@@ -172,6 +179,7 @@
     writeAligned(buffer, size, mAutoRefresh);
     writeAligned(buffer, size, mQueuedBuffer);
     writeAligned(buffer, size, mIsStale);
+    writeAligned(buffer, size, mApi);
 
     return NO_ERROR;
 }
@@ -212,6 +220,10 @@
     if (err) return err;
     FlattenableUtils::advance(buffer, size, mSurfaceDamage.getFlattenedSize());
 
+    err = mHdrMetadata.unflatten(buffer, size);
+    if (err) return err;
+    FlattenableUtils::advance(buffer, size, mHdrMetadata.getFlattenedSize());
+
     // Check we still have enough space
     if (size < getPodSize()) {
         return NO_MEMORY;
@@ -238,6 +250,7 @@
     readAligned(buffer, size, mAutoRefresh);
     readAligned(buffer, size, mQueuedBuffer);
     readAligned(buffer, size, mIsStale);
+    readAligned(buffer, size, mApi);
 
     return NO_ERROR;
 }
diff --git a/libs/gui/BufferItemConsumer.cpp b/libs/gui/BufferItemConsumer.cpp
index 3aa4e44..89bc0c4 100644
--- a/libs/gui/BufferItemConsumer.cpp
+++ b/libs/gui/BufferItemConsumer.cpp
@@ -49,16 +49,6 @@
 
 BufferItemConsumer::~BufferItemConsumer() {}
 
-void BufferItemConsumer::setName(const String8& name) {
-    Mutex::Autolock _l(mMutex);
-    if (mAbandoned) {
-        BI_LOGE("setName: BufferItemConsumer is abandoned!");
-        return;
-    }
-    mName = name;
-    mConsumer->setConsumerName(name);
-}
-
 void BufferItemConsumer::setBufferFreedListener(
         const wp<BufferFreedListener>& listener) {
     Mutex::Autolock _l(mMutex);
@@ -102,10 +92,13 @@
     Mutex::Autolock _l(mMutex);
 
     err = addReleaseFenceLocked(item.mSlot, item.mGraphicBuffer, releaseFence);
+    if (err != OK) {
+        BI_LOGE("Failed to addReleaseFenceLocked");
+    }
 
     err = releaseBufferLocked(item.mSlot, item.mGraphicBuffer, EGL_NO_DISPLAY,
             EGL_NO_SYNC_KHR);
-    if (err != OK) {
+    if (err != OK && err != IGraphicBufferConsumer::STALE_BUFFER_SLOT) {
         BI_LOGE("Failed to release buffer: %s (%d)",
                 strerror(-err), err);
     }
@@ -114,7 +107,7 @@
 
 void BufferItemConsumer::freeBufferLocked(int slotIndex) {
     sp<BufferFreedListener> listener = mBufferFreedListener.promote();
-    if (listener != nullptr && mSlots[slotIndex].mGraphicBuffer != nullptr) {
+    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);
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index 7da4db4..a8da134 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -18,6 +18,11 @@
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 //#define LOG_NDEBUG 0
 
+#ifndef NO_BUFFERHUB
+#include <gui/BufferHubConsumer.h>
+#include <gui/BufferHubProducer.h>
+#endif
+
 #include <gui/BufferQueue.h>
 #include <gui/BufferQueueConsumer.h>
 #include <gui/BufferQueueCore.h>
@@ -33,7 +38,7 @@
 
 void BufferQueue::ProxyConsumerListener::onDisconnect() {
     sp<ConsumerListener> listener(mConsumerListener.promote());
-    if (listener != nullptr) {
+    if (listener != NULL) {
         listener->onDisconnect();
     }
 }
@@ -41,7 +46,7 @@
 void BufferQueue::ProxyConsumerListener::onFrameAvailable(
         const BufferItem& item) {
     sp<ConsumerListener> listener(mConsumerListener.promote());
-    if (listener != nullptr) {
+    if (listener != NULL) {
         listener->onFrameAvailable(item);
     }
 }
@@ -49,21 +54,21 @@
 void BufferQueue::ProxyConsumerListener::onFrameReplaced(
         const BufferItem& item) {
     sp<ConsumerListener> listener(mConsumerListener.promote());
-    if (listener != nullptr) {
+    if (listener != NULL) {
         listener->onFrameReplaced(item);
     }
 }
 
 void BufferQueue::ProxyConsumerListener::onBuffersReleased() {
     sp<ConsumerListener> listener(mConsumerListener.promote());
-    if (listener != nullptr) {
+    if (listener != NULL) {
         listener->onBuffersReleased();
     }
 }
 
 void BufferQueue::ProxyConsumerListener::onSidebandStreamChanged() {
     sp<ConsumerListener> listener(mConsumerListener.promote());
-    if (listener != nullptr) {
+    if (listener != NULL) {
         listener->onSidebandStreamChanged();
     }
 }
@@ -80,25 +85,53 @@
 void BufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
         sp<IGraphicBufferConsumer>* outConsumer,
         bool consumerIsSurfaceFlinger) {
-    LOG_ALWAYS_FATAL_IF(outProducer == nullptr,
+    LOG_ALWAYS_FATAL_IF(outProducer == NULL,
             "BufferQueue: outProducer must not be NULL");
-    LOG_ALWAYS_FATAL_IF(outConsumer == nullptr,
+    LOG_ALWAYS_FATAL_IF(outConsumer == NULL,
             "BufferQueue: outConsumer must not be NULL");
 
     sp<BufferQueueCore> core(new BufferQueueCore());
-    LOG_ALWAYS_FATAL_IF(core == nullptr,
+    LOG_ALWAYS_FATAL_IF(core == NULL,
             "BufferQueue: failed to create BufferQueueCore");
 
     sp<IGraphicBufferProducer> producer(new BufferQueueProducer(core, consumerIsSurfaceFlinger));
-    LOG_ALWAYS_FATAL_IF(producer == nullptr,
+    LOG_ALWAYS_FATAL_IF(producer == NULL,
             "BufferQueue: failed to create BufferQueueProducer");
 
     sp<IGraphicBufferConsumer> consumer(new BufferQueueConsumer(core));
-    LOG_ALWAYS_FATAL_IF(consumer == nullptr,
+    LOG_ALWAYS_FATAL_IF(consumer == NULL,
             "BufferQueue: failed to create BufferQueueConsumer");
 
     *outProducer = producer;
     *outConsumer = consumer;
 }
 
+#ifndef NO_BUFFERHUB
+void BufferQueue::createBufferHubQueue(sp<IGraphicBufferProducer>* outProducer,
+                                       sp<IGraphicBufferConsumer>* outConsumer) {
+    LOG_ALWAYS_FATAL_IF(outProducer == NULL, "BufferQueue: outProducer must not be NULL");
+    LOG_ALWAYS_FATAL_IF(outConsumer == NULL, "BufferQueue: outConsumer must not be NULL");
+
+    sp<IGraphicBufferProducer> producer;
+    sp<IGraphicBufferConsumer> consumer;
+
+    dvr::ProducerQueueConfigBuilder configBuilder;
+    std::shared_ptr<dvr::ProducerQueue> producerQueue =
+            dvr::ProducerQueue::Create(configBuilder.Build(), dvr::UsagePolicy{});
+    LOG_ALWAYS_FATAL_IF(producerQueue == NULL, "BufferQueue: failed to create ProducerQueue.");
+
+    std::shared_ptr<dvr::ConsumerQueue> consumerQueue = producerQueue->CreateConsumerQueue();
+    LOG_ALWAYS_FATAL_IF(consumerQueue == NULL, "BufferQueue: failed to create ConsumerQueue.");
+
+    producer = BufferHubProducer::Create(producerQueue);
+    consumer = BufferHubConsumer::Create(consumerQueue);
+
+    LOG_ALWAYS_FATAL_IF(producer == NULL, "BufferQueue: failed to create BufferQueueProducer");
+    LOG_ALWAYS_FATAL_IF(consumer == NULL, "BufferQueue: failed to create BufferQueueConsumer");
+
+    *outProducer = producer;
+    *outConsumer = consumer;
+}
+#endif
+
 }; // namespace android
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index 31eb29b..d70e142 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -35,7 +35,9 @@
 #include <gui/IProducerListener.h>
 
 #include <binder/IPCThreadState.h>
+#ifndef __ANDROID_VNDK__
 #include <binder/PermissionCache.h>
+#endif
 
 #include <system/window.h>
 
@@ -253,7 +255,7 @@
         // mGraphicBuffer to NULL to avoid unnecessarily remapping this buffer
         // on the consumer side
         if (outBuffer->mAcquireCalled) {
-            outBuffer->mGraphicBuffer = nullptr;
+            outBuffer->mGraphicBuffer = NULL;
         }
 
         mCore->mQueue.erase(front);
@@ -270,7 +272,7 @@
         VALIDATE_CONSISTENCY();
     }
 
-    if (listener != nullptr) {
+    if (listener != NULL) {
         for (int i = 0; i < numDroppedBuffers; ++i) {
             listener->onBufferReleased();
         }
@@ -319,10 +321,10 @@
         const sp<android::GraphicBuffer>& buffer) {
     ATRACE_CALL();
 
-    if (outSlot == nullptr) {
+    if (outSlot == NULL) {
         BQ_LOGE("attachBuffer: outSlot must not be NULL");
         return BAD_VALUE;
-    } else if (buffer == nullptr) {
+    } else if (buffer == NULL) {
         BQ_LOGE("attachBuffer: cannot attach NULL buffer");
         return BAD_VALUE;
     }
@@ -411,7 +413,7 @@
     ATRACE_BUFFER_INDEX(slot);
 
     if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS ||
-            releaseFence == nullptr) {
+            releaseFence == NULL) {
         BQ_LOGE("releaseBuffer: slot %d out of range or fence %p NULL", slot,
                 releaseFence.get());
         return BAD_VALUE;
@@ -463,7 +465,7 @@
     } // Autolock scope
 
     // Call back without lock held
-    if (listener != nullptr) {
+    if (listener != NULL) {
         listener->onBufferReleased();
     }
 
@@ -474,7 +476,7 @@
         const sp<IConsumerListener>& consumerListener, bool controlledByApp) {
     ATRACE_CALL();
 
-    if (consumerListener == nullptr) {
+    if (consumerListener == NULL) {
         BQ_LOGE("connect: consumerListener may not be NULL");
         return BAD_VALUE;
     }
@@ -502,13 +504,13 @@
 
     Mutex::Autolock lock(mCore->mMutex);
 
-    if (mCore->mConsumerListener == nullptr) {
+    if (mCore->mConsumerListener == NULL) {
         BQ_LOGE("disconnect: no consumer is connected");
         return BAD_VALUE;
     }
 
     mCore->mIsAbandoned = true;
-    mCore->mConsumerListener = nullptr;
+    mCore->mConsumerListener = NULL;
     mCore->mQueue.clear();
     mCore->freeAllBuffersLocked();
     mCore->mSharedBufferSlot = BufferQueueCore::INVALID_BUFFER_SLOT;
@@ -519,7 +521,7 @@
 status_t BufferQueueConsumer::getReleasedBuffers(uint64_t *outSlotMask) {
     ATRACE_CALL();
 
-    if (outSlotMask == nullptr) {
+    if (outSlotMask == NULL) {
         BQ_LOGE("getReleasedBuffers: outSlotMask may not be NULL");
         return BAD_VALUE;
     }
@@ -671,7 +673,7 @@
         }
     }
     // Call back without lock held
-    if (listener != nullptr) {
+    if (listener != NULL) {
         listener->onBuffersReleased();
     }
 
@@ -757,14 +759,20 @@
     }
 
     const IPCThreadState* ipc = IPCThreadState::self();
-    const pid_t pid = ipc->getCallingPid();
     const uid_t uid = ipc->getCallingUid();
+#ifndef __ANDROID_VNDK__
+    // permission check can't be done for vendors as vendors have no access to
+    // the PermissionController
+    const pid_t pid = ipc->getCallingPid();
     if ((uid != shellUid) &&
         !PermissionCache::checkPermission(String16("android.permission.DUMP"), pid, uid)) {
         outResult->appendFormat("Permission Denial: can't dump BufferQueueConsumer "
                 "from pid=%d, uid=%d\n", pid, uid);
+#else
+    if (uid != shellUid) {
+#endif
         android_errorWriteWithInfoLog(0x534e4554, "27046057",
-                static_cast<int32_t>(uid), nullptr, 0);
+                static_cast<int32_t>(uid), NULL, 0);
         return PERMISSION_DENIED;
     }
 
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 0c7b7e2..c8021e4 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -166,7 +166,7 @@
     } // Autolock scope
 
     // Call back without lock held
-    if (listener != nullptr) {
+    if (listener != NULL) {
         listener->onBuffersReleased();
     }
 
@@ -221,7 +221,7 @@
     } // Autolock scope
 
     // Call back without lock held
-    if (listener != nullptr) {
+    if (listener != NULL) {
         listener->onBuffersReleased();
     }
     return NO_ERROR;
@@ -450,11 +450,11 @@
 
         mSlots[found].mBufferState.dequeue();
 
-        if ((buffer == nullptr) ||
+        if ((buffer == NULL) ||
                 buffer->needsReallocation(width, height, format, BQ_LAYER_COUNT, usage))
         {
             mSlots[found].mAcquireCalled = false;
-            mSlots[found].mGraphicBuffer = nullptr;
+            mSlots[found].mGraphicBuffer = NULL;
             mSlots[found].mRequestBufferCalled = false;
             mSlots[found].mEglDisplay = EGL_NO_DISPLAY;
             mSlots[found].mEglFence = EGL_NO_SYNC_KHR;
@@ -472,7 +472,7 @@
         BQ_LOGV("dequeueBuffer: setting buffer age to %" PRIu64,
                 mCore->mBufferAge);
 
-        if (CC_UNLIKELY(mSlots[found].mFence == nullptr)) {
+        if (CC_UNLIKELY(mSlots[found].mFence == NULL)) {
             BQ_LOGE("dequeueBuffer: about to return a NULL fence - "
                     "slot=%d w=%d h=%d format=%u",
                     found, buffer->width, buffer->height, buffer->format);
@@ -613,7 +613,7 @@
         listener = mCore->mConsumerListener;
     }
 
-    if (listener != nullptr) {
+    if (listener != NULL) {
         listener->onBuffersReleased();
     }
 
@@ -624,10 +624,10 @@
         sp<Fence>* outFence) {
     ATRACE_CALL();
 
-    if (outBuffer == nullptr) {
+    if (outBuffer == NULL) {
         BQ_LOGE("detachNextBuffer: outBuffer must not be NULL");
         return BAD_VALUE;
-    } else if (outFence == nullptr) {
+    } else if (outFence == NULL) {
         BQ_LOGE("detachNextBuffer: outFence must not be NULL");
         return BAD_VALUE;
     }
@@ -671,7 +671,7 @@
         listener = mCore->mConsumerListener;
     }
 
-    if (listener != nullptr) {
+    if (listener != NULL) {
         listener->onBuffersReleased();
     }
 
@@ -682,10 +682,10 @@
         const sp<android::GraphicBuffer>& buffer) {
     ATRACE_CALL();
 
-    if (outSlot == nullptr) {
+    if (outSlot == NULL) {
         BQ_LOGE("attachBuffer: outSlot must not be NULL");
         return BAD_VALUE;
-    } else if (buffer == nullptr) {
+    } else if (buffer == NULL) {
         BQ_LOGE("attachBuffer: cannot attach NULL buffer");
         return BAD_VALUE;
     }
@@ -765,8 +765,9 @@
             &crop, &scalingMode, &transform, &acquireFence, &stickyTransform,
             &getFrameTimestamps);
     const Region& surfaceDamage = input.getSurfaceDamage();
+    const HdrMetadata& hdrMetadata = input.getHdrMetadata();
 
-    if (acquireFence == nullptr) {
+    if (acquireFence == NULL) {
         BQ_LOGE("queueBuffer: fence is NULL");
         return BAD_VALUE;
     }
@@ -825,9 +826,9 @@
         }
 
         BQ_LOGV("queueBuffer: slot=%d/%" PRIu64 " time=%" PRIu64 " dataSpace=%d"
-                " crop=[%d,%d,%d,%d] transform=%#x scale=%s",
-                slot, mCore->mFrameCounter + 1, requestedPresentTimestamp,
-                dataSpace, crop.left, crop.top, crop.right, crop.bottom,
+                " validHdrMetadataTypes=0x%x crop=[%d,%d,%d,%d] transform=%#x scale=%s",
+                slot, mCore->mFrameCounter + 1, requestedPresentTimestamp, dataSpace,
+                hdrMetadata.validTypes, crop.left, crop.top, crop.right, crop.bottom,
                 transform,
                 BufferItem::scalingModeName(static_cast<uint32_t>(scalingMode)));
 
@@ -866,6 +867,7 @@
         item.mTimestamp = requestedPresentTimestamp;
         item.mIsAutoTimestamp = isAutoTimestamp;
         item.mDataSpace = dataSpace;
+        item.mHdrMetadata = hdrMetadata;
         item.mFrameNumber = currentFrameNumber;
         item.mSlot = slot;
         item.mFence = acquireFence;
@@ -876,6 +878,7 @@
         item.mSurfaceDamage = surfaceDamage;
         item.mQueuedBuffer = true;
         item.mAutoRefresh = mCore->mSharedBufferMode && mCore->mAutoRefresh;
+        item.mApi = mCore->mConnectedApi;
 
         mStickyTransform = stickyTransform;
 
@@ -970,9 +973,9 @@
             mCallbackCondition.wait(mCallbackMutex);
         }
 
-        if (frameAvailableListener != nullptr) {
+        if (frameAvailableListener != NULL) {
             frameAvailableListener->onFrameAvailable(item);
-        } else if (frameReplacedListener != nullptr) {
+        } else if (frameReplacedListener != NULL) {
             frameReplacedListener->onFrameReplaced(item);
         }
 
@@ -1037,7 +1040,7 @@
         BQ_LOGE("cancelBuffer: slot %d is not owned by the producer "
                 "(state = %s)", slot, mSlots[slot].mBufferState.string());
         return BAD_VALUE;
-    } else if (fence == nullptr) {
+    } else if (fence == NULL) {
         BQ_LOGE("cancelBuffer: fence is NULL");
         return BAD_VALUE;
     }
@@ -1067,7 +1070,7 @@
     ATRACE_CALL();
     Mutex::Autolock lock(mCore->mMutex);
 
-    if (outValue == nullptr) {
+    if (outValue == NULL) {
         BQ_LOGE("query: outValue was NULL");
         return BAD_VALUE;
     }
@@ -1118,6 +1121,9 @@
         case NATIVE_WINDOW_CONSUMER_IS_PROTECTED:
             value = static_cast<int32_t>(mCore->mConsumerIsProtected);
             break;
+        case NATIVE_WINDOW_MAX_BUFFER_COUNT:
+            value = static_cast<int32_t>(mCore->mMaxBufferCount);
+            break;
         default:
             return BAD_VALUE;
     }
@@ -1140,12 +1146,12 @@
         return NO_INIT;
     }
 
-    if (mCore->mConsumerListener == nullptr) {
+    if (mCore->mConsumerListener == NULL) {
         BQ_LOGE("connect: BufferQueue has no consumer");
         return NO_INIT;
     }
 
-    if (output == nullptr) {
+    if (output == NULL) {
         BQ_LOGE("connect: output was NULL");
         return BAD_VALUE;
     }
@@ -1183,10 +1189,10 @@
             output->nextFrameNumber = mCore->mFrameCounter + 1;
             output->bufferReplaced = false;
 
-            if (listener != nullptr) {
+            if (listener != NULL) {
                 // Set up a death notification so that we can disconnect
                 // automatically if the remote producer dies
-                if (IInterface::asBinder(listener)->remoteBinder() != nullptr) {
+                if (IInterface::asBinder(listener)->remoteBinder() != NULL) {
                     status = IInterface::asBinder(listener)->linkToDeath(
                             static_cast<IBinder::DeathRecipient*>(this));
                     if (status != NO_ERROR) {
@@ -1263,7 +1269,7 @@
                     mCore->freeAllBuffersLocked();
 
                     // Remove our death notification callback if we have one
-                    if (mCore->mLinkedToDeath != nullptr) {
+                    if (mCore->mLinkedToDeath != NULL) {
                         sp<IBinder> token =
                                 IInterface::asBinder(mCore->mLinkedToDeath);
                         // This can fail if we're here because of the death
@@ -1273,8 +1279,8 @@
                     }
                     mCore->mSharedBufferSlot =
                             BufferQueueCore::INVALID_BUFFER_SLOT;
-                    mCore->mLinkedToDeath = nullptr;
-                    mCore->mConnectedProducerListener = nullptr;
+                    mCore->mLinkedToDeath = NULL;
+                    mCore->mConnectedProducerListener = NULL;
                     mCore->mConnectedApi = BufferQueueCore::NO_CONNECTED_API;
                     mCore->mConnectedPid = -1;
                     mCore->mSidebandStream.clear();
@@ -1297,7 +1303,7 @@
     } // Autolock scope
 
     // Call back without lock held
-    if (listener != nullptr) {
+    if (listener != NULL) {
         listener->onBuffersReleased();
         listener->onDisconnect();
     }
@@ -1313,7 +1319,7 @@
         listener = mCore->mConsumerListener;
     } // Autolock scope
 
-    if (listener != nullptr) {
+    if (listener != NULL) {
         listener->onSidebandStreamChanged();
     }
     return NO_ERROR;
@@ -1328,6 +1334,7 @@
         uint32_t allocHeight = 0;
         PixelFormat allocFormat = PIXEL_FORMAT_UNKNOWN;
         uint64_t allocUsage = 0;
+        std::string allocName;
         { // Autolock scope
             Mutex::Autolock lock(mCore->mMutex);
             mCore->waitWhileAllocatingLocked();
@@ -1347,6 +1354,7 @@
             allocHeight = height > 0 ? height : mCore->mDefaultHeight;
             allocFormat = format != 0 ? format : mCore->mDefaultBufferFormat;
             allocUsage = usage | mCore->mConsumerUsageBits;
+            allocName.assign(mCore->mConsumerName.string(), mCore->mConsumerName.size());
 
             mCore->mIsAllocating = true;
         } // Autolock scope
@@ -1355,7 +1363,7 @@
         for (size_t i = 0; i <  newBufferCount; ++i) {
             sp<GraphicBuffer> graphicBuffer = new GraphicBuffer(
                     allocWidth, allocHeight, allocFormat, BQ_LAYER_COUNT,
-                    allocUsage, {mConsumerName.string(), mConsumerName.size()});
+                    allocUsage, allocName);
 
             status_t result = graphicBuffer->initCheck();
 
@@ -1527,7 +1535,7 @@
         Mutex::Autolock lock(mCore->mMutex);
         listener = mCore->mConsumerListener;
     }
-    if (listener != nullptr) {
+    if (listener != NULL) {
         listener->addAndGetFrameTimestamps(newTimestamps, outDelta);
     }
 }
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
index 2a9d742..f9e292e 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -96,7 +96,7 @@
 
 void ConsumerBase::freeBufferLocked(int slotIndex) {
     CB_LOGV("freeBufferLocked: slotIndex=%d", slotIndex);
-    mSlots[slotIndex].mGraphicBuffer = nullptr;
+    mSlots[slotIndex].mGraphicBuffer = 0;
     mSlots[slotIndex].mFence = Fence::NO_FENCE;
     mSlots[slotIndex].mFrameNumber = 0;
 }
@@ -110,7 +110,7 @@
         listener = mFrameAvailableListener.promote();
     }
 
-    if (listener != nullptr) {
+    if (listener != NULL) {
         CB_LOGV("actually calling onFrameAvailable");
         listener->onFrameAvailable(item);
     }
@@ -125,7 +125,7 @@
         listener = mFrameAvailableListener.promote();
     }
 
-    if (listener != nullptr) {
+    if (listener != NULL) {
         CB_LOGV("actually calling onFrameReplaced");
         listener->onFrameReplaced(item);
     }
@@ -182,6 +182,16 @@
     return mAbandoned;
 }
 
+void ConsumerBase::setName(const String8& name) {
+    Mutex::Autolock _l(mMutex);
+    if (mAbandoned) {
+        CB_LOGE("setName: ConsumerBase is abandoned!");
+        return;
+    }
+    mName = name;
+    mConsumer->setConsumerName(name);
+}
+
 void ConsumerBase::setFrameAvailableListener(
         const wp<FrameAvailableListener>& listener) {
     CB_LOGV("setFrameAvailableListener");
@@ -237,6 +247,50 @@
     return mConsumer->setDefaultBufferDataSpace(defaultDataSpace);
 }
 
+status_t ConsumerBase::setConsumerUsageBits(uint64_t usage) {
+    Mutex::Autolock lock(mMutex);
+    if (mAbandoned) {
+        CB_LOGE("setConsumerUsageBits: ConsumerBase is abandoned!");
+        return NO_INIT;
+    }
+    return mConsumer->setConsumerUsageBits(usage);
+}
+
+status_t ConsumerBase::setTransformHint(uint32_t hint) {
+    Mutex::Autolock lock(mMutex);
+    if (mAbandoned) {
+        CB_LOGE("setTransformHint: ConsumerBase is abandoned!");
+        return NO_INIT;
+    }
+    return mConsumer->setTransformHint(hint);
+}
+
+status_t ConsumerBase::setMaxAcquiredBufferCount(int maxAcquiredBuffers) {
+    Mutex::Autolock lock(mMutex);
+    if (mAbandoned) {
+        CB_LOGE("setMaxAcquiredBufferCount: ConsumerBase is abandoned!");
+        return NO_INIT;
+    }
+    return mConsumer->setMaxAcquiredBufferCount(maxAcquiredBuffers);
+}
+
+sp<NativeHandle> ConsumerBase::getSidebandStream() const {
+    Mutex::Autolock _l(mMutex);
+    if (mAbandoned) {
+        CB_LOGE("getSidebandStream: ConsumerBase is abandoned!");
+        return nullptr;
+    }
+
+    sp<NativeHandle> stream;
+    status_t err = mConsumer->getSidebandStream(&stream);
+    if (err != NO_ERROR) {
+        CB_LOGE("failed to get sideband stream: %d", err);
+        return nullptr;
+    }
+
+    return stream;
+}
+
 status_t ConsumerBase::getOccupancyHistory(bool forceFlush,
         std::vector<OccupancyTracker::Segment>* outHistory) {
     Mutex::Autolock _l(mMutex);
@@ -298,8 +352,8 @@
         return err;
     }
 
-    if (item->mGraphicBuffer != nullptr) {
-        if (mSlots[item->mSlot].mGraphicBuffer != nullptr) {
+    if (item->mGraphicBuffer != NULL) {
+        if (mSlots[item->mSlot].mGraphicBuffer != NULL) {
             freeBufferLocked(item->mSlot);
         }
         mSlots[item->mSlot].mGraphicBuffer = item->mGraphicBuffer;
@@ -414,7 +468,7 @@
     if (slot < 0 || slot >= BufferQueue::NUM_BUFFER_SLOTS) {
         return false;
     }
-    return (mSlots[slot].mGraphicBuffer != nullptr &&
+    return (mSlots[slot].mGraphicBuffer != NULL &&
             mSlots[slot].mGraphicBuffer->handle == graphicBuffer->handle);
 }
 
diff --git a/libs/gui/CpuConsumer.cpp b/libs/gui/CpuConsumer.cpp
index 9f09e0c..8edf604 100644
--- a/libs/gui/CpuConsumer.cpp
+++ b/libs/gui/CpuConsumer.cpp
@@ -18,11 +18,11 @@
 #define LOG_TAG "CpuConsumer"
 //#define ATRACE_TAG ATRACE_TAG_GRAPHICS
 
-#include <cutils/compiler.h>
-#include <utils/Log.h>
-#include <gui/BufferItem.h>
 #include <gui/CpuConsumer.h>
 
+#include <gui/BufferItem.h>
+#include <utils/Log.h>
+
 #define CC_LOGV(x, ...) ALOGV("[%s] " x, mName.string(), ##__VA_ARGS__)
 //#define CC_LOGD(x, ...) ALOGD("[%s] " x, mName.string(), ##__VA_ARGS__)
 //#define CC_LOGI(x, ...) ALOGI("[%s] " x, mName.string(), ##__VA_ARGS__)
@@ -44,20 +44,19 @@
     mConsumer->setMaxAcquiredBufferCount(static_cast<int32_t>(maxLockedBuffers));
 }
 
-CpuConsumer::~CpuConsumer() {
-    // ConsumerBase destructor does all the work.
+size_t CpuConsumer::findAcquiredBufferLocked(uintptr_t id) const {
+    for (size_t i = 0; i < mMaxLockedBuffers; i++) {
+        const auto& ab = mAcquiredBuffers[i];
+        // note that this finds AcquiredBuffer::kUnusedId as well
+        if (ab.mLockedBufferId == id) {
+            return i;
+        }
+    }
+    return mMaxLockedBuffers; // an invalid index
 }
 
-
-
-void CpuConsumer::setName(const String8& name) {
-    Mutex::Autolock _l(mMutex);
-    if (mAbandoned) {
-        CC_LOGE("setName: CpuConsumer is abandoned!");
-        return;
-    }
-    mName = name;
-    mConsumer->setConsumerName(name);
+static uintptr_t getLockedBufferId(const CpuConsumer::LockedBuffer& buffer) {
+    return reinterpret_cast<uintptr_t>(buffer.data);
 }
 
 static bool isPossiblyYUV(PixelFormat format) {
@@ -88,10 +87,74 @@
     }
 }
 
+status_t CpuConsumer::lockBufferItem(const BufferItem& item, LockedBuffer* outBuffer) const {
+    android_ycbcr ycbcr = android_ycbcr();
+
+    PixelFormat format = item.mGraphicBuffer->getPixelFormat();
+    PixelFormat flexFormat = format;
+    if (isPossiblyYUV(format)) {
+        int fenceFd = item.mFence.get() ? item.mFence->dup() : -1;
+        status_t err = item.mGraphicBuffer->lockAsyncYCbCr(GraphicBuffer::USAGE_SW_READ_OFTEN,
+                                                           item.mCrop, &ycbcr, fenceFd);
+        if (err == OK) {
+            flexFormat = HAL_PIXEL_FORMAT_YCbCr_420_888;
+            if (format != HAL_PIXEL_FORMAT_YCbCr_420_888) {
+                CC_LOGV("locking buffer of format %#x as flex YUV", format);
+            }
+        } else if (format == HAL_PIXEL_FORMAT_YCbCr_420_888) {
+            CC_LOGE("Unable to lock YCbCr buffer for CPU reading: %s (%d)", strerror(-err), err);
+            return err;
+        }
+    }
+
+    if (ycbcr.y != nullptr) {
+        outBuffer->data = reinterpret_cast<uint8_t*>(ycbcr.y);
+        outBuffer->stride = static_cast<uint32_t>(ycbcr.ystride);
+        outBuffer->dataCb = reinterpret_cast<uint8_t*>(ycbcr.cb);
+        outBuffer->dataCr = reinterpret_cast<uint8_t*>(ycbcr.cr);
+        outBuffer->chromaStride = static_cast<uint32_t>(ycbcr.cstride);
+        outBuffer->chromaStep = static_cast<uint32_t>(ycbcr.chroma_step);
+    } else {
+        // not flexible YUV; try lockAsync
+        void* bufferPointer = nullptr;
+        int fenceFd = item.mFence.get() ? item.mFence->dup() : -1;
+        status_t err = item.mGraphicBuffer->lockAsync(GraphicBuffer::USAGE_SW_READ_OFTEN,
+                                                      item.mCrop, &bufferPointer, fenceFd);
+        if (err != OK) {
+            CC_LOGE("Unable to lock buffer for CPU reading: %s (%d)", strerror(-err), err);
+            return err;
+        }
+
+        outBuffer->data = reinterpret_cast<uint8_t*>(bufferPointer);
+        outBuffer->stride = item.mGraphicBuffer->getStride();
+        outBuffer->dataCb = nullptr;
+        outBuffer->dataCr = nullptr;
+        outBuffer->chromaStride = 0;
+        outBuffer->chromaStep = 0;
+    }
+
+    outBuffer->width = item.mGraphicBuffer->getWidth();
+    outBuffer->height = item.mGraphicBuffer->getHeight();
+    outBuffer->format = format;
+    outBuffer->flexFormat = flexFormat;
+
+    outBuffer->crop = item.mCrop;
+    outBuffer->transform = item.mTransform;
+    outBuffer->scalingMode = item.mScalingMode;
+    outBuffer->timestamp = item.mTimestamp;
+    outBuffer->dataSpace = item.mDataSpace;
+    outBuffer->frameNumber = item.mFrameNumber;
+
+    return OK;
+}
+
 status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) {
     status_t err;
 
     if (!nativeBuffer) return BAD_VALUE;
+
+    Mutex::Autolock _l(mMutex);
+
     if (mCurrentLockedBuffers == mMaxLockedBuffers) {
         CC_LOGW("Max buffers have been locked (%zd), cannot lock anymore.",
                 mMaxLockedBuffers);
@@ -99,9 +162,6 @@
     }
 
     BufferItem b;
-
-    Mutex::Autolock _l(mMutex);
-
     err = acquireBufferLocked(&b, 0);
     if (err != OK) {
         if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
@@ -112,94 +172,23 @@
         }
     }
 
-    int slot = b.mSlot;
-
-    void *bufferPointer = nullptr;
-    android_ycbcr ycbcr = android_ycbcr();
-
-    PixelFormat format = mSlots[slot].mGraphicBuffer->getPixelFormat();
-    PixelFormat flexFormat = format;
-    if (isPossiblyYUV(format)) {
-        if (b.mFence.get()) {
-            err = mSlots[slot].mGraphicBuffer->lockAsyncYCbCr(
-                GraphicBuffer::USAGE_SW_READ_OFTEN,
-                b.mCrop,
-                &ycbcr,
-                b.mFence->dup());
-        } else {
-            err = mSlots[slot].mGraphicBuffer->lockYCbCr(
-                GraphicBuffer::USAGE_SW_READ_OFTEN,
-                b.mCrop,
-                &ycbcr);
-        }
-        if (err == OK) {
-            bufferPointer = ycbcr.y;
-            flexFormat = HAL_PIXEL_FORMAT_YCbCr_420_888;
-            if (format != HAL_PIXEL_FORMAT_YCbCr_420_888) {
-                CC_LOGV("locking buffer of format %#x as flex YUV", format);
-            }
-        } else if (format == HAL_PIXEL_FORMAT_YCbCr_420_888) {
-            CC_LOGE("Unable to lock YCbCr buffer for CPU reading: %s (%d)",
-                    strerror(-err), err);
-            return err;
-        }
+    if (b.mGraphicBuffer == nullptr) {
+        b.mGraphicBuffer = mSlots[b.mSlot].mGraphicBuffer;
     }
 
-    if (bufferPointer == nullptr) { // not flexible YUV
-        if (b.mFence.get()) {
-            err = mSlots[slot].mGraphicBuffer->lockAsync(
-                GraphicBuffer::USAGE_SW_READ_OFTEN,
-                b.mCrop,
-                &bufferPointer,
-                b.mFence->dup());
-        } else {
-            err = mSlots[slot].mGraphicBuffer->lock(
-                GraphicBuffer::USAGE_SW_READ_OFTEN,
-                b.mCrop,
-                &bufferPointer);
-        }
-        if (err != OK) {
-            CC_LOGE("Unable to lock buffer for CPU reading: %s (%d)",
-                    strerror(-err), err);
-            return err;
-        }
+    err = lockBufferItem(b, nativeBuffer);
+    if (err != OK) {
+        return err;
     }
 
-    size_t lockedIdx = 0;
-    for (; lockedIdx < static_cast<size_t>(mMaxLockedBuffers); lockedIdx++) {
-        if (mAcquiredBuffers[lockedIdx].mSlot ==
-                BufferQueue::INVALID_BUFFER_SLOT) {
-            break;
-        }
-    }
-    assert(lockedIdx < mMaxLockedBuffers);
+    // find an unused AcquiredBuffer
+    size_t lockedIdx = findAcquiredBufferLocked(AcquiredBuffer::kUnusedId);
+    ALOG_ASSERT(lockedIdx < mMaxLockedBuffers);
+    AcquiredBuffer& ab = mAcquiredBuffers.editItemAt(lockedIdx);
 
-    AcquiredBuffer &ab = mAcquiredBuffers.editItemAt(lockedIdx);
-    ab.mSlot = slot;
-    ab.mBufferPointer = bufferPointer;
-    ab.mGraphicBuffer = mSlots[slot].mGraphicBuffer;
-
-    nativeBuffer->data   =
-            reinterpret_cast<uint8_t*>(bufferPointer);
-    nativeBuffer->width  = mSlots[slot].mGraphicBuffer->getWidth();
-    nativeBuffer->height = mSlots[slot].mGraphicBuffer->getHeight();
-    nativeBuffer->format = format;
-    nativeBuffer->flexFormat = flexFormat;
-    nativeBuffer->stride = (ycbcr.y != nullptr) ?
-            static_cast<uint32_t>(ycbcr.ystride) :
-            mSlots[slot].mGraphicBuffer->getStride();
-
-    nativeBuffer->crop        = b.mCrop;
-    nativeBuffer->transform   = b.mTransform;
-    nativeBuffer->scalingMode = b.mScalingMode;
-    nativeBuffer->timestamp   = b.mTimestamp;
-    nativeBuffer->dataSpace   = b.mDataSpace;
-    nativeBuffer->frameNumber = b.mFrameNumber;
-
-    nativeBuffer->dataCb       = reinterpret_cast<uint8_t*>(ycbcr.cb);
-    nativeBuffer->dataCr       = reinterpret_cast<uint8_t*>(ycbcr.cr);
-    nativeBuffer->chromaStride = static_cast<uint32_t>(ycbcr.cstride);
-    nativeBuffer->chromaStep   = static_cast<uint32_t>(ycbcr.chroma_step);
+    ab.mSlot = b.mSlot;
+    ab.mGraphicBuffer = b.mGraphicBuffer;
+    ab.mLockedBufferId = getLockedBufferId(*nativeBuffer);
 
     mCurrentLockedBuffers++;
 
@@ -208,60 +197,34 @@
 
 status_t CpuConsumer::unlockBuffer(const LockedBuffer &nativeBuffer) {
     Mutex::Autolock _l(mMutex);
-    size_t lockedIdx = 0;
 
-    void *bufPtr = reinterpret_cast<void *>(nativeBuffer.data);
-    for (; lockedIdx < static_cast<size_t>(mMaxLockedBuffers); lockedIdx++) {
-        if (bufPtr == mAcquiredBuffers[lockedIdx].mBufferPointer) break;
-    }
+    uintptr_t id = getLockedBufferId(nativeBuffer);
+    size_t lockedIdx =
+        (id != AcquiredBuffer::kUnusedId) ? findAcquiredBufferLocked(id) : mMaxLockedBuffers;
     if (lockedIdx == mMaxLockedBuffers) {
         CC_LOGE("%s: Can't find buffer to free", __FUNCTION__);
         return BAD_VALUE;
     }
 
-    return releaseAcquiredBufferLocked(lockedIdx);
-}
+    AcquiredBuffer& ab = mAcquiredBuffers.editItemAt(lockedIdx);
 
-status_t CpuConsumer::releaseAcquiredBufferLocked(size_t lockedIdx) {
-    status_t err;
-    int fd = -1;
-
-    err = mAcquiredBuffers[lockedIdx].mGraphicBuffer->unlockAsync(&fd);
+    int fenceFd = -1;
+    status_t err = ab.mGraphicBuffer->unlockAsync(&fenceFd);
     if (err != OK) {
         CC_LOGE("%s: Unable to unlock graphic buffer %zd", __FUNCTION__,
                 lockedIdx);
         return err;
     }
-    int buf = mAcquiredBuffers[lockedIdx].mSlot;
-    if (CC_LIKELY(fd != -1)) {
-        sp<Fence> fence(new Fence(fd));
-        addReleaseFenceLocked(
-            mAcquiredBuffers[lockedIdx].mSlot,
-            mSlots[buf].mGraphicBuffer,
-            fence);
-    }
 
-    // release the buffer if it hasn't already been freed by the BufferQueue.
-    // This can happen, for example, when the producer of this buffer
-    // disconnected after this buffer was acquired.
-    if (CC_LIKELY(mAcquiredBuffers[lockedIdx].mGraphicBuffer ==
-            mSlots[buf].mGraphicBuffer)) {
-        releaseBufferLocked(
-                buf, mAcquiredBuffers[lockedIdx].mGraphicBuffer,
-                EGL_NO_DISPLAY, EGL_NO_SYNC_KHR);
-    }
+    sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE);
+    addReleaseFenceLocked(ab.mSlot, ab.mGraphicBuffer, fence);
+    releaseBufferLocked(ab.mSlot, ab.mGraphicBuffer);
 
-    AcquiredBuffer &ab = mAcquiredBuffers.editItemAt(lockedIdx);
-    ab.mSlot = BufferQueue::INVALID_BUFFER_SLOT;
-    ab.mBufferPointer = nullptr;
-    ab.mGraphicBuffer.clear();
+    ab.reset();
 
     mCurrentLockedBuffers--;
-    return OK;
-}
 
-void CpuConsumer::freeBufferLocked(int slotIndex) {
-    ConsumerBase::freeBufferLocked(slotIndex);
+    return OK;
 }
 
 } // namespace android
diff --git a/libs/gui/DisplayEventReceiver.cpp b/libs/gui/DisplayEventReceiver.cpp
index f5cf1c4..1757ec1 100644
--- a/libs/gui/DisplayEventReceiver.cpp
+++ b/libs/gui/DisplayEventReceiver.cpp
@@ -34,9 +34,9 @@
 
 DisplayEventReceiver::DisplayEventReceiver(ISurfaceComposer::VsyncSource vsyncSource) {
     sp<ISurfaceComposer> sf(ComposerService::getComposerService());
-    if (sf != nullptr) {
+    if (sf != NULL) {
         mEventConnection = sf->createDisplayEventConnection(vsyncSource);
-        if (mEventConnection != nullptr) {
+        if (mEventConnection != NULL) {
             mDataChannel = std::make_unique<gui::BitTube>();
             mEventConnection->stealReceiveChannel(mDataChannel.get());
         }
@@ -47,13 +47,13 @@
 }
 
 status_t DisplayEventReceiver::initCheck() const {
-    if (mDataChannel != nullptr)
+    if (mDataChannel != NULL)
         return NO_ERROR;
     return NO_INIT;
 }
 
 int DisplayEventReceiver::getFd() const {
-    if (mDataChannel == nullptr)
+    if (mDataChannel == NULL)
         return NO_INIT;
 
     return mDataChannel->getFd();
@@ -63,7 +63,7 @@
     if (int32_t(count) < 0)
         return BAD_VALUE;
 
-    if (mEventConnection != nullptr) {
+    if (mEventConnection != NULL) {
         mEventConnection->setVsyncRate(count);
         return NO_ERROR;
     }
@@ -71,7 +71,7 @@
 }
 
 status_t DisplayEventReceiver::requestNextVsync() {
-    if (mEventConnection != nullptr) {
+    if (mEventConnection != NULL) {
         mEventConnection->requestNextVsync();
         return NO_ERROR;
     }
diff --git a/libs/gui/FrameTimestamps.cpp b/libs/gui/FrameTimestamps.cpp
index fccca97..a379ad6 100644
--- a/libs/gui/FrameTimestamps.cpp
+++ b/libs/gui/FrameTimestamps.cpp
@@ -628,7 +628,6 @@
         ALOGE("FrameEventHistoryDelta assign clobbering history.");
     }
     mDeltas = std::move(src.mDeltas);
-    ALOGE_IF(src.mDeltas.empty(), "Source mDeltas not empty.");
     return *this;
 }
 
diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp
index 59e78cc..885efec 100644
--- a/libs/gui/GLConsumer.cpp
+++ b/libs/gui/GLConsumer.cpp
@@ -31,6 +31,8 @@
 
 #include <hardware/hardware.h>
 
+#include <math/mat4.h>
+
 #include <gui/BufferItem.h>
 #include <gui/GLConsumer.h>
 #include <gui/ISurfaceComposer.h>
@@ -75,33 +77,7 @@
     "_______________"
 };
 
-// Transform matrices
-static float mtxIdentity[16] = {
-    1, 0, 0, 0,
-    0, 1, 0, 0,
-    0, 0, 1, 0,
-    0, 0, 0, 1,
-};
-static float mtxFlipH[16] = {
-    -1, 0, 0, 0,
-    0, 1, 0, 0,
-    0, 0, 1, 0,
-    1, 0, 0, 1,
-};
-static float mtxFlipV[16] = {
-    1, 0, 0, 0,
-    0, -1, 0, 0,
-    0, 0, 1, 0,
-    0, 1, 0, 1,
-};
-static float mtxRot90[16] = {
-    0, 1, 0, 0,
-    -1, 0, 0, 0,
-    0, 0, 1, 0,
-    1, 0, 0, 1,
-};
-
-static void mtxMul(float out[16], const float a[16], const float b[16]);
+static const mat4 mtxIdentity;
 
 Mutex GLConsumer::sStaticInitLock;
 sp<GraphicBuffer> GLConsumer::sReleasedTexImageBuffer;
@@ -173,7 +149,7 @@
 {
     GLC_LOGV("GLConsumer");
 
-    memcpy(mCurrentTransformMatrix, mtxIdentity,
+    memcpy(mCurrentTransformMatrix, mtxIdentity.asArray(),
             sizeof(mCurrentTransformMatrix));
 
     mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS);
@@ -202,7 +178,7 @@
 {
     GLC_LOGV("GLConsumer");
 
-    memcpy(mCurrentTransformMatrix, mtxIdentity,
+    memcpy(mCurrentTransformMatrix, mtxIdentity.asArray(),
             sizeof(mCurrentTransformMatrix));
 
     mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS);
@@ -315,7 +291,7 @@
             return err;
         }
 
-        if (mReleasedTexImage == nullptr) {
+        if (mReleasedTexImage == NULL) {
             mReleasedTexImage = new EglImage(getDebugTexImageBuffer());
         }
 
@@ -345,7 +321,7 @@
 
 sp<GraphicBuffer> GLConsumer::getDebugTexImageBuffer() {
     Mutex::Autolock _l(sStaticInitLock);
-    if (CC_UNLIKELY(sReleasedTexImageBuffer == nullptr)) {
+    if (CC_UNLIKELY(sReleasedTexImageBuffer == NULL)) {
         // The first time, create the debug texture in case the application
         // continues to use it.
         sp<GraphicBuffer> buffer = new GraphicBuffer(
@@ -381,7 +357,7 @@
     // If item->mGraphicBuffer is not null, this buffer has not been acquired
     // before, so any prior EglImage created is using a stale buffer. This
     // replaces any old EglImage with a new one (using the new buffer).
-    if (item->mGraphicBuffer != nullptr) {
+    if (item->mGraphicBuffer != NULL) {
         int slot = item->mSlot;
         mEglSlots[slot].mEglImage = new EglImage(item->mGraphicBuffer);
     }
@@ -455,7 +431,7 @@
 
     GLC_LOGV("updateAndRelease: (slot=%d buf=%p) -> (slot=%d buf=%p)",
             mCurrentTexture, mCurrentTextureImage != NULL ?
-                    mCurrentTextureImage->graphicBufferHandle() : nullptr,
+                    mCurrentTextureImage->graphicBufferHandle() : 0,
             slot, mSlots[slot].mGraphicBuffer->handle);
 
     // Hang onto the pointer so that it isn't freed in the call to
@@ -515,7 +491,7 @@
 
     glBindTexture(mTexTarget, mTexName);
     if (mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT &&
-            mCurrentTextureImage == nullptr) {
+            mCurrentTextureImage == NULL) {
         GLC_LOGE("bindTextureImage: no currently-bound texture");
         return NO_INIT;
     }
@@ -679,7 +655,7 @@
     mTexName = tex;
     mAttached = true;
 
-    if (mCurrentTextureImage != nullptr) {
+    if (mCurrentTextureImage != NULL) {
         // This may wait for a buffer a second time. This is likely required if
         // this is a different context, since otherwise the wait could be skipped
         // by bouncing through another context. For the same context the extra
@@ -700,7 +676,7 @@
     if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
         if (SyncFeatures::getInstance().useNativeFenceSync()) {
             EGLSyncKHR sync = eglCreateSyncKHR(dpy,
-                    EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr);
+                    EGL_SYNC_NATIVE_FENCE_ANDROID, NULL);
             if (sync == EGL_NO_SYNC_KHR) {
                 GLC_LOGE("syncForReleaseLocked: error creating EGL fence: %#x",
                         eglGetError());
@@ -744,7 +720,7 @@
 
             // Create a fence for the outstanding accesses in the current
             // OpenGL ES context.
-            fence = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, nullptr);
+            fence = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, NULL);
             if (fence == EGL_NO_SYNC_KHR) {
                 GLC_LOGE("syncForReleaseLocked: error creating fence: %#x",
                         eglGetError());
@@ -758,25 +734,6 @@
     return OK;
 }
 
-bool GLConsumer::isExternalFormat(PixelFormat format)
-{
-    switch (format) {
-    // supported YUV formats
-    case HAL_PIXEL_FORMAT_YV12:
-    // Legacy/deprecated YUV formats
-    case HAL_PIXEL_FORMAT_YCbCr_422_SP:
-    case HAL_PIXEL_FORMAT_YCrCb_420_SP:
-    case HAL_PIXEL_FORMAT_YCbCr_422_I:
-        return true;
-    }
-
-    // Any OEM format needs to be considered
-    if (format>=0x100 && format<=0x1FF)
-        return true;
-
-    return false;
-}
-
 uint32_t GLConsumer::getCurrentTextureTarget() const {
     return mTexTarget;
 }
@@ -795,11 +752,11 @@
     bool needsRecompute = mFilteringEnabled != enabled;
     mFilteringEnabled = enabled;
 
-    if (needsRecompute && mCurrentTextureImage==nullptr) {
+    if (needsRecompute && mCurrentTextureImage==NULL) {
         GLC_LOGD("setFilteringEnabled called with mCurrentTextureImage == NULL");
     }
 
-    if (needsRecompute && mCurrentTextureImage != nullptr) {
+    if (needsRecompute && mCurrentTextureImage != NULL) {
         computeCurrentTransformMatrixLocked();
     }
 }
@@ -820,34 +777,37 @@
 void GLConsumer::computeTransformMatrix(float outTransform[16],
         const sp<GraphicBuffer>& buf, const Rect& cropRect, uint32_t transform,
         bool filtering) {
+    // Transform matrices
+    static const mat4 mtxFlipH(
+        -1, 0, 0, 0,
+        0, 1, 0, 0,
+        0, 0, 1, 0,
+        1, 0, 0, 1
+    );
+    static const mat4 mtxFlipV(
+        1, 0, 0, 0,
+        0, -1, 0, 0,
+        0, 0, 1, 0,
+        0, 1, 0, 1
+    );
+    static const mat4 mtxRot90(
+        0, 1, 0, 0,
+        -1, 0, 0, 0,
+        0, 0, 1, 0,
+        1, 0, 0, 1
+    );
 
-    float xform[16];
-    for (int i = 0; i < 16; i++) {
-        xform[i] = mtxIdentity[i];
-    }
+    mat4 xform;
     if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H) {
-        float result[16];
-        mtxMul(result, xform, mtxFlipH);
-        for (int i = 0; i < 16; i++) {
-            xform[i] = result[i];
-        }
+        xform *= mtxFlipH;
     }
     if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V) {
-        float result[16];
-        mtxMul(result, xform, mtxFlipV);
-        for (int i = 0; i < 16; i++) {
-            xform[i] = result[i];
-        }
+        xform *= mtxFlipV;
     }
     if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
-        float result[16];
-        mtxMul(result, xform, mtxRot90);
-        for (int i = 0; i < 16; i++) {
-            xform[i] = result[i];
-        }
+        xform *= mtxRot90;
     }
 
-    float mtxBeforeFlipV[16];
     if (!cropRect.isEmpty()) {
         float tx = 0.0f, ty = 0.0f, sx = 1.0f, sy = 1.0f;
         float bufferWidth = buf->getWidth();
@@ -893,25 +853,63 @@
             sy = (float(cropRect.height()) - (2.0f * shrinkAmount)) /
                     bufferHeight;
         }
-        float crop[16] = {
+
+        mat4 crop(
             sx, 0, 0, 0,
             0, sy, 0, 0,
             0, 0, 1, 0,
-            tx, ty, 0, 1,
-        };
-
-        mtxMul(mtxBeforeFlipV, crop, xform);
-    } else {
-        for (int i = 0; i < 16; i++) {
-            mtxBeforeFlipV[i] = xform[i];
-        }
+            tx, ty, 0, 1
+        );
+        xform = crop * xform;
     }
 
     // SurfaceFlinger expects the top of its window textures to be at a Y
     // coordinate of 0, so GLConsumer must behave the same way.  We don't
     // want to expose this to applications, however, so we must add an
     // additional vertical flip to the transform after all the other transforms.
-    mtxMul(outTransform, mtxFlipV, mtxBeforeFlipV);
+    xform = mtxFlipV * xform;
+
+    memcpy(outTransform, xform.asArray(), sizeof(xform));
+}
+
+Rect GLConsumer::scaleDownCrop(const Rect& crop, uint32_t bufferWidth, uint32_t bufferHeight) {
+    Rect outCrop = crop;
+
+    uint32_t newWidth = static_cast<uint32_t>(crop.width());
+    uint32_t newHeight = static_cast<uint32_t>(crop.height());
+
+    if (newWidth * bufferHeight > newHeight * bufferWidth) {
+        newWidth = newHeight * bufferWidth / bufferHeight;
+        ALOGV("too wide: newWidth = %d", newWidth);
+    } else if (newWidth * bufferHeight < newHeight * bufferWidth) {
+        newHeight = newWidth * bufferHeight / bufferWidth;
+        ALOGV("too tall: newHeight = %d", newHeight);
+    }
+
+    uint32_t currentWidth = static_cast<uint32_t>(crop.width());
+    uint32_t currentHeight = static_cast<uint32_t>(crop.height());
+
+    // The crop is too wide
+    if (newWidth < currentWidth) {
+        uint32_t dw = currentWidth - newWidth;
+        auto halfdw = dw / 2;
+        outCrop.left += halfdw;
+        // Not halfdw because it would subtract 1 too few when dw is odd
+        outCrop.right -= (dw - halfdw);
+        // The crop is too tall
+    } else if (newHeight < currentHeight) {
+        uint32_t dh = currentHeight - newHeight;
+        auto halfdh = dh / 2;
+        outCrop.top += halfdh;
+        // Not halfdh because it would subtract 1 too few when dh is odd
+        outCrop.bottom -= (dh - halfdh);
+    }
+
+    ALOGV("getCurrentCrop final crop [%d,%d,%d,%d]",
+            outCrop.left, outCrop.top,
+            outCrop.right,outCrop.bottom);
+
+    return outCrop;
 }
 
 nsecs_t GLConsumer::getTimestamp() {
@@ -940,50 +938,14 @@
     }
 
     return (mCurrentTextureImage == nullptr) ?
-            nullptr : mCurrentTextureImage->graphicBuffer();
+            NULL : mCurrentTextureImage->graphicBuffer();
 }
 
 Rect GLConsumer::getCurrentCrop() const {
     Mutex::Autolock lock(mMutex);
-
-    Rect outCrop = mCurrentCrop;
-    if (mCurrentScalingMode == NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) {
-        uint32_t newWidth = static_cast<uint32_t>(mCurrentCrop.width());
-        uint32_t newHeight = static_cast<uint32_t>(mCurrentCrop.height());
-
-        if (newWidth * mDefaultHeight > newHeight * mDefaultWidth) {
-            newWidth = newHeight * mDefaultWidth / mDefaultHeight;
-            GLC_LOGV("too wide: newWidth = %d", newWidth);
-        } else if (newWidth * mDefaultHeight < newHeight * mDefaultWidth) {
-            newHeight = newWidth * mDefaultHeight / mDefaultWidth;
-            GLC_LOGV("too tall: newHeight = %d", newHeight);
-        }
-
-        uint32_t currentWidth = static_cast<uint32_t>(mCurrentCrop.width());
-        uint32_t currentHeight = static_cast<uint32_t>(mCurrentCrop.height());
-
-        // The crop is too wide
-        if (newWidth < currentWidth) {
-            uint32_t dw = currentWidth - newWidth;
-            auto halfdw = dw / 2;
-            outCrop.left += halfdw;
-            // Not halfdw because it would subtract 1 too few when dw is odd
-            outCrop.right -= (dw - halfdw);
-        // The crop is too tall
-        } else if (newHeight < currentHeight) {
-            uint32_t dh = currentHeight - newHeight;
-            auto halfdh = dh / 2;
-            outCrop.top += halfdh;
-            // Not halfdh because it would subtract 1 too few when dh is odd
-            outCrop.bottom -= (dh - halfdh);
-        }
-
-        GLC_LOGV("getCurrentCrop final crop [%d,%d,%d,%d]",
-            outCrop.left, outCrop.top,
-            outCrop.right,outCrop.bottom);
-    }
-
-    return outCrop;
+    return (mCurrentScalingMode == NATIVE_WINDOW_SCALING_MODE_SCALE_CROP)
+        ? scaleDownCrop(mCurrentCrop, mDefaultWidth, mDefaultHeight)
+        : mCurrentCrop;
 }
 
 uint32_t GLConsumer::getCurrentTransform() const {
@@ -1006,11 +968,6 @@
     return mCurrentFenceTime;
 }
 
-status_t GLConsumer::doGLFenceWait() const {
-    Mutex::Autolock lock(mMutex);
-    return doGLFenceWaitLocked();
-}
-
 status_t GLConsumer::doGLFenceWaitLocked() const {
 
     EGLDisplay dpy = eglGetCurrentDisplay();
@@ -1027,7 +984,8 @@
     }
 
     if (mCurrentFence->isValid()) {
-        if (SyncFeatures::getInstance().useWaitSync()) {
+        if (SyncFeatures::getInstance().useWaitSync() &&
+            SyncFeatures::getInstance().useNativeFenceSync()) {
             // Create an EGLSyncKHR from the current fence.
             int fenceFd = mCurrentFence->dup();
             if (fenceFd == -1) {
@@ -1086,61 +1044,8 @@
     ConsumerBase::abandonLocked();
 }
 
-void GLConsumer::setName(const String8& name) {
-    Mutex::Autolock _l(mMutex);
-    if (mAbandoned) {
-        GLC_LOGE("setName: GLConsumer is abandoned!");
-        return;
-    }
-    mName = name;
-    mConsumer->setConsumerName(name);
-}
-
-status_t GLConsumer::setDefaultBufferFormat(PixelFormat defaultFormat) {
-    Mutex::Autolock lock(mMutex);
-    if (mAbandoned) {
-        GLC_LOGE("setDefaultBufferFormat: GLConsumer is abandoned!");
-        return NO_INIT;
-    }
-    return mConsumer->setDefaultBufferFormat(defaultFormat);
-}
-
-status_t GLConsumer::setDefaultBufferDataSpace(
-        android_dataspace defaultDataSpace) {
-    Mutex::Autolock lock(mMutex);
-    if (mAbandoned) {
-        GLC_LOGE("setDefaultBufferDataSpace: GLConsumer is abandoned!");
-        return NO_INIT;
-    }
-    return mConsumer->setDefaultBufferDataSpace(defaultDataSpace);
-}
-
 status_t GLConsumer::setConsumerUsageBits(uint64_t usage) {
-    Mutex::Autolock lock(mMutex);
-    if (mAbandoned) {
-        GLC_LOGE("setConsumerUsageBits: GLConsumer is abandoned!");
-        return NO_INIT;
-    }
-    usage |= DEFAULT_USAGE_FLAGS;
-    return mConsumer->setConsumerUsageBits(usage);
-}
-
-status_t GLConsumer::setTransformHint(uint32_t hint) {
-    Mutex::Autolock lock(mMutex);
-    if (mAbandoned) {
-        GLC_LOGE("setTransformHint: GLConsumer is abandoned!");
-        return NO_INIT;
-    }
-    return mConsumer->setTransformHint(hint);
-}
-
-status_t GLConsumer::setMaxAcquiredBufferCount(int maxAcquiredBuffers) {
-    Mutex::Autolock lock(mMutex);
-    if (mAbandoned) {
-        GLC_LOGE("setMaxAcquiredBufferCount: GLConsumer is abandoned!");
-        return NO_INIT;
-    }
-    return mConsumer->setMaxAcquiredBufferCount(maxAcquiredBuffers);
+    return ConsumerBase::setConsumerUsageBits(usage | DEFAULT_USAGE_FLAGS);
 }
 
 void GLConsumer::dumpLocked(String8& result, const char* prefix) const
@@ -1155,28 +1060,6 @@
     ConsumerBase::dumpLocked(result, prefix);
 }
 
-static void mtxMul(float out[16], const float a[16], const float b[16]) {
-    out[0] = a[0]*b[0] + a[4]*b[1] + a[8]*b[2] + a[12]*b[3];
-    out[1] = a[1]*b[0] + a[5]*b[1] + a[9]*b[2] + a[13]*b[3];
-    out[2] = a[2]*b[0] + a[6]*b[1] + a[10]*b[2] + a[14]*b[3];
-    out[3] = a[3]*b[0] + a[7]*b[1] + a[11]*b[2] + a[15]*b[3];
-
-    out[4] = a[0]*b[4] + a[4]*b[5] + a[8]*b[6] + a[12]*b[7];
-    out[5] = a[1]*b[4] + a[5]*b[5] + a[9]*b[6] + a[13]*b[7];
-    out[6] = a[2]*b[4] + a[6]*b[5] + a[10]*b[6] + a[14]*b[7];
-    out[7] = a[3]*b[4] + a[7]*b[5] + a[11]*b[6] + a[15]*b[7];
-
-    out[8] = a[0]*b[8] + a[4]*b[9] + a[8]*b[10] + a[12]*b[11];
-    out[9] = a[1]*b[8] + a[5]*b[9] + a[9]*b[10] + a[13]*b[11];
-    out[10] = a[2]*b[8] + a[6]*b[9] + a[10]*b[10] + a[14]*b[11];
-    out[11] = a[3]*b[8] + a[7]*b[9] + a[11]*b[10] + a[15]*b[11];
-
-    out[12] = a[0]*b[12] + a[4]*b[13] + a[8]*b[14] + a[12]*b[15];
-    out[13] = a[1]*b[12] + a[5]*b[13] + a[9]*b[14] + a[13]*b[15];
-    out[14] = a[2]*b[12] + a[6]*b[13] + a[10]*b[14] + a[14]*b[15];
-    out[15] = a[3]*b[12] + a[7]*b[13] + a[11]*b[14] + a[15]*b[15];
-}
-
 GLConsumer::EglImage::EglImage(sp<GraphicBuffer> graphicBuffer) :
     mGraphicBuffer(graphicBuffer),
     mEglImage(EGL_NO_IMAGE_KHR),
@@ -1267,7 +1150,7 @@
         attrs[3] = attrs[11];
         attrs[4] = EGL_NONE;
     }
-    eglInitialize(dpy, nullptr, nullptr);
+    eglInitialize(dpy, 0, 0);
     EGLImageKHR image = eglCreateImageKHR(dpy, EGL_NO_CONTEXT,
             EGL_NATIVE_BUFFER_ANDROID, cbuf, attrs);
     if (image == EGL_NO_IMAGE_KHR) {
diff --git a/libs/gui/HdrMetadata.cpp b/libs/gui/HdrMetadata.cpp
new file mode 100644
index 0000000..b715e43
--- /dev/null
+++ b/libs/gui/HdrMetadata.cpp
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gui/HdrMetadata.h>
+
+namespace android {
+
+size_t HdrMetadata::getFlattenedSize() const {
+    size_t size = sizeof(validTypes);
+    if (validTypes & SMPTE2086) {
+        size += sizeof(smpte2086);
+    }
+    if (validTypes & CTA861_3) {
+        size += sizeof(cta8613);
+    }
+    return size;
+}
+
+status_t HdrMetadata::flatten(void* buffer, size_t size) const {
+    if (size < getFlattenedSize()) {
+        return NO_MEMORY;
+    }
+
+    FlattenableUtils::write(buffer, size, validTypes);
+    if (validTypes & SMPTE2086) {
+        FlattenableUtils::write(buffer, size, smpte2086);
+    }
+    if (validTypes & CTA861_3) {
+        FlattenableUtils::write(buffer, size, cta8613);
+    }
+
+    return NO_ERROR;
+}
+
+status_t HdrMetadata::unflatten(void const* buffer, size_t size) {
+    if (size < sizeof(validTypes)) {
+        return NO_MEMORY;
+    }
+    FlattenableUtils::read(buffer, size, validTypes);
+    if (validTypes & SMPTE2086) {
+        if (size < sizeof(smpte2086)) {
+            return NO_MEMORY;
+        }
+        FlattenableUtils::read(buffer, size, smpte2086);
+    }
+    if (validTypes & CTA861_3) {
+        if (size < sizeof(cta8613)) {
+            return NO_MEMORY;
+        }
+        FlattenableUtils::read(buffer, size, cta8613);
+    }
+
+    return NO_ERROR;
+}
+
+bool HdrMetadata::operator==(const HdrMetadata& rhs) const {
+    if (validTypes != rhs.validTypes) return false;
+
+    if ((validTypes & SMPTE2086) == SMPTE2086) {
+        if (smpte2086.displayPrimaryRed.x != rhs.smpte2086.displayPrimaryRed.x ||
+            smpte2086.displayPrimaryRed.y != rhs.smpte2086.displayPrimaryRed.y ||
+            smpte2086.displayPrimaryGreen.x != rhs.smpte2086.displayPrimaryGreen.x ||
+            smpte2086.displayPrimaryGreen.y != rhs.smpte2086.displayPrimaryGreen.y ||
+            smpte2086.displayPrimaryBlue.x != rhs.smpte2086.displayPrimaryBlue.x ||
+            smpte2086.displayPrimaryBlue.y != rhs.smpte2086.displayPrimaryBlue.y ||
+            smpte2086.whitePoint.x != rhs.smpte2086.whitePoint.x ||
+            smpte2086.whitePoint.y != rhs.smpte2086.whitePoint.y ||
+            smpte2086.maxLuminance != rhs.smpte2086.maxLuminance ||
+            smpte2086.minLuminance != rhs.smpte2086.minLuminance) {
+            return false;
+        }
+    }
+
+    if ((validTypes & CTA861_3) == CTA861_3) {
+        if (cta8613.maxFrameAverageLightLevel != rhs.cta8613.maxFrameAverageLightLevel ||
+            cta8613.maxContentLightLevel != rhs.cta8613.maxContentLightLevel) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+} // namespace android
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index 23e9ddc..0749fde 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -27,6 +27,9 @@
 #include <binder/Parcel.h>
 #include <binder/IInterface.h>
 
+#ifndef NO_BUFFERHUB
+#include <gui/BufferHubProducer.h>
+#endif
 #include <gui/BufferQueueDefs.h>
 #include <gui/IGraphicBufferProducer.h>
 #include <gui/IProducerListener.h>
@@ -187,10 +190,10 @@
 
     virtual status_t detachNextBuffer(sp<GraphicBuffer>* outBuffer,
             sp<Fence>* outFence) {
-        if (outBuffer == nullptr) {
+        if (outBuffer == NULL) {
             ALOGE("detachNextBuffer: outBuffer must not be NULL");
             return BAD_VALUE;
-        } else if (outFence == nullptr) {
+        } else if (outFence == NULL) {
             ALOGE("detachNextBuffer: outFence must not be NULL");
             return BAD_VALUE;
         }
@@ -298,7 +301,7 @@
             int api, bool producerControlledByApp, QueueBufferOutput* output) {
         Parcel data, reply;
         data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
-        if (listener != nullptr) {
+        if (listener != NULL) {
             data.writeInt32(1);
             data.writeStrongBinder(IInterface::asBinder(listener));
         } else {
@@ -653,6 +656,79 @@
 
 // ----------------------------------------------------------------------
 
+status_t IGraphicBufferProducer::exportToParcel(Parcel* parcel) {
+    status_t res = OK;
+    res = parcel->writeUint32(USE_BUFFER_QUEUE);
+    if (res != NO_ERROR) {
+        ALOGE("exportToParcel: Cannot write magic, res=%d.", res);
+        return res;
+    }
+
+    return parcel->writeStrongBinder(IInterface::asBinder(this));
+}
+
+/* static */
+status_t IGraphicBufferProducer::exportToParcel(const sp<IGraphicBufferProducer>& producer,
+                                                Parcel* parcel) {
+    if (parcel == nullptr) {
+        ALOGE("exportToParcel: Invalid parcel object.");
+        return BAD_VALUE;
+    }
+
+    if (producer == nullptr) {
+        status_t res = OK;
+        res = parcel->writeUint32(IGraphicBufferProducer::USE_BUFFER_QUEUE);
+        if (res != NO_ERROR) return res;
+        return parcel->writeStrongBinder(nullptr);
+    } else {
+        return producer->exportToParcel(parcel);
+    }
+}
+
+/* static */
+sp<IGraphicBufferProducer> IGraphicBufferProducer::createFromParcel(const Parcel* parcel) {
+    uint32_t outMagic = 0;
+    status_t res = NO_ERROR;
+
+    res = parcel->readUint32(&outMagic);
+    if (res != NO_ERROR) {
+        ALOGE("createFromParcel: Failed to read magic, error=%d.", res);
+        return nullptr;
+    }
+
+    switch (outMagic) {
+        case USE_BUFFER_QUEUE: {
+            sp<IBinder> binder;
+            res = parcel->readNullableStrongBinder(&binder);
+            if (res != NO_ERROR) {
+                ALOGE("createFromParcel: Can't read strong binder.");
+                return nullptr;
+            }
+            return interface_cast<IGraphicBufferProducer>(binder);
+        }
+        case USE_BUFFER_HUB: {
+            ALOGE("createFromParcel: BufferHub not implemented.");
+#ifndef NO_BUFFERHUB
+            dvr::ProducerQueueParcelable producerParcelable;
+            res = producerParcelable.readFromParcel(parcel);
+            if (res != NO_ERROR) {
+                ALOGE("createFromParcel: Failed to read from parcel, error=%d", res);
+                return nullptr;
+            }
+            return BufferHubProducer::Create(std::move(producerParcelable));
+#else
+            return nullptr;
+#endif
+        }
+        default: {
+            ALOGE("createFromParcel: Unexpected mgaic: 0x%x.", outMagic);
+            return nullptr;
+        }
+    }
+}
+
+// ----------------------------------------------------------------------------
+
 status_t BnGraphicBufferProducer::onTransact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
@@ -662,8 +738,8 @@
             int bufferIdx   = data.readInt32();
             sp<GraphicBuffer> buffer;
             int result = requestBuffer(bufferIdx, &buffer);
-            reply->writeInt32(buffer != nullptr);
-            if (buffer != nullptr) {
+            reply->writeInt32(buffer != 0);
+            if (buffer != 0) {
                 reply->write(*buffer);
             }
             reply->writeInt32(result);
@@ -721,12 +797,12 @@
             int32_t result = detachNextBuffer(&buffer, &fence);
             reply->writeInt32(result);
             if (result == NO_ERROR) {
-                reply->writeInt32(buffer != nullptr);
-                if (buffer != nullptr) {
+                reply->writeInt32(buffer != NULL);
+                if (buffer != NULL) {
                     reply->write(*buffer);
                 }
-                reply->writeInt32(fence != nullptr);
-                if (fence != nullptr) {
+                reply->writeInt32(fence != NULL);
+                if (fence != NULL) {
                     reply->write(*fence);
                 }
             }
@@ -951,7 +1027,8 @@
 size_t IGraphicBufferProducer::QueueBufferInput::getFlattenedSize() const {
     return minFlattenedSize() +
             fence->getFlattenedSize() +
-            surfaceDamage.getFlattenedSize();
+            surfaceDamage.getFlattenedSize() +
+            hdrMetadata.getFlattenedSize();
 }
 
 size_t IGraphicBufferProducer::QueueBufferInput::getFdCount() const {
@@ -978,7 +1055,12 @@
     if (result != NO_ERROR) {
         return result;
     }
-    return surfaceDamage.flatten(buffer, size);
+    result = surfaceDamage.flatten(buffer, size);
+    if (result != NO_ERROR) {
+        return result;
+    }
+    FlattenableUtils::advance(buffer, size, surfaceDamage.getFlattenedSize());
+    return hdrMetadata.flatten(buffer, size);
 }
 
 status_t IGraphicBufferProducer::QueueBufferInput::unflatten(
@@ -1002,7 +1084,12 @@
     if (result != NO_ERROR) {
         return result;
     }
-    return surfaceDamage.unflatten(buffer, size);
+    result = surfaceDamage.unflatten(buffer, size);
+    if (result != NO_ERROR) {
+        return result;
+    }
+    FlattenableUtils::advance(buffer, size, surfaceDamage.getFlattenedSize());
+    return hdrMetadata.unflatten(buffer, size);
 }
 
 // ----------------------------------------------------------------------------
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 8e7f814..e22bc70 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -29,8 +29,7 @@
 #include <gui/ISurfaceComposer.h>
 #include <gui/ISurfaceComposerClient.h>
 #include <gui/LayerDebugInfo.h>
-
-#include <private/gui/LayerState.h>
+#include <gui/LayerState.h>
 
 #include <system/graphics.h>
 
@@ -44,6 +43,8 @@
 
 namespace android {
 
+using ui::ColorMode;
+
 class BpSurfaceComposer : public BpInterface<ISurfaceComposer>
 {
 public:
@@ -101,17 +102,13 @@
         remote()->transact(BnSurfaceComposer::BOOT_FINISHED, data, &reply);
     }
 
-    virtual status_t captureScreen(const sp<IBinder>& display,
-            const sp<IGraphicBufferProducer>& producer,
-            Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
-            int32_t minLayerZ, int32_t maxLayerZ,
-            bool useIdentityTransform,
-            ISurfaceComposer::Rotation rotation)
-    {
+    virtual status_t captureScreen(const sp<IBinder>& display, sp<GraphicBuffer>* outBuffer,
+                                   Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
+                                   int32_t minLayerZ, int32_t maxLayerZ, bool useIdentityTransform,
+                                   ISurfaceComposer::Rotation rotation) {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         data.writeStrongBinder(display);
-        data.writeStrongBinder(IInterface::asBinder(producer));
         data.write(sourceCrop);
         data.writeUint32(reqWidth);
         data.writeUint32(reqHeight);
@@ -119,8 +116,46 @@
         data.writeInt32(maxLayerZ);
         data.writeInt32(static_cast<int32_t>(useIdentityTransform));
         data.writeInt32(static_cast<int32_t>(rotation));
-        remote()->transact(BnSurfaceComposer::CAPTURE_SCREEN, data, &reply);
-        return reply.readInt32();
+        status_t err = remote()->transact(BnSurfaceComposer::CAPTURE_SCREEN, data, &reply);
+
+        if (err != NO_ERROR) {
+            return err;
+        }
+
+        err = reply.readInt32();
+        if (err != NO_ERROR) {
+            return err;
+        }
+
+        *outBuffer = new GraphicBuffer();
+        reply.read(**outBuffer);
+        return err;
+    }
+
+    virtual status_t captureLayers(const sp<IBinder>& layerHandleBinder,
+                                   sp<GraphicBuffer>* outBuffer, const Rect& sourceCrop,
+                                   float frameScale, bool childrenOnly) {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        data.writeStrongBinder(layerHandleBinder);
+        data.write(sourceCrop);
+        data.writeFloat(frameScale);
+        data.writeBool(childrenOnly);
+        status_t err = remote()->transact(BnSurfaceComposer::CAPTURE_LAYERS, data, &reply);
+
+        if (err != NO_ERROR) {
+            return err;
+        }
+
+        err = reply.readInt32();
+        if (err != NO_ERROR) {
+            return err;
+        }
+
+        *outBuffer = new GraphicBuffer();
+        reply.read(**outBuffer);
+
+        return err;
     }
 
     virtual bool authenticateSurfaceTexture(
@@ -317,7 +352,7 @@
     }
 
     virtual status_t getDisplayColorModes(const sp<IBinder>& display,
-            Vector<android_color_mode_t>* outColorModes) {
+            Vector<ColorMode>* outColorModes) {
         Parcel data, reply;
         status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         if (result != NO_ERROR) {
@@ -340,34 +375,34 @@
             outColorModes->clear();
             outColorModes->resize(numModes);
             for (size_t i = 0; i < numModes; ++i) {
-                outColorModes->replaceAt(static_cast<android_color_mode_t>(reply.readInt32()), i);
+                outColorModes->replaceAt(static_cast<ColorMode>(reply.readInt32()), i);
             }
         }
         return result;
     }
 
-    virtual android_color_mode_t getActiveColorMode(const sp<IBinder>& display) {
+    virtual ColorMode getActiveColorMode(const sp<IBinder>& display) {
         Parcel data, reply;
         status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         if (result != NO_ERROR) {
             ALOGE("getActiveColorMode failed to writeInterfaceToken: %d", result);
-            return static_cast<android_color_mode_t>(result);
+            return static_cast<ColorMode>(result);
         }
         result = data.writeStrongBinder(display);
         if (result != NO_ERROR) {
             ALOGE("getActiveColorMode failed to writeStrongBinder: %d", result);
-            return static_cast<android_color_mode_t>(result);
+            return static_cast<ColorMode>(result);
         }
         result = remote()->transact(BnSurfaceComposer::GET_ACTIVE_COLOR_MODE, data, &reply);
         if (result != NO_ERROR) {
             ALOGE("getActiveColorMode failed to transact: %d", result);
-            return static_cast<android_color_mode_t>(result);
+            return static_cast<ColorMode>(result);
         }
-        return static_cast<android_color_mode_t>(reply.readInt32());
+        return static_cast<ColorMode>(reply.readInt32());
     }
 
     virtual status_t setActiveColorMode(const sp<IBinder>& display,
-            android_color_mode_t colorMode) {
+            ColorMode colorMode) {
         Parcel data, reply;
         status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         if (result != NO_ERROR) {
@@ -379,7 +414,7 @@
             ALOGE("setActiveColorMode failed to writeStrongBinder: %d", result);
             return result;
         }
-        result = data.writeInt32(colorMode);
+        result = data.writeInt32(static_cast<int32_t>(colorMode));
         if (result != NO_ERROR) {
             ALOGE("setActiveColorMode failed to writeInt32: %d", result);
             return result;
@@ -571,8 +606,7 @@
         case CAPTURE_SCREEN: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
             sp<IBinder> display = data.readStrongBinder();
-            sp<IGraphicBufferProducer> producer =
-                    interface_cast<IGraphicBufferProducer>(data.readStrongBinder());
+            sp<GraphicBuffer> outBuffer;
             Rect sourceCrop(Rect::EMPTY_RECT);
             data.read(sourceCrop);
             uint32_t reqWidth = data.readUint32();
@@ -582,11 +616,30 @@
             bool useIdentityTransform = static_cast<bool>(data.readInt32());
             int32_t rotation = data.readInt32();
 
-            status_t res = captureScreen(display, producer,
-                    sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ,
-                    useIdentityTransform,
-                    static_cast<ISurfaceComposer::Rotation>(rotation));
+            status_t res = captureScreen(display, &outBuffer, sourceCrop, reqWidth, reqHeight,
+                                         minLayerZ, maxLayerZ, useIdentityTransform,
+                                         static_cast<ISurfaceComposer::Rotation>(rotation));
             reply->writeInt32(res);
+            if (res == NO_ERROR) {
+                reply->write(*outBuffer);
+            }
+            return NO_ERROR;
+        }
+        case CAPTURE_LAYERS: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+            sp<IBinder> layerHandleBinder = data.readStrongBinder();
+            sp<GraphicBuffer> outBuffer;
+            Rect sourceCrop(Rect::EMPTY_RECT);
+            data.read(sourceCrop);
+            float frameScale = data.readFloat();
+            bool childrenOnly = data.readBool();
+
+            status_t res = captureLayers(layerHandleBinder, &outBuffer, sourceCrop, frameScale,
+                                         childrenOnly);
+            reply->writeInt32(res);
+            if (res == NO_ERROR) {
+                reply->write(*outBuffer);
+            }
             return NO_ERROR;
         }
         case AUTHENTICATE_SURFACE: {
@@ -688,7 +741,7 @@
         }
         case GET_DISPLAY_COLOR_MODES: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            Vector<android_color_mode_t> colorModes;
+            Vector<ColorMode> colorModes;
             sp<IBinder> display = nullptr;
             status_t result = data.readStrongBinder(&display);
             if (result != NO_ERROR) {
@@ -700,7 +753,7 @@
             if (result == NO_ERROR) {
                 reply->writeUint32(static_cast<uint32_t>(colorModes.size()));
                 for (size_t i = 0; i < colorModes.size(); ++i) {
-                    reply->writeInt32(colorModes[i]);
+                    reply->writeInt32(static_cast<int32_t>(colorModes[i]));
                 }
             }
             return NO_ERROR;
@@ -713,7 +766,7 @@
                 ALOGE("getActiveColorMode failed to readStrongBinder: %d", result);
                 return result;
             }
-            android_color_mode_t colorMode = getActiveColorMode(display);
+            ColorMode colorMode = getActiveColorMode(display);
             result = reply->writeInt32(static_cast<int32_t>(colorMode));
             return result;
         }
@@ -732,7 +785,7 @@
                 return result;
             }
             result = setActiveColorMode(display,
-                    static_cast<android_color_mode_t>(colorModeInt));
+                    static_cast<ColorMode>(colorModeInt));
             result = reply->writeInt32(result);
             return result;
         }
diff --git a/libs/gui/ISurfaceComposerClient.cpp b/libs/gui/ISurfaceComposerClient.cpp
index 679f44b..a6890ee 100644
--- a/libs/gui/ISurfaceComposerClient.cpp
+++ b/libs/gui/ISurfaceComposerClient.cpp
@@ -47,8 +47,8 @@
     ~BpSurfaceComposerClient() override;
 
     status_t createSurface(const String8& name, uint32_t width, uint32_t height, PixelFormat format,
-                           uint32_t flags, const sp<IBinder>& parent, uint32_t windowType,
-                           uint32_t ownerUid, sp<IBinder>* handle,
+                           uint32_t flags, const sp<IBinder>& parent, int32_t windowType,
+                           int32_t ownerUid, sp<IBinder>* handle,
                            sp<IGraphicBufferProducer>* gbp) override {
         return callRemote<decltype(&ISurfaceComposerClient::createSurface)>(Tag::CREATE_SURFACE,
                                                                             name, width, height,
diff --git a/libs/gui/LayerDebugInfo.cpp b/libs/gui/LayerDebugInfo.cpp
index 57ddde0..d3dc16d 100644
--- a/libs/gui/LayerDebugInfo.cpp
+++ b/libs/gui/LayerDebugInfo.cpp
@@ -43,7 +43,10 @@
     RETURN_ON_ERROR(parcel->writeInt32(mHeight));
     RETURN_ON_ERROR(parcel->write(mCrop));
     RETURN_ON_ERROR(parcel->write(mFinalCrop));
-    RETURN_ON_ERROR(parcel->writeFloat(mAlpha));
+    RETURN_ON_ERROR(parcel->writeFloat(mColor.r));
+    RETURN_ON_ERROR(parcel->writeFloat(mColor.g));
+    RETURN_ON_ERROR(parcel->writeFloat(mColor.b));
+    RETURN_ON_ERROR(parcel->writeFloat(mColor.a));
     RETURN_ON_ERROR(parcel->writeUint32(mFlags));
     RETURN_ON_ERROR(parcel->writeInt32(mPixelFormat));
     RETURN_ON_ERROR(parcel->writeUint32(static_cast<uint32_t>(mDataSpace)));
@@ -79,7 +82,14 @@
     RETURN_ON_ERROR(parcel->readInt32(&mHeight));
     RETURN_ON_ERROR(parcel->read(mCrop));
     RETURN_ON_ERROR(parcel->read(mFinalCrop));
-    RETURN_ON_ERROR(parcel->readFloat(&mAlpha));
+    mColor.r = parcel->readFloat();
+    RETURN_ON_ERROR(parcel->errorCheck());
+    mColor.g = parcel->readFloat();
+    RETURN_ON_ERROR(parcel->errorCheck());
+    mColor.b = parcel->readFloat();
+    RETURN_ON_ERROR(parcel->errorCheck());
+    mColor.a = parcel->readFloat();
+    RETURN_ON_ERROR(parcel->errorCheck());
     RETURN_ON_ERROR(parcel->readUint32(&mFlags));
     RETURN_ON_ERROR(parcel->readInt32(&mPixelFormat));
     // \todo [2017-07-25 kraita]: Static casting mDataSpace pointer to an uint32 does work. Better ways?
@@ -116,8 +126,10 @@
     result.appendFormat("isOpaque=%1d, invalidate=%1d, ", info.mIsOpaque, info.mContentDirty);
     result.appendFormat("dataspace=%s, ", dataspaceDetails(info.mDataSpace).c_str());
     result.appendFormat("pixelformat=%s, ", decodePixelFormat(info.mPixelFormat).c_str());
-    result.appendFormat("alpha=%.3f, flags=0x%08x, ",
-            static_cast<double>(info.mAlpha), info.mFlags);
+    result.appendFormat("color=(%.3f,%.3f,%.3f,%.3f), flags=0x%08x, ",
+            static_cast<double>(info.mColor.r), static_cast<double>(info.mColor.g),
+            static_cast<double>(info.mColor.b), static_cast<double>(info.mColor.a),
+            info.mFlags);
     result.appendFormat("tr=[%.2f, %.2f][%.2f, %.2f]",
             static_cast<double>(info.mMatrix[0][0]), static_cast<double>(info.mMatrix[0][1]),
             static_cast<double>(info.mMatrix[1][0]), static_cast<double>(info.mMatrix[1][1]));
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 9b06e63..01acc2d 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -18,7 +18,7 @@
 #include <binder/Parcel.h>
 #include <gui/ISurfaceComposerClient.h>
 #include <gui/IGraphicBufferProducer.h>
-#include <private/gui/LayerState.h>
+#include <gui/LayerState.h>
 
 namespace android {
 
@@ -45,6 +45,10 @@
     output.writeInt32(overrideScalingMode);
     output.writeStrongBinder(IInterface::asBinder(barrierGbp));
     output.writeStrongBinder(relativeLayerHandle);
+    output.writeStrongBinder(parentHandleForChild);
+    output.writeFloat(color.r);
+    output.writeFloat(color.g);
+    output.writeFloat(color.b);
     output.write(transparentRegion);
     return NO_ERROR;
 }
@@ -77,6 +81,10 @@
     barrierGbp =
         interface_cast<IGraphicBufferProducer>(input.readStrongBinder());
     relativeLayerHandle = input.readStrongBinder();
+    parentHandleForChild = input.readStrongBinder();
+    color.r = input.readFloat();
+    color.g = input.readFloat();
+    color.b = input.readFloat();
     input.read(transparentRegion);
     return NO_ERROR;
 }
@@ -128,5 +136,104 @@
     return NO_ERROR;
 }
 
+void DisplayState::merge(const DisplayState& other) {
+    if (other.what & eSurfaceChanged) {
+        what |= eSurfaceChanged;
+        surface = other.surface;
+    }
+    if (other.what & eLayerStackChanged) {
+        what |= eLayerStackChanged;
+        layerStack = other.layerStack;
+    }
+    if (other.what & eDisplayProjectionChanged) {
+        what |= eDisplayProjectionChanged;
+        orientation = other.orientation;
+        viewport = other.viewport;
+        frame = other.frame;
+    }
+    if (other.what & eDisplaySizeChanged) {
+        what |= eDisplaySizeChanged;
+        width = other.width;
+        height = other.height;
+    }
+}
+
+void layer_state_t::merge(const layer_state_t& other) {
+    if (other.what & ePositionChanged) {
+        what |= ePositionChanged;
+        x = other.x;
+        y = other.y;
+    }
+    if (other.what & eLayerChanged) {
+        what |= eLayerChanged;
+        z = other.z;
+    }
+    if (other.what & eSizeChanged) {
+        what |= eSizeChanged;
+        w = other.w;
+        h = other.h;
+    }
+    if (other.what & eAlphaChanged) {
+        what |= eAlphaChanged;
+        alpha = other.alpha;
+    }
+    if (other.what & eMatrixChanged) {
+        what |= eMatrixChanged;
+        matrix = other.matrix;
+    }
+    if (other.what & eTransparentRegionChanged) {
+        what |= eTransparentRegionChanged;
+        transparentRegion = other.transparentRegion;
+    }
+    if (other.what & eFlagsChanged) {
+        what |= eFlagsChanged;
+        flags = other.flags;
+        mask = other.mask;
+    }
+    if (other.what & eLayerStackChanged) {
+        what |= eLayerStackChanged;
+        layerStack = other.layerStack;
+    }
+    if (other.what & eCropChanged) {
+        what |= eCropChanged;
+        crop = other.crop;
+    }
+    if (other.what & eDeferTransaction) {
+        what |= eDeferTransaction;
+        barrierHandle = other.barrierHandle;
+        barrierGbp = other.barrierGbp;
+        frameNumber = other.frameNumber;
+    }
+    if (other.what & eFinalCropChanged) {
+        what |= eFinalCropChanged;
+        finalCrop = other.finalCrop;
+    }
+    if (other.what & eOverrideScalingModeChanged) {
+        what |= eOverrideScalingModeChanged;
+        overrideScalingMode = other.overrideScalingMode;
+    }
+    if (other.what & eGeometryAppliesWithResize) {
+        what |= eGeometryAppliesWithResize;
+    }
+    if (other.what & eReparentChildren) {
+        what |= eReparentChildren;
+        reparentHandle = other.reparentHandle;
+    }
+    if (other.what & eDetachChildren) {
+        what |= eDetachChildren;
+    }
+    if (other.what & eRelativeLayerChanged) {
+        what |= eRelativeLayerChanged;
+        z = other.z;
+        relativeLayerHandle = other.relativeLayerHandle;
+    }
+    if (other.what & eReparent) {
+        what |= eReparent;
+        parentHandleForChild = other.parentHandleForChild;
+    }
+    if (other.what & eDestroySurface) {
+        what |= eDestroySurface;
+    }
+}
 
 }; // namespace android
diff --git a/libs/gui/StreamSplitter.cpp b/libs/gui/StreamSplitter.cpp
index 2f8e104..52c9067 100644
--- a/libs/gui/StreamSplitter.cpp
+++ b/libs/gui/StreamSplitter.cpp
@@ -38,11 +38,11 @@
 status_t StreamSplitter::createSplitter(
         const sp<IGraphicBufferConsumer>& inputQueue,
         sp<StreamSplitter>* outSplitter) {
-    if (inputQueue == nullptr) {
+    if (inputQueue == NULL) {
         ALOGE("createSplitter: inputQueue must not be NULL");
         return BAD_VALUE;
     }
-    if (outSplitter == nullptr) {
+    if (outSplitter == NULL) {
         ALOGE("createSplitter: outSplitter must not be NULL");
         return BAD_VALUE;
     }
@@ -74,7 +74,7 @@
 
 status_t StreamSplitter::addOutput(
         const sp<IGraphicBufferProducer>& outputQueue) {
-    if (outputQueue == nullptr) {
+    if (outputQueue == NULL) {
         ALOGE("addOutput: outputQueue must not be NULL");
         return BAD_VALUE;
     }
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index e55e6e4..339bd0f 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -44,6 +44,9 @@
 
 namespace android {
 
+using ui::ColorMode;
+using ui::Dataspace;
+
 Surface::Surface(const sp<IGraphicBufferProducer>& bufferProducer, bool controlledByApp)
       : mGraphicBufferProducer(bufferProducer),
         mCrop(Rect::EMPTY_RECT),
@@ -78,7 +81,7 @@
     mReqFormat = 0;
     mReqUsage = 0;
     mTimestamp = NATIVE_WINDOW_TIMESTAMP_AUTO;
-    mDataSpace = HAL_DATASPACE_UNKNOWN;
+    mDataSpace = Dataspace::UNKNOWN;
     mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE;
     mTransform = 0;
     mStickyTransform = 0;
@@ -153,7 +156,7 @@
     ATRACE_CALL();
 
     DisplayStatInfo stats;
-    status_t result = composerService()->getDisplayStats(nullptr, &stats);
+    status_t result = composerService()->getDisplayStats(NULL, &stats);
     if (result != NO_ERROR) {
         return result;
     }
@@ -326,7 +329,7 @@
 
     sp<IBinder> display(
         composerService()->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
-    Vector<android_color_mode_t> colorModes;
+    Vector<ColorMode> colorModes;
     status_t err =
         composerService()->getDisplayColorModes(display, &colorModes);
 
@@ -338,11 +341,11 @@
                 &ISurfaceFlingerConfigs::hasWideColorDisplay>(false);
 
     *supported = false;
-    for (android_color_mode_t colorMode : colorModes) {
+    for (ColorMode colorMode : colorModes) {
         switch (colorMode) {
-            case HAL_COLOR_MODE_DISPLAY_P3:
-            case HAL_COLOR_MODE_ADOBE_RGB:
-            case HAL_COLOR_MODE_DCI_P3:
+            case ColorMode::DISPLAY_P3:
+            case ColorMode::ADOBE_RGB:
+            case ColorMode::DCI_P3:
                 if (wideColorBoardConfig) {
                     *supported = true;
                 }
@@ -494,7 +497,7 @@
         if (mSharedBufferMode && mAutoRefresh && mSharedBufferSlot !=
                 BufferItem::INVALID_BUFFER_SLOT) {
             sp<GraphicBuffer>& gbuf(mSlots[mSharedBufferSlot].buffer);
-            if (gbuf != nullptr) {
+            if (gbuf != NULL) {
                 *buffer = gbuf.get();
                 *fenceFd = -1;
                 return OK;
@@ -534,7 +537,7 @@
     sp<GraphicBuffer>& gbuf(mSlots[buf].buffer);
 
     // this should never happen
-    ALOGE_IF(fence == nullptr, "Surface::dequeueBuffer: received null Fence! buf=%d", buf);
+    ALOGE_IF(fence == NULL, "Surface::dequeueBuffer: received null Fence! buf=%d", buf);
 
     if (result & IGraphicBufferProducer::RELEASE_ALL_BUFFERS) {
         freeAllBuffers();
@@ -612,7 +615,7 @@
 int Surface::getSlotFromBufferLocked(
         android_native_buffer_t* buffer) const {
     for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
-        if (mSlots[i].buffer != nullptr &&
+        if (mSlots[i].buffer != NULL &&
                 mSlots[i].buffer->handle == buffer->handle) {
             return i;
         }
@@ -664,8 +667,12 @@
     sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE);
     IGraphicBufferProducer::QueueBufferOutput output;
     IGraphicBufferProducer::QueueBufferInput input(timestamp, isAutoTimestamp,
-            mDataSpace, crop, mScalingMode, mTransform ^ mStickyTransform,
-            fence, mStickyTransform, mEnableFrameTimestamps);
+            static_cast<android_dataspace>(mDataSpace), crop, mScalingMode,
+            mTransform ^ mStickyTransform, fence, mStickyTransform,
+            mEnableFrameTimestamps);
+
+    // we should send HDR metadata as needed if this becomes a bottleneck
+    input.setHdrMetadata(mHdrMetadata);
 
     if (mConnectedToCpu || mDirtyRegion.bounds() == Rect::INVALID_RECT) {
         input.setSurfaceDamage(Region::INVALID_REGION);
@@ -878,6 +885,10 @@
                 *value = mGraphicBufferProducer != nullptr ? 1 : 0;
                 return NO_ERROR;
             }
+            case NATIVE_WINDOW_DATASPACE: {
+                *value = static_cast<int>(mDataSpace);
+                return NO_ERROR;
+            }
         }
     }
     return mGraphicBufferProducer->query(what, value);
@@ -944,6 +955,12 @@
     case NATIVE_WINDOW_SET_BUFFERS_DATASPACE:
         res = dispatchSetBuffersDataSpace(args);
         break;
+    case NATIVE_WINDOW_SET_BUFFERS_SMPTE2086_METADATA:
+        res = dispatchSetBuffersSmpte2086Metadata(args);
+        break;
+    case NATIVE_WINDOW_SET_BUFFERS_CTA861_3_METADATA:
+        res = dispatchSetBuffersCta8613Metadata(args);
+        break;
     case NATIVE_WINDOW_SET_SURFACE_DAMAGE:
         res = dispatchSetSurfaceDamage(args);
         break;
@@ -1083,11 +1100,22 @@
 }
 
 int Surface::dispatchSetBuffersDataSpace(va_list args) {
-    android_dataspace dataspace =
-            static_cast<android_dataspace>(va_arg(args, int));
+    Dataspace dataspace = static_cast<Dataspace>(va_arg(args, int));
     return setBuffersDataSpace(dataspace);
 }
 
+int Surface::dispatchSetBuffersSmpte2086Metadata(va_list args) {
+    const android_smpte2086_metadata* metadata =
+        va_arg(args, const android_smpte2086_metadata*);
+    return setBuffersSmpte2086Metadata(metadata);
+}
+
+int Surface::dispatchSetBuffersCta8613Metadata(va_list args) {
+    const android_cta861_3_metadata* metadata =
+        va_arg(args, const android_cta861_3_metadata*);
+    return setBuffersCta8613Metadata(metadata);
+}
+
 int Surface::dispatchSetSurfaceDamage(va_list args) {
     android_native_rect_t* rects = va_arg(args, android_native_rect_t*);
     size_t numRects = va_arg(args, size_t);
@@ -1236,7 +1264,7 @@
     ATRACE_CALL();
     ALOGV("Surface::detachNextBuffer");
 
-    if (outBuffer == nullptr || outFence == nullptr) {
+    if (outBuffer == NULL || outFence == NULL) {
         return BAD_VALUE;
     }
 
@@ -1245,8 +1273,8 @@
         mRemovedBuffers.clear();
     }
 
-    sp<GraphicBuffer> buffer(nullptr);
-    sp<Fence> fence(nullptr);
+    sp<GraphicBuffer> buffer(NULL);
+    sp<Fence> fence(NULL);
     status_t result = mGraphicBufferProducer->detachNextBuffer(
             &buffer, &fence);
     if (result != NO_ERROR) {
@@ -1254,19 +1282,19 @@
     }
 
     *outBuffer = buffer;
-    if (fence != nullptr && fence->isValid()) {
+    if (fence != NULL && fence->isValid()) {
         *outFence = fence;
     } else {
         *outFence = Fence::NO_FENCE;
     }
 
     for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
-        if (mSlots[i].buffer != nullptr &&
+        if (mSlots[i].buffer != NULL &&
                 mSlots[i].buffer->getId() == buffer->getId()) {
             if (mReportRemovedBuffers) {
                 mRemovedBuffers.push_back(mSlots[i].buffer);
             }
-            mSlots[i].buffer = nullptr;
+            mSlots[i].buffer = NULL;
         }
     }
 
@@ -1317,7 +1345,7 @@
     ATRACE_CALL();
 
     Rect realRect(Rect::EMPTY_RECT);
-    if (rect == nullptr || rect->isEmpty()) {
+    if (rect == NULL || rect->isEmpty()) {
         realRect.clear();
     } else {
         realRect = *rect;
@@ -1504,7 +1532,7 @@
     return NO_ERROR;
 }
 
-int Surface::setBuffersDataSpace(android_dataspace dataSpace)
+int Surface::setBuffersDataSpace(Dataspace dataSpace)
 {
     ALOGV("Surface::setBuffersDataSpace");
     Mutex::Autolock lock(mMutex);
@@ -1512,9 +1540,39 @@
     return NO_ERROR;
 }
 
+int Surface::setBuffersSmpte2086Metadata(const android_smpte2086_metadata* metadata) {
+    ALOGV("Surface::setBuffersSmpte2086Metadata");
+    Mutex::Autolock lock(mMutex);
+    if (metadata) {
+        mHdrMetadata.smpte2086 = *metadata;
+        mHdrMetadata.validTypes |= HdrMetadata::SMPTE2086;
+    } else {
+        mHdrMetadata.validTypes &= ~HdrMetadata::SMPTE2086;
+    }
+    return NO_ERROR;
+}
+
+int Surface::setBuffersCta8613Metadata(const android_cta861_3_metadata* metadata) {
+    ALOGV("Surface::setBuffersCta8613Metadata");
+    Mutex::Autolock lock(mMutex);
+    if (metadata) {
+        mHdrMetadata.cta8613 = *metadata;
+        mHdrMetadata.validTypes |= HdrMetadata::CTA861_3;
+    } else {
+        mHdrMetadata.validTypes &= ~HdrMetadata::CTA861_3;
+    }
+    return NO_ERROR;
+}
+
+Dataspace Surface::getBuffersDataSpace() {
+    ALOGV("Surface::getBuffersDataSpace");
+    Mutex::Autolock lock(mMutex);
+    return mDataSpace;
+}
+
 void Surface::freeAllBuffers() {
     for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
-        mSlots[i].buffer = nullptr;
+        mSlots[i].buffer = 0;
     }
 }
 
@@ -1554,12 +1612,12 @@
     // src and dst with, height and format must be identical. no verification
     // is done here.
     status_t err;
-    uint8_t* src_bits = nullptr;
+    uint8_t* src_bits = NULL;
     err = src->lock(GRALLOC_USAGE_SW_READ_OFTEN, reg.bounds(),
             reinterpret_cast<void**>(&src_bits));
     ALOGE_IF(err, "error locking src buffer %s", strerror(-err));
 
-    uint8_t* dst_bits = nullptr;
+    uint8_t* dst_bits = NULL;
     err = dst->lockAsync(GRALLOC_USAGE_SW_WRITE_OFTEN, reg.bounds(),
             reinterpret_cast<void**>(&dst_bits), *dstFenceFd);
     ALOGE_IF(err, "error locking dst buffer %s", strerror(-err));
@@ -1607,7 +1665,7 @@
 status_t Surface::lock(
         ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds)
 {
-    if (mLockedBuffer != nullptr) {
+    if (mLockedBuffer != 0) {
         ALOGE("Surface::lock failed, already locked");
         return INVALID_OPERATION;
     }
@@ -1639,7 +1697,7 @@
 
         // figure out if we can copy the frontbuffer back
         const sp<GraphicBuffer>& frontBuffer(mPostedBuffer);
-        const bool canCopyBack = (frontBuffer != nullptr &&
+        const bool canCopyBack = (frontBuffer != 0 &&
                 backBuffer->width  == frontBuffer->width &&
                 backBuffer->height == frontBuffer->height &&
                 backBuffer->format == frontBuffer->format);
@@ -1701,7 +1759,7 @@
 
 status_t Surface::unlockAndPost()
 {
-    if (mLockedBuffer == nullptr) {
+    if (mLockedBuffer == 0) {
         ALOGE("Surface::unlockAndPost failed, no locked buffer");
         return INVALID_OPERATION;
     }
@@ -1715,7 +1773,7 @@
             mLockedBuffer->handle, strerror(-err));
 
     mPostedBuffer = mLockedBuffer;
-    mLockedBuffer = nullptr;
+    mLockedBuffer = 0;
     return err;
 }
 
@@ -1754,4 +1812,25 @@
     return OK;
 }
 
+status_t Surface::attachAndQueueBuffer(Surface* surface, sp<GraphicBuffer> buffer) {
+    if (buffer == nullptr) {
+        return BAD_VALUE;
+    }
+    int err = static_cast<ANativeWindow*>(surface)->perform(surface, NATIVE_WINDOW_API_CONNECT,
+                                                            NATIVE_WINDOW_API_CPU);
+    if (err != OK) {
+        return err;
+    }
+    err = surface->attachBuffer(buffer->getNativeBuffer());
+    if (err != OK) {
+        return err;
+    }
+    err = static_cast<ANativeWindow*>(surface)->queueBuffer(surface, buffer->getNativeBuffer(), -1);
+    if (err != OK) {
+        return err;
+    }
+    err = surface->disconnect(NATIVE_WINDOW_API_CPU);
+    return err;
+}
+
 }; // namespace android
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 053b9af..63560c4 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -21,7 +21,6 @@
 
 #include <utils/Errors.h>
 #include <utils/Log.h>
-#include <utils/Singleton.h>
 #include <utils/SortedVector.h>
 #include <utils/String8.h>
 #include <utils/threads.h>
@@ -37,13 +36,15 @@
 #include <gui/IGraphicBufferProducer.h>
 #include <gui/ISurfaceComposer.h>
 #include <gui/ISurfaceComposerClient.h>
+#include <gui/LayerState.h>
 #include <gui/Surface.h>
 #include <gui/SurfaceComposerClient.h>
 
 #include <private/gui/ComposerService.h>
-#include <private/gui/LayerState.h>
 
 namespace android {
+
+using ui::ColorMode;
 // ---------------------------------------------------------------------------
 
 ANDROID_SINGLETON_STATIC_INSTANCE(ComposerService);
@@ -80,7 +81,7 @@
 /*static*/ sp<ISurfaceComposer> ComposerService::getComposerService() {
     ComposerService& instance = ComposerService::getInstance();
     Mutex::Autolock _l(instance.mLock);
-    if (instance.mComposerService == nullptr) {
+    if (instance.mComposerService == NULL) {
         ComposerService::getInstance().connectLocked();
         assert(instance.mComposerService != NULL);
         ALOGD("ComposerService reconnected");
@@ -91,239 +92,150 @@
 void ComposerService::composerServiceDied()
 {
     Mutex::Autolock _l(mLock);
-    mComposerService = nullptr;
-    mDeathObserver = nullptr;
+    mComposerService = NULL;
+    mDeathObserver = NULL;
 }
 
 // ---------------------------------------------------------------------------
 
-static inline
-int compare_type(const ComposerState& lhs, const ComposerState& rhs) {
-    if (lhs.client < rhs.client)  return -1;
-    if (lhs.client > rhs.client)  return 1;
-    if (lhs.state.surface < rhs.state.surface)  return -1;
-    if (lhs.state.surface > rhs.state.surface)  return 1;
-    return 0;
+SurfaceComposerClient::Transaction::Transaction(const Transaction& other) :
+    mForceSynchronous(other.mForceSynchronous),
+    mTransactionNestCount(other.mTransactionNestCount),
+    mAnimation(other.mAnimation),
+    mEarlyWakeup(other.mEarlyWakeup) {
+    mDisplayStates = other.mDisplayStates;
+    mComposerStates = other.mComposerStates;
 }
 
-static inline
-int compare_type(const DisplayState& lhs, const DisplayState& rhs) {
-    return compare_type(lhs.token, rhs.token);
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Transaction&& other) {
+    for (auto const& kv : other.mComposerStates) {
+        if (mComposerStates.count(kv.first) == 0) {
+            mComposerStates[kv.first] = kv.second;
+        } else {
+            mComposerStates[kv.first].state.merge(kv.second.state);
+        }
+    }
+    other.mComposerStates.clear();
+
+    for (auto const& state : other.mDisplayStates) {
+        ssize_t index = mDisplayStates.indexOf(state);
+        if (index < 0) {
+            mDisplayStates.add(state);
+        } else {
+            mDisplayStates.editItemAt(static_cast<size_t>(index)).merge(state);
+        }
+    }
+    other.mDisplayStates.clear();
+
+    return *this;
 }
 
-class Composer : public Singleton<Composer>
-{
-    friend class Singleton<Composer>;
-
-    mutable Mutex               mLock;
-    SortedVector<ComposerState> mComposerStates;
-    SortedVector<DisplayState > mDisplayStates;
-    uint32_t                    mForceSynchronous;
-    uint32_t                    mTransactionNestCount;
-    bool                        mAnimation;
-
-    Composer() : Singleton<Composer>(),
-        mForceSynchronous(0), mTransactionNestCount(0),
-        mAnimation(false)
-    { }
-
-    void openGlobalTransactionImpl();
-    void closeGlobalTransactionImpl(bool synchronous);
-    void setAnimationTransactionImpl();
-    status_t enableVSyncInjectionsImpl(bool enable);
-    status_t injectVSyncImpl(nsecs_t when);
-
-    layer_state_t* getLayerStateLocked(
-            const sp<SurfaceComposerClient>& client, const sp<IBinder>& id);
-
-    DisplayState& getDisplayStateLocked(const sp<IBinder>& token);
-
-public:
-    sp<IBinder> createDisplay(const String8& displayName, bool secure);
-    void destroyDisplay(const sp<IBinder>& display);
-    sp<IBinder> getBuiltInDisplay(int32_t id);
-
-    status_t setPosition(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
-            float x, float y);
-    status_t setSize(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
-            uint32_t w, uint32_t h);
-    status_t setLayer(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
-            int32_t z);
-    status_t setRelativeLayer(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
-            const sp<IBinder>& relativeTo, int32_t z);
-    status_t setFlags(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
-            uint32_t flags, uint32_t mask);
-    status_t setTransparentRegionHint(
-            const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
-            const Region& transparentRegion);
-    status_t setAlpha(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
-            float alpha);
-    status_t setMatrix(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
-            float dsdx, float dtdx, float dtdy, float dsdy);
-    status_t setOrientation(int orientation);
-    status_t setCrop(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
-            const Rect& crop);
-    status_t setFinalCrop(const sp<SurfaceComposerClient>& client,
-            const sp<IBinder>& id, const Rect& crop);
-    status_t setLayerStack(const sp<SurfaceComposerClient>& client,
-            const sp<IBinder>& id, uint32_t layerStack);
-    status_t deferTransactionUntil(const sp<SurfaceComposerClient>& client,
-            const sp<IBinder>& id, const sp<IBinder>& handle,
-            uint64_t frameNumber);
-    status_t deferTransactionUntil(const sp<SurfaceComposerClient>& client,
-            const sp<IBinder>& id, const sp<Surface>& barrierSurface,
-            uint64_t frameNumber);
-    status_t reparentChildren(const sp<SurfaceComposerClient>& client,
-            const sp<IBinder>& id,
-            const sp<IBinder>& newParentHandle);
-    status_t detachChildren(const sp<SurfaceComposerClient>& client,
-            const sp<IBinder>& id);
-    status_t setOverrideScalingMode(const sp<SurfaceComposerClient>& client,
-            const sp<IBinder>& id, int32_t overrideScalingMode);
-    status_t setGeometryAppliesWithResize(const sp<SurfaceComposerClient>& client,
-            const sp<IBinder>& id);
-
-    status_t setDisplaySurface(const sp<IBinder>& token,
-            sp<IGraphicBufferProducer> bufferProducer);
-    void setDisplayLayerStack(const sp<IBinder>& token, uint32_t layerStack);
-    void setDisplayProjection(const sp<IBinder>& token,
-            uint32_t orientation,
-            const Rect& layerStackRect,
-            const Rect& displayRect);
-    void setDisplaySize(const sp<IBinder>& token, uint32_t width, uint32_t height);
-
-    static void setAnimationTransaction() {
-        Composer::getInstance().setAnimationTransactionImpl();
+status_t SurfaceComposerClient::Transaction::apply(bool synchronous) {
+    if (mStatus != NO_ERROR) {
+        return mStatus;
     }
 
-    static void openGlobalTransaction() {
-        Composer::getInstance().openGlobalTransactionImpl();
+    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+
+    Vector<ComposerState> composerStates;
+    Vector<DisplayState> displayStates;
+    uint32_t flags = 0;
+
+    mForceSynchronous |= synchronous;
+
+    for (auto const& kv : mComposerStates){
+        composerStates.add(kv.second);
     }
 
-    static void closeGlobalTransaction(bool synchronous) {
-        Composer::getInstance().closeGlobalTransactionImpl(synchronous);
+    mComposerStates.clear();
+
+    displayStates = mDisplayStates;
+    mDisplayStates.clear();
+
+    if (mForceSynchronous) {
+        flags |= ISurfaceComposer::eSynchronous;
+    }
+    if (mAnimation) {
+        flags |= ISurfaceComposer::eAnimation;
+    }
+    if (mEarlyWakeup) {
+        flags |= ISurfaceComposer::eEarlyWakeup;
     }
 
-    static status_t enableVSyncInjections(bool enable) {
-        return Composer::getInstance().enableVSyncInjectionsImpl(enable);
-    }
+    mForceSynchronous = false;
+    mAnimation = false;
+    mEarlyWakeup = false;
 
-    static status_t injectVSync(nsecs_t when) {
-        return Composer::getInstance().injectVSyncImpl(when);
-    }
-};
-
-ANDROID_SINGLETON_STATIC_INSTANCE(Composer);
+    sf->setTransactionState(composerStates, displayStates, flags);
+    mStatus = NO_ERROR;
+    return NO_ERROR;
+}
 
 // ---------------------------------------------------------------------------
 
-sp<IBinder> Composer::createDisplay(const String8& displayName, bool secure) {
+sp<IBinder> SurfaceComposerClient::createDisplay(const String8& displayName, bool secure) {
     return ComposerService::getComposerService()->createDisplay(displayName,
             secure);
 }
 
-void Composer::destroyDisplay(const sp<IBinder>& display) {
+void SurfaceComposerClient::destroyDisplay(const sp<IBinder>& display) {
     return ComposerService::getComposerService()->destroyDisplay(display);
 }
 
-sp<IBinder> Composer::getBuiltInDisplay(int32_t id) {
+sp<IBinder> SurfaceComposerClient::getBuiltInDisplay(int32_t id) {
     return ComposerService::getComposerService()->getBuiltInDisplay(id);
 }
 
-void Composer::openGlobalTransactionImpl() {
-    { // scope for the lock
-        Mutex::Autolock _l(mLock);
-        mTransactionNestCount += 1;
-    }
-}
-
-void Composer::closeGlobalTransactionImpl(bool synchronous) {
-    sp<ISurfaceComposer> sm(ComposerService::getComposerService());
-
-    Vector<ComposerState> transaction;
-    Vector<DisplayState> displayTransaction;
-    uint32_t flags = 0;
-
-    { // scope for the lock
-        Mutex::Autolock _l(mLock);
-        mForceSynchronous |= synchronous;
-        if (!mTransactionNestCount) {
-            ALOGW("At least one call to closeGlobalTransaction() was not matched by a prior "
-                    "call to openGlobalTransaction().");
-        } else if (--mTransactionNestCount) {
-            return;
-        }
-
-        transaction = mComposerStates;
-        mComposerStates.clear();
-
-        displayTransaction = mDisplayStates;
-        mDisplayStates.clear();
-
-        if (mForceSynchronous) {
-            flags |= ISurfaceComposer::eSynchronous;
-        }
-        if (mAnimation) {
-            flags |= ISurfaceComposer::eAnimation;
-        }
-
-        mForceSynchronous = false;
-        mAnimation = false;
-    }
-
-   sm->setTransactionState(transaction, displayTransaction, flags);
-}
-
-status_t Composer::enableVSyncInjectionsImpl(bool enable) {
-    sp<ISurfaceComposer> sm(ComposerService::getComposerService());
-    return sm->enableVSyncInjections(enable);
-}
-
-status_t Composer::injectVSyncImpl(nsecs_t when) {
-    sp<ISurfaceComposer> sm(ComposerService::getComposerService());
-    return sm->injectVSync(when);
-}
-
-void Composer::setAnimationTransactionImpl() {
-    Mutex::Autolock _l(mLock);
+void SurfaceComposerClient::Transaction::setAnimationTransaction() {
     mAnimation = true;
 }
 
-layer_state_t* Composer::getLayerStateLocked(
-        const sp<SurfaceComposerClient>& client, const sp<IBinder>& id) {
-
-    ComposerState s;
-    s.client = client->mClient;
-    s.state.surface = id;
-
-    ssize_t index = mComposerStates.indexOf(s);
-    if (index < 0) {
-        // we don't have it, add an initialized layer_state to our list
-        index = mComposerStates.add(s);
-    }
-
-    ComposerState* const out = mComposerStates.editArray();
-    return &(out[index].state);
+void SurfaceComposerClient::Transaction::setEarlyWakeup() {
+    mEarlyWakeup = true;
 }
 
-status_t Composer::setPosition(const sp<SurfaceComposerClient>& client,
-        const sp<IBinder>& id, float x, float y) {
-    Mutex::Autolock _l(mLock);
-    layer_state_t* s = getLayerStateLocked(client, id);
-    if (!s)
-        return BAD_INDEX;
+layer_state_t* SurfaceComposerClient::Transaction::getLayerState(const sp<SurfaceControl>& sc) {
+    if (mComposerStates.count(sc) == 0) {
+        // we don't have it, add an initialized layer_state to our list
+        ComposerState s;
+        s.client = sc->getClient()->mClient;
+        s.state.surface = sc->getHandle();
+        mComposerStates[sc] = s;
+    }
+
+    return &(mComposerStates[sc].state);
+}
+
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setPosition(
+        const sp<SurfaceControl>& sc, float x, float y) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
     s->what |= layer_state_t::ePositionChanged;
     s->x = x;
     s->y = y;
-    return NO_ERROR;
+    return *this;
 }
 
-status_t Composer::setSize(const sp<SurfaceComposerClient>& client,
-        const sp<IBinder>& id, uint32_t w, uint32_t h) {
-    Mutex::Autolock _l(mLock);
-    layer_state_t* s = getLayerStateLocked(client, id);
-    if (!s)
-        return BAD_INDEX;
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::show(
+        const sp<SurfaceControl>& sc) {
+    return setFlags(sc, 0, layer_state_t::eLayerHidden);
+}
+
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::hide(
+        const sp<SurfaceControl>& sc) {
+    return setFlags(sc, layer_state_t::eLayerHidden, layer_state_t::eLayerHidden);
+}
+
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setSize(
+        const sp<SurfaceControl>& sc, uint32_t w, uint32_t h) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
     s->what |= layer_state_t::eSizeChanged;
     s->w = w;
     s->h = h;
@@ -331,41 +243,41 @@
     // Resizing a surface makes the transaction synchronous.
     mForceSynchronous = true;
 
-    return NO_ERROR;
+    return *this;
 }
 
-status_t Composer::setLayer(const sp<SurfaceComposerClient>& client,
-        const sp<IBinder>& id, int32_t z) {
-    Mutex::Autolock _l(mLock);
-    layer_state_t* s = getLayerStateLocked(client, id);
-    if (!s)
-        return BAD_INDEX;
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setLayer(
+        const sp<SurfaceControl>& sc, int32_t z) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
     s->what |= layer_state_t::eLayerChanged;
     s->z = z;
-    return NO_ERROR;
+    return *this;
 }
 
-status_t Composer::setRelativeLayer(const sp<SurfaceComposerClient>& client,
-        const sp<IBinder>& id, const sp<IBinder>& relativeTo,
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setRelativeLayer(const sp<SurfaceControl>& sc, const sp<IBinder>& relativeTo,
         int32_t z) {
-    Mutex::Autolock _l(mLock);
-    layer_state_t* s = getLayerStateLocked(client, id);
+    layer_state_t* s = getLayerState(sc);
     if (!s) {
-        return BAD_INDEX;
+        mStatus = BAD_INDEX;
     }
     s->what |= layer_state_t::eRelativeLayerChanged;
     s->relativeLayerHandle = relativeTo;
     s->z = z;
-    return NO_ERROR;
+    return *this;
 }
 
-status_t Composer::setFlags(const sp<SurfaceComposerClient>& client,
-        const sp<IBinder>& id, uint32_t flags,
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFlags(
+        const sp<SurfaceControl>& sc, uint32_t flags,
         uint32_t mask) {
-    Mutex::Autolock _l(mLock);
-    layer_state_t* s = getLayerStateLocked(client, id);
-    if (!s)
-        return BAD_INDEX;
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
     if ((mask & layer_state_t::eLayerOpaque) ||
             (mask & layer_state_t::eLayerHidden) ||
             (mask & layer_state_t::eLayerSecure)) {
@@ -374,50 +286,54 @@
     s->flags &= ~mask;
     s->flags |= (flags & mask);
     s->mask |= mask;
-    return NO_ERROR;
+    return *this;
 }
 
-status_t Composer::setTransparentRegionHint(
-        const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setTransparentRegionHint(
+        const sp<SurfaceControl>& sc,
         const Region& transparentRegion) {
-    Mutex::Autolock _l(mLock);
-    layer_state_t* s = getLayerStateLocked(client, id);
-    if (!s)
-        return BAD_INDEX;
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
     s->what |= layer_state_t::eTransparentRegionChanged;
     s->transparentRegion = transparentRegion;
-    return NO_ERROR;
+    return *this;
 }
 
-status_t Composer::setAlpha(const sp<SurfaceComposerClient>& client,
-        const sp<IBinder>& id, float alpha) {
-    Mutex::Autolock _l(mLock);
-    layer_state_t* s = getLayerStateLocked(client, id);
-    if (!s)
-        return BAD_INDEX;
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setAlpha(
+        const sp<SurfaceControl>& sc, float alpha) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
     s->what |= layer_state_t::eAlphaChanged;
     s->alpha = alpha;
-    return NO_ERROR;
+    return *this;
 }
 
-status_t Composer::setLayerStack(const sp<SurfaceComposerClient>& client,
-        const sp<IBinder>& id, uint32_t layerStack) {
-    Mutex::Autolock _l(mLock);
-    layer_state_t* s = getLayerStateLocked(client, id);
-    if (!s)
-        return BAD_INDEX;
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setLayerStack(
+        const sp<SurfaceControl>& sc, uint32_t layerStack) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
     s->what |= layer_state_t::eLayerStackChanged;
     s->layerStack = layerStack;
-    return NO_ERROR;
+    return *this;
 }
 
-status_t Composer::setMatrix(const sp<SurfaceComposerClient>& client,
-        const sp<IBinder>& id, float dsdx, float dtdx,
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setMatrix(
+        const sp<SurfaceControl>& sc, float dsdx, float dtdx,
         float dtdy, float dsdy) {
-    Mutex::Autolock _l(mLock);
-    layer_state_t* s = getLayerStateLocked(client, id);
-    if (!s)
-        return BAD_INDEX;
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
     s->what |= layer_state_t::eMatrixChanged;
     layer_state_t::matrix22_t matrix;
     matrix.dsdx = dsdx;
@@ -425,93 +341,115 @@
     matrix.dsdy = dsdy;
     matrix.dtdy = dtdy;
     s->matrix = matrix;
-    return NO_ERROR;
+    return *this;
 }
 
-status_t Composer::setCrop(const sp<SurfaceComposerClient>& client,
-        const sp<IBinder>& id, const Rect& crop) {
-    Mutex::Autolock _l(mLock);
-    layer_state_t* s = getLayerStateLocked(client, id);
-    if (!s)
-        return BAD_INDEX;
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setCrop(
+        const sp<SurfaceControl>& sc, const Rect& crop) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
     s->what |= layer_state_t::eCropChanged;
     s->crop = crop;
-    return NO_ERROR;
+    return *this;
 }
 
-status_t Composer::setFinalCrop(const sp<SurfaceComposerClient>& client,
-        const sp<IBinder>& id, const Rect& crop) {
-    Mutex::Autolock _l(mLock);
-    layer_state_t* s = getLayerStateLocked(client, id);
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFinalCrop(const sp<SurfaceControl>& sc, const Rect& crop) {
+    layer_state_t* s = getLayerState(sc);
     if (!s) {
-        return BAD_INDEX;
+        mStatus = BAD_INDEX;
+        return *this;
     }
     s->what |= layer_state_t::eFinalCropChanged;
     s->finalCrop = crop;
-    return NO_ERROR;
+    return *this;
 }
 
-status_t Composer::deferTransactionUntil(
-        const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::deferTransactionUntil(
+        const sp<SurfaceControl>& sc,
         const sp<IBinder>& handle, uint64_t frameNumber) {
-    Mutex::Autolock lock(mLock);
-    layer_state_t* s = getLayerStateLocked(client, id);
+    layer_state_t* s = getLayerState(sc);
     if (!s) {
-        return BAD_INDEX;
+        mStatus = BAD_INDEX;
+        return *this;
     }
     s->what |= layer_state_t::eDeferTransaction;
     s->barrierHandle = handle;
     s->frameNumber = frameNumber;
-    return NO_ERROR;
+    return *this;
 }
 
-status_t Composer::deferTransactionUntil(
-        const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::deferTransactionUntil(
+        const sp<SurfaceControl>& sc,
         const sp<Surface>& barrierSurface, uint64_t frameNumber) {
-    Mutex::Autolock lock(mLock);
-    layer_state_t* s = getLayerStateLocked(client, id);
+    layer_state_t* s = getLayerState(sc);
     if (!s) {
-        return BAD_INDEX;
+        mStatus = BAD_INDEX;
+        return *this;
     }
     s->what |= layer_state_t::eDeferTransaction;
     s->barrierGbp = barrierSurface->getIGraphicBufferProducer();
     s->frameNumber = frameNumber;
-    return NO_ERROR;
+    return *this;
 }
 
-status_t Composer::reparentChildren(
-        const sp<SurfaceComposerClient>& client,
-        const sp<IBinder>& id,
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::reparentChildren(
+        const sp<SurfaceControl>& sc,
         const sp<IBinder>& newParentHandle) {
-    Mutex::Autolock lock(mLock);
-    layer_state_t* s = getLayerStateLocked(client, id);
+    layer_state_t* s = getLayerState(sc);
     if (!s) {
-        return BAD_INDEX;
+        mStatus = BAD_INDEX;
+        return *this;
     }
     s->what |= layer_state_t::eReparentChildren;
     s->reparentHandle = newParentHandle;
-    return NO_ERROR;
+    return *this;
 }
 
-status_t Composer::detachChildren(
-        const sp<SurfaceComposerClient>& client,
-        const sp<IBinder>& id) {
-    Mutex::Autolock lock(mLock);
-    layer_state_t* s = getLayerStateLocked(client, id);
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::reparent(
+        const sp<SurfaceControl>& sc,
+        const sp<IBinder>& newParentHandle) {
+    layer_state_t* s = getLayerState(sc);
     if (!s) {
-        return BAD_INDEX;
+        mStatus = BAD_INDEX;
+        return *this;
+    }
+    s->what |= layer_state_t::eReparent;
+    s->parentHandleForChild = newParentHandle;
+    return *this;
+}
+
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setColor(
+        const sp<SurfaceControl>& sc,
+        const half3& color) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
+    s->what |= layer_state_t::eColorChanged;
+    s->color = color;
+    return *this;
+}
+
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::detachChildren(
+        const sp<SurfaceControl>& sc) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
     }
     s->what |= layer_state_t::eDetachChildren;
-    return NO_ERROR;
+    return *this;
 }
 
-status_t Composer::setOverrideScalingMode(
-        const sp<SurfaceComposerClient>& client,
-        const sp<IBinder>& id, int32_t overrideScalingMode) {
-    Mutex::Autolock lock(mLock);
-    layer_state_t* s = getLayerStateLocked(client, id);
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setOverrideScalingMode(
+        const sp<SurfaceControl>& sc, int32_t overrideScalingMode) {
+    layer_state_t* s = getLayerState(sc);
     if (!s) {
-        return BAD_INDEX;
+        mStatus = BAD_INDEX;
+        return *this;
     }
 
     switch (overrideScalingMode) {
@@ -524,29 +462,40 @@
         default:
             ALOGE("unknown scaling mode: %d",
                     overrideScalingMode);
-            return BAD_VALUE;
+            mStatus = BAD_VALUE;
+            return *this;
     }
 
     s->what |= layer_state_t::eOverrideScalingModeChanged;
     s->overrideScalingMode = overrideScalingMode;
-    return NO_ERROR;
+    return *this;
 }
 
-status_t Composer::setGeometryAppliesWithResize(
-        const sp<SurfaceComposerClient>& client,
-        const sp<IBinder>& id) {
-    Mutex::Autolock lock(mLock);
-    layer_state_t* s = getLayerStateLocked(client, id);
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setGeometryAppliesWithResize(
+        const sp<SurfaceControl>& sc) {
+    layer_state_t* s = getLayerState(sc);
     if (!s) {
-        return BAD_INDEX;
+        mStatus = BAD_INDEX;
+        return *this;
     }
     s->what |= layer_state_t::eGeometryAppliesWithResize;
-    return NO_ERROR;
+    return *this;
+}
+
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::destroySurface(
+        const sp<SurfaceControl>& sc) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
+    s->what |= layer_state_t::eDestroySurface;
+    return *this;
 }
 
 // ---------------------------------------------------------------------------
 
-DisplayState& Composer::getDisplayStateLocked(const sp<IBinder>& token) {
+DisplayState& SurfaceComposerClient::Transaction::getDisplayState(const sp<IBinder>& token) {
     DisplayState s;
     s.token = token;
     ssize_t index = mDisplayStates.indexOf(s);
@@ -558,8 +507,8 @@
     return mDisplayStates.editItemAt(static_cast<size_t>(index));
 }
 
-status_t Composer::setDisplaySurface(const sp<IBinder>& token,
-        sp<IGraphicBufferProducer> bufferProducer) {
+status_t SurfaceComposerClient::Transaction::setDisplaySurface(const sp<IBinder>& token,
+        const sp<IGraphicBufferProducer>& bufferProducer) {
     if (bufferProducer.get() != nullptr) {
         // Make sure that composition can never be stalled by a virtual display
         // consumer that isn't processing buffers fast enough.
@@ -571,27 +520,24 @@
             return err;
         }
     }
-    Mutex::Autolock _l(mLock);
-    DisplayState& s(getDisplayStateLocked(token));
+    DisplayState& s(getDisplayState(token));
     s.surface = bufferProducer;
     s.what |= DisplayState::eSurfaceChanged;
     return NO_ERROR;
 }
 
-void Composer::setDisplayLayerStack(const sp<IBinder>& token,
+void SurfaceComposerClient::Transaction::setDisplayLayerStack(const sp<IBinder>& token,
         uint32_t layerStack) {
-    Mutex::Autolock _l(mLock);
-    DisplayState& s(getDisplayStateLocked(token));
+    DisplayState& s(getDisplayState(token));
     s.layerStack = layerStack;
     s.what |= DisplayState::eLayerStackChanged;
 }
 
-void Composer::setDisplayProjection(const sp<IBinder>& token,
+void SurfaceComposerClient::Transaction::setDisplayProjection(const sp<IBinder>& token,
         uint32_t orientation,
         const Rect& layerStackRect,
         const Rect& displayRect) {
-    Mutex::Autolock _l(mLock);
-    DisplayState& s(getDisplayStateLocked(token));
+    DisplayState& s(getDisplayState(token));
     s.orientation = orientation;
     s.viewport = layerStackRect;
     s.frame = displayRect;
@@ -599,9 +545,8 @@
     mForceSynchronous = true; // TODO: do we actually still need this?
 }
 
-void Composer::setDisplaySize(const sp<IBinder>& token, uint32_t width, uint32_t height) {
-    Mutex::Autolock _l(mLock);
-    DisplayState& s(getDisplayStateLocked(token));
+void SurfaceComposerClient::Transaction::setDisplaySize(const sp<IBinder>& token, uint32_t width, uint32_t height) {
+    DisplayState& s(getDisplayState(token));
     s.width = width;
     s.height = height;
     s.what |= DisplayState::eDisplaySizeChanged;
@@ -610,23 +555,28 @@
 // ---------------------------------------------------------------------------
 
 SurfaceComposerClient::SurfaceComposerClient()
-    : mStatus(NO_INIT), mComposer(Composer::getInstance())
+    : mStatus(NO_INIT)
 {
 }
 
 SurfaceComposerClient::SurfaceComposerClient(const sp<IGraphicBufferProducer>& root)
-    : mStatus(NO_INIT), mComposer(Composer::getInstance()), mParent(root)
+    : mStatus(NO_INIT), mParent(root)
+{
+}
+
+SurfaceComposerClient::SurfaceComposerClient(const sp<ISurfaceComposerClient>& client)
+    : mStatus(NO_ERROR), mClient(client)
 {
 }
 
 void SurfaceComposerClient::onFirstRef() {
-    sp<ISurfaceComposer> sm(ComposerService::getComposerService());
-    if (sm != nullptr) {
+    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+    if (sf != 0 && mStatus == NO_INIT) {
         auto rootProducer = mParent.promote();
         sp<ISurfaceComposerClient> conn;
-        conn = (rootProducer != nullptr) ? sm->createScopedConnection(rootProducer) :
-                sm->createConnection();
-        if (conn != nullptr) {
+        conn = (rootProducer != nullptr) ? sf->createScopedConnection(rootProducer) :
+                sf->createConnection();
+        if (conn != 0) {
             mClient = conn;
             mStatus = NO_ERROR;
         }
@@ -648,15 +598,15 @@
 status_t SurfaceComposerClient::linkToComposerDeath(
         const sp<IBinder::DeathRecipient>& recipient,
         void* cookie, uint32_t flags) {
-    sp<ISurfaceComposer> sm(ComposerService::getComposerService());
-    return IInterface::asBinder(sm)->linkToDeath(recipient, cookie, flags);
+    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+    return IInterface::asBinder(sf)->linkToDeath(recipient, cookie, flags);
 }
 
 void SurfaceComposerClient::dispose() {
     // this can be called more than once.
     sp<ISurfaceComposerClient> client;
     Mutex::Autolock _lm(mLock);
-    if (mClient != nullptr) {
+    if (mClient != 0) {
         client = mClient; // hold ref while lock is held
         mClient.clear();
     }
@@ -670,10 +620,28 @@
         PixelFormat format,
         uint32_t flags,
         SurfaceControl* parent,
-        uint32_t windowType,
-        uint32_t ownerUid)
+        int32_t windowType,
+        int32_t ownerUid)
+{
+    sp<SurfaceControl> s;
+    createSurfaceChecked(name, w, h, format, &s, flags, parent, windowType, ownerUid);
+    return s;
+}
+
+status_t SurfaceComposerClient::createSurfaceChecked(
+        const String8& name,
+        uint32_t w,
+        uint32_t h,
+        PixelFormat format,
+        sp<SurfaceControl>* outSurface,
+        uint32_t flags,
+        SurfaceControl* parent,
+        int32_t windowType,
+        int32_t ownerUid)
 {
     sp<SurfaceControl> sur;
+    status_t err = mStatus;
+
     if (mStatus == NO_ERROR) {
         sp<IBinder> handle;
         sp<IBinder> parentHandle;
@@ -682,27 +650,14 @@
         if (parent != nullptr) {
             parentHandle = parent->getHandle();
         }
-        status_t err = mClient->createSurface(name, w, h, format, flags, parentHandle,
+        err = mClient->createSurface(name, w, h, format, flags, parentHandle,
                 windowType, ownerUid, &handle, &gbp);
         ALOGE_IF(err, "SurfaceComposerClient::createSurface error %s", strerror(-err));
         if (err == NO_ERROR) {
-            sur = new SurfaceControl(this, handle, gbp);
+            *outSurface = new SurfaceControl(this, handle, gbp, true /* owned */);
         }
     }
-    return sur;
-}
-
-sp<IBinder> SurfaceComposerClient::createDisplay(const String8& displayName,
-        bool secure) {
-    return Composer::getInstance().createDisplay(displayName, secure);
-}
-
-void SurfaceComposerClient::destroyDisplay(const sp<IBinder>& display) {
-    Composer::getInstance().destroyDisplay(display);
-}
-
-sp<IBinder> SurfaceComposerClient::getBuiltInDisplay(int32_t id) {
-    return Composer::getInstance().getBuiltInDisplay(id);
+    return err;
 }
 
 status_t SurfaceComposerClient::destroySurface(const sp<IBinder>& sid) {
@@ -727,152 +682,18 @@
     return mClient->getLayerFrameStats(token, outStats);
 }
 
-inline Composer& SurfaceComposerClient::getComposer() {
-    return mComposer;
-}
-
 // ----------------------------------------------------------------------------
 
-void SurfaceComposerClient::openGlobalTransaction() {
-    Composer::openGlobalTransaction();
-}
-
-void SurfaceComposerClient::closeGlobalTransaction(bool synchronous) {
-    Composer::closeGlobalTransaction(synchronous);
-}
-
-void SurfaceComposerClient::setAnimationTransaction() {
-    Composer::setAnimationTransaction();
-}
-
 status_t SurfaceComposerClient::enableVSyncInjections(bool enable) {
-    return Composer::enableVSyncInjections(enable);
+    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+    return sf->enableVSyncInjections(enable);
 }
 
 status_t SurfaceComposerClient::injectVSync(nsecs_t when) {
-    return Composer::injectVSync(when);
+    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+    return sf->injectVSync(when);
 }
 
-// ----------------------------------------------------------------------------
-
-status_t SurfaceComposerClient::setCrop(const sp<IBinder>& id, const Rect& crop) {
-    return getComposer().setCrop(this, id, crop);
-}
-
-status_t SurfaceComposerClient::setFinalCrop(const sp<IBinder>& id,
-        const Rect& crop) {
-    return getComposer().setFinalCrop(this, id, crop);
-}
-
-status_t SurfaceComposerClient::setPosition(const sp<IBinder>& id, float x, float y) {
-    return getComposer().setPosition(this, id, x, y);
-}
-
-status_t SurfaceComposerClient::setSize(const sp<IBinder>& id, uint32_t w, uint32_t h) {
-    return getComposer().setSize(this, id, w, h);
-}
-
-status_t SurfaceComposerClient::setLayer(const sp<IBinder>& id, int32_t z) {
-    return getComposer().setLayer(this, id, z);
-}
-
-status_t SurfaceComposerClient::setRelativeLayer(const sp<IBinder>& id,
-        const sp<IBinder>& relativeTo, int32_t z) {
-    return getComposer().setRelativeLayer(this, id, relativeTo, z);
-}
-
-status_t SurfaceComposerClient::hide(const sp<IBinder>& id) {
-    return getComposer().setFlags(this, id,
-            layer_state_t::eLayerHidden,
-            layer_state_t::eLayerHidden);
-}
-
-status_t SurfaceComposerClient::show(const sp<IBinder>& id) {
-    return getComposer().setFlags(this, id,
-            0,
-            layer_state_t::eLayerHidden);
-}
-
-status_t SurfaceComposerClient::setFlags(const sp<IBinder>& id, uint32_t flags,
-        uint32_t mask) {
-    return getComposer().setFlags(this, id, flags, mask);
-}
-
-status_t SurfaceComposerClient::setTransparentRegionHint(const sp<IBinder>& id,
-        const Region& transparentRegion) {
-    return getComposer().setTransparentRegionHint(this, id, transparentRegion);
-}
-
-status_t SurfaceComposerClient::setAlpha(const sp<IBinder>& id, float alpha) {
-    return getComposer().setAlpha(this, id, alpha);
-}
-
-status_t SurfaceComposerClient::setLayerStack(const sp<IBinder>& id, uint32_t layerStack) {
-    return getComposer().setLayerStack(this, id, layerStack);
-}
-
-status_t SurfaceComposerClient::setMatrix(const sp<IBinder>& id, float dsdx, float dtdx,
-        float dtdy, float dsdy) {
-    return getComposer().setMatrix(this, id, dsdx, dtdx, dtdy, dsdy);
-}
-
-status_t SurfaceComposerClient::deferTransactionUntil(const sp<IBinder>& id,
-        const sp<IBinder>& handle, uint64_t frameNumber) {
-    return getComposer().deferTransactionUntil(this, id, handle, frameNumber);
-}
-
-status_t SurfaceComposerClient::deferTransactionUntil(const sp<IBinder>& id,
-        const sp<Surface>& barrierSurface, uint64_t frameNumber) {
-    return getComposer().deferTransactionUntil(this, id, barrierSurface, frameNumber);
-}
-
-status_t SurfaceComposerClient::reparentChildren(const sp<IBinder>& id,
-        const sp<IBinder>& newParentHandle) {
-    return getComposer().reparentChildren(this, id, newParentHandle);
-}
-
-status_t SurfaceComposerClient::detachChildren(const sp<IBinder>& id) {
-    return getComposer().detachChildren(this, id);
-}
-
-status_t SurfaceComposerClient::setOverrideScalingMode(
-        const sp<IBinder>& id, int32_t overrideScalingMode) {
-    return getComposer().setOverrideScalingMode(
-            this, id, overrideScalingMode);
-}
-
-status_t SurfaceComposerClient::setGeometryAppliesWithResize(
-        const sp<IBinder>& id) {
-    return getComposer().setGeometryAppliesWithResize(this, id);
-}
-
-// ----------------------------------------------------------------------------
-
-status_t SurfaceComposerClient::setDisplaySurface(const sp<IBinder>& token,
-        sp<IGraphicBufferProducer> bufferProducer) {
-    return Composer::getInstance().setDisplaySurface(token, bufferProducer);
-}
-
-void SurfaceComposerClient::setDisplayLayerStack(const sp<IBinder>& token,
-        uint32_t layerStack) {
-    Composer::getInstance().setDisplayLayerStack(token, layerStack);
-}
-
-void SurfaceComposerClient::setDisplayProjection(const sp<IBinder>& token,
-        uint32_t orientation,
-        const Rect& layerStackRect,
-        const Rect& displayRect) {
-    Composer::getInstance().setDisplayProjection(token, orientation,
-            layerStackRect, displayRect);
-}
-
-void SurfaceComposerClient::setDisplaySize(const sp<IBinder>& token,
-        uint32_t width, uint32_t height) {
-    Composer::getInstance().setDisplaySize(token, width, height);
-}
-
-// ----------------------------------------------------------------------------
-
 status_t SurfaceComposerClient::getDisplayConfigs(
         const sp<IBinder>& display, Vector<DisplayInfo>* configs)
 {
@@ -906,16 +727,16 @@
 }
 
 status_t SurfaceComposerClient::getDisplayColorModes(const sp<IBinder>& display,
-        Vector<android_color_mode_t>* outColorModes) {
+        Vector<ColorMode>* outColorModes) {
     return ComposerService::getComposerService()->getDisplayColorModes(display, outColorModes);
 }
 
-android_color_mode_t SurfaceComposerClient::getActiveColorMode(const sp<IBinder>& display) {
+ColorMode SurfaceComposerClient::getActiveColorMode(const sp<IBinder>& display) {
     return ComposerService::getComposerService()->getActiveColorMode(display);
 }
 
 status_t SurfaceComposerClient::setActiveColorMode(const sp<IBinder>& display,
-        android_color_mode_t colorMode) {
+        ColorMode colorMode) {
     return ComposerService::getComposerService()->setActiveColorMode(display, colorMode);
 }
 
@@ -940,149 +761,37 @@
 
 // ----------------------------------------------------------------------------
 
-status_t ScreenshotClient::capture(
-        const sp<IBinder>& display,
-        const sp<IGraphicBufferProducer>& producer,
-        Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
-        int32_t minLayerZ, int32_t maxLayerZ, bool useIdentityTransform) {
+status_t ScreenshotClient::capture(const sp<IBinder>& display, Rect sourceCrop, uint32_t reqWidth,
+                                   uint32_t reqHeight, int32_t minLayerZ, int32_t maxLayerZ,
+                                   bool useIdentityTransform, uint32_t rotation,
+                                   sp<GraphicBuffer>* outBuffer) {
     sp<ISurfaceComposer> s(ComposerService::getComposerService());
-    if (s == nullptr) return NO_INIT;
-    return s->captureScreen(display, producer, sourceCrop,
-            reqWidth, reqHeight, minLayerZ, maxLayerZ, useIdentityTransform);
-}
-
-status_t ScreenshotClient::captureToBuffer(const sp<IBinder>& display,
-        Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
-        int32_t minLayerZ, int32_t maxLayerZ, bool useIdentityTransform,
-        uint32_t rotation,
-        sp<GraphicBuffer>* outBuffer) {
-    sp<ISurfaceComposer> s(ComposerService::getComposerService());
-    if (s == nullptr) return NO_INIT;
-
-    sp<IGraphicBufferConsumer> gbpConsumer;
-    sp<IGraphicBufferProducer> producer;
-    BufferQueue::createBufferQueue(&producer, &gbpConsumer);
-    sp<BufferItemConsumer> consumer(new BufferItemConsumer(gbpConsumer,
-           GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_SW_READ_NEVER | GRALLOC_USAGE_SW_WRITE_NEVER,
-           1, true));
-
-    status_t ret = s->captureScreen(display, producer, sourceCrop, reqWidth, reqHeight,
-            minLayerZ, maxLayerZ, useIdentityTransform,
-            static_cast<ISurfaceComposer::Rotation>(rotation));
+    if (s == NULL) return NO_INIT;
+    status_t ret = s->captureScreen(display, outBuffer, sourceCrop, reqWidth, reqHeight, minLayerZ,
+                                    maxLayerZ, useIdentityTransform,
+                                    static_cast<ISurfaceComposer::Rotation>(rotation));
     if (ret != NO_ERROR) {
         return ret;
     }
-    BufferItem b;
-    consumer->acquireBuffer(&b, 0, true);
-    *outBuffer = b.mGraphicBuffer;
     return ret;
 }
 
-ScreenshotClient::ScreenshotClient()
-    : mHaveBuffer(false) {
-    memset(&mBuffer, 0, sizeof(mBuffer));
-}
-
-ScreenshotClient::~ScreenshotClient() {
-    ScreenshotClient::release();
-}
-
-sp<CpuConsumer> ScreenshotClient::getCpuConsumer() const {
-    if (mCpuConsumer == nullptr) {
-        sp<IGraphicBufferConsumer> consumer;
-        BufferQueue::createBufferQueue(&mProducer, &consumer);
-        mCpuConsumer = new CpuConsumer(consumer, 1);
-        mCpuConsumer->setName(String8("ScreenshotClient"));
-    }
-    return mCpuConsumer;
-}
-
-status_t ScreenshotClient::update(const sp<IBinder>& display,
-        Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
-        int32_t minLayerZ, int32_t maxLayerZ,
-        bool useIdentityTransform, uint32_t rotation) {
+status_t ScreenshotClient::captureLayers(const sp<IBinder>& layerHandle, Rect sourceCrop,
+                                         float frameScale, sp<GraphicBuffer>* outBuffer) {
     sp<ISurfaceComposer> s(ComposerService::getComposerService());
-    if (s == nullptr) return NO_INIT;
-    sp<CpuConsumer> cpuConsumer = getCpuConsumer();
-
-    if (mHaveBuffer) {
-        mCpuConsumer->unlockBuffer(mBuffer);
-        memset(&mBuffer, 0, sizeof(mBuffer));
-        mHaveBuffer = false;
-    }
-
-    status_t err = s->captureScreen(display, mProducer, sourceCrop,
-            reqWidth, reqHeight, minLayerZ, maxLayerZ, useIdentityTransform,
-            static_cast<ISurfaceComposer::Rotation>(rotation));
-
-    if (err == NO_ERROR) {
-        err = mCpuConsumer->lockNextBuffer(&mBuffer);
-        if (err == NO_ERROR) {
-            mHaveBuffer = true;
-        }
-    }
-    return err;
+    if (s == NULL) return NO_INIT;
+    status_t ret = s->captureLayers(layerHandle, outBuffer, sourceCrop, frameScale,
+                                    false /* childrenOnly */);
+    return ret;
 }
 
-status_t ScreenshotClient::update(const sp<IBinder>& display,
-        Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
-        int32_t minLayerZ, int32_t maxLayerZ,
-        bool useIdentityTransform) {
-
-    return ScreenshotClient::update(display, sourceCrop, reqWidth, reqHeight,
-            minLayerZ, maxLayerZ, useIdentityTransform, ISurfaceComposer::eRotateNone);
+status_t ScreenshotClient::captureChildLayers(const sp<IBinder>& layerHandle, Rect sourceCrop,
+                                              float frameScale, sp<GraphicBuffer>* outBuffer) {
+    sp<ISurfaceComposer> s(ComposerService::getComposerService());
+    if (s == NULL) return NO_INIT;
+    status_t ret = s->captureLayers(layerHandle, outBuffer, sourceCrop, frameScale,
+                                    true /* childrenOnly */);
+    return ret;
 }
-
-status_t ScreenshotClient::update(const sp<IBinder>& display, Rect sourceCrop,
-        bool useIdentityTransform) {
-    return ScreenshotClient::update(display, sourceCrop, 0, 0,
-            INT32_MIN, INT32_MAX,
-            useIdentityTransform, ISurfaceComposer::eRotateNone);
-}
-
-status_t ScreenshotClient::update(const sp<IBinder>& display, Rect sourceCrop,
-        uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform) {
-    return ScreenshotClient::update(display, sourceCrop, reqWidth, reqHeight,
-            INT32_MIN, INT32_MAX,
-            useIdentityTransform, ISurfaceComposer::eRotateNone);
-}
-
-void ScreenshotClient::release() {
-    if (mHaveBuffer) {
-        mCpuConsumer->unlockBuffer(mBuffer);
-        memset(&mBuffer, 0, sizeof(mBuffer));
-        mHaveBuffer = false;
-    }
-    mCpuConsumer.clear();
-}
-
-void const* ScreenshotClient::getPixels() const {
-    return mBuffer.data;
-}
-
-uint32_t ScreenshotClient::getWidth() const {
-    return mBuffer.width;
-}
-
-uint32_t ScreenshotClient::getHeight() const {
-    return mBuffer.height;
-}
-
-PixelFormat ScreenshotClient::getFormat() const {
-    return mBuffer.format;
-}
-
-uint32_t ScreenshotClient::getStride() const {
-    return mBuffer.stride;
-}
-
-size_t ScreenshotClient::getSize() const {
-    return mBuffer.stride * mBuffer.height * bytesPerPixel(mBuffer.format);
-}
-
-android_dataspace ScreenshotClient::getDataSpace() const {
-    return mBuffer.dataSpace;
-}
-
 // ----------------------------------------------------------------------------
 }; // namespace android
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index 08e3b60..5eafbb3 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -48,8 +48,9 @@
 SurfaceControl::SurfaceControl(
         const sp<SurfaceComposerClient>& client,
         const sp<IBinder>& handle,
-        const sp<IGraphicBufferProducer>& gbp)
-    : mClient(client), mHandle(handle), mGraphicBufferProducer(gbp)
+        const sp<IGraphicBufferProducer>& gbp,
+        bool owned)
+    : mClient(client), mHandle(handle), mGraphicBufferProducer(gbp), mOwned(owned)
 {
 }
 
@@ -60,7 +61,9 @@
 
 void SurfaceControl::destroy()
 {
-    if (isValid()) {
+    // Avoid destroying the server-side surface if we are not the owner of it, meaning that we
+    // retrieved it from another process.
+    if (isValid() && mOwned) {
         mClient->destroySurface(mHandle);
     }
     // clear all references and trigger an IPC now, to make sure things
@@ -83,7 +86,7 @@
 }
 
 void SurfaceControl::disconnect() {
-    if (mGraphicBufferProducer != nullptr) {
+    if (mGraphicBufferProducer != NULL) {
         mGraphicBufferProducer->disconnect(
                 BufferQueueCore::CURRENTLY_CONNECTED_API);
     }
@@ -92,117 +95,11 @@
 bool SurfaceControl::isSameSurface(
         const sp<SurfaceControl>& lhs, const sp<SurfaceControl>& rhs)
 {
-    if (lhs == nullptr || rhs == nullptr)
+    if (lhs == 0 || rhs == 0)
         return false;
     return lhs->mHandle == rhs->mHandle;
 }
 
-status_t SurfaceControl::setLayerStack(uint32_t layerStack) {
-    status_t err = validate();
-    if (err < 0) return err;
-    return mClient->setLayerStack(mHandle, layerStack);
-}
-
-status_t SurfaceControl::setLayer(int32_t layer) {
-    status_t err = validate();
-    if (err < 0) return err;
-    return mClient->setLayer(mHandle, layer);
-}
-
-status_t SurfaceControl::setRelativeLayer(const sp<IBinder>& relativeTo, int32_t layer) {
-    status_t err = validate();
-    if (err < 0) return err;
-    return mClient->setRelativeLayer(mHandle, relativeTo, layer);
-}
-
-status_t SurfaceControl::setPosition(float x, float y) {
-    status_t err = validate();
-    if (err < 0) return err;
-    return mClient->setPosition(mHandle, x, y);
-}
-status_t SurfaceControl::setGeometryAppliesWithResize() {
-    status_t err = validate();
-    if (err < 0) return err;
-    return mClient->setGeometryAppliesWithResize(mHandle);
-}
-status_t SurfaceControl::setSize(uint32_t w, uint32_t h) {
-    status_t err = validate();
-    if (err < 0) return err;
-    return mClient->setSize(mHandle, w, h);
-}
-status_t SurfaceControl::hide() {
-    status_t err = validate();
-    if (err < 0) return err;
-    return mClient->hide(mHandle);
-}
-status_t SurfaceControl::show() {
-    status_t err = validate();
-    if (err < 0) return err;
-    return mClient->show(mHandle);
-}
-status_t SurfaceControl::setFlags(uint32_t flags, uint32_t mask) {
-    status_t err = validate();
-    if (err < 0) return err;
-    return mClient->setFlags(mHandle, flags, mask);
-}
-status_t SurfaceControl::setTransparentRegionHint(const Region& transparent) {
-    status_t err = validate();
-    if (err < 0) return err;
-    return mClient->setTransparentRegionHint(mHandle, transparent);
-}
-status_t SurfaceControl::setAlpha(float alpha) {
-    status_t err = validate();
-    if (err < 0) return err;
-    return mClient->setAlpha(mHandle, alpha);
-}
-status_t SurfaceControl::setMatrix(float dsdx, float dtdx, float dtdy, float dsdy) {
-    status_t err = validate();
-    if (err < 0) return err;
-    return mClient->setMatrix(mHandle, dsdx, dtdx, dtdy, dsdy);
-}
-status_t SurfaceControl::setCrop(const Rect& crop) {
-    status_t err = validate();
-    if (err < 0) return err;
-    return mClient->setCrop(mHandle, crop);
-}
-status_t SurfaceControl::setFinalCrop(const Rect& crop) {
-    status_t err = validate();
-    if (err < 0) return err;
-    return mClient->setFinalCrop(mHandle, crop);
-}
-
-status_t SurfaceControl::deferTransactionUntil(const sp<IBinder>& handle,
-        uint64_t frameNumber) {
-    status_t err = validate();
-    if (err < 0) return err;
-    return mClient->deferTransactionUntil(mHandle, handle, frameNumber);
-}
-
-status_t SurfaceControl::deferTransactionUntil(const sp<Surface>& handle,
-        uint64_t frameNumber) {
-    status_t err = validate();
-    if (err < 0) return err;
-    return mClient->deferTransactionUntil(mHandle, handle, frameNumber);
-}
-
-status_t SurfaceControl::reparentChildren(const sp<IBinder>& newParentHandle) {
-    status_t err = validate();
-    if (err < 0) return err;
-    return mClient->reparentChildren(mHandle, newParentHandle);
-}
-
-status_t SurfaceControl::detachChildren() {
-    status_t err = validate();
-    if (err < 0) return err;
-    return mClient->detachChildren(mHandle);
-}
-
-status_t SurfaceControl::setOverrideScalingMode(int32_t overrideScalingMode) {
-    status_t err = validate();
-    if (err < 0) return err;
-    return mClient->setOverrideScalingMode(mHandle, overrideScalingMode);
-}
-
 status_t SurfaceControl::clearLayerFrameStats() const {
     status_t err = validate();
     if (err < 0) return err;
@@ -219,7 +116,7 @@
 
 status_t SurfaceControl::validate() const
 {
-    if (mHandle==nullptr || mClient==nullptr) {
+    if (mHandle==0 || mClient==0) {
         ALOGE("invalid handle (%p) or client (%p)",
                 mHandle.get(), mClient.get());
         return NO_INIT;
@@ -231,7 +128,7 @@
         const sp<SurfaceControl>& control, Parcel* parcel)
 {
     sp<IGraphicBufferProducer> bp;
-    if (control != nullptr) {
+    if (control != NULL) {
         bp = control->mGraphicBufferProducer;
     }
     return parcel->writeStrongBinder(IInterface::asBinder(bp));
@@ -249,7 +146,7 @@
 sp<Surface> SurfaceControl::getSurface() const
 {
     Mutex::Autolock _l(mLock);
-    if (mSurfaceData == nullptr) {
+    if (mSurfaceData == 0) {
         return generateSurfaceLocked();
     }
     return mSurfaceData;
@@ -267,5 +164,35 @@
     return mHandle;
 }
 
+sp<SurfaceComposerClient> SurfaceControl::getClient() const
+{
+    return mClient;
+}
+
+void SurfaceControl::writeToParcel(Parcel* parcel)
+{
+    parcel->writeStrongBinder(ISurfaceComposerClient::asBinder(mClient->getClient()));
+    parcel->writeStrongBinder(mHandle);
+    parcel->writeStrongBinder(IGraphicBufferProducer::asBinder(mGraphicBufferProducer));
+}
+
+sp<SurfaceControl> SurfaceControl::readFromParcel(Parcel* parcel)
+{
+    sp<IBinder> client = parcel->readStrongBinder();
+    sp<IBinder> handle = parcel->readStrongBinder();
+    if (client == nullptr || handle == nullptr)
+    {
+        ALOGE("Invalid parcel");
+        return nullptr;
+    }
+    sp<IBinder> gbp;
+    parcel->readNullableStrongBinder(&gbp);
+
+    // We aren't the original owner of the surface.
+    return new SurfaceControl(new SurfaceComposerClient(
+                    interface_cast<ISurfaceComposerClient>(client)),
+            handle.get(), interface_cast<IGraphicBufferProducer>(gbp), false /* owned */);
+}
+
 // ----------------------------------------------------------------------------
 }; // namespace android
diff --git a/libs/gui/SyncFeatures.cpp b/libs/gui/SyncFeatures.cpp
index fcae05c..afa15c5 100644
--- a/libs/gui/SyncFeatures.cpp
+++ b/libs/gui/SyncFeatures.cpp
@@ -41,7 +41,7 @@
     // This can only be called after EGL has been initialized; otherwise the
     // check below will abort.
     const char* exts = eglQueryStringImplementationANDROID(dpy, EGL_EXTENSIONS);
-    LOG_ALWAYS_FATAL_IF(exts == nullptr, "eglQueryStringImplementationANDROID failed");
+    LOG_ALWAYS_FATAL_IF(exts == NULL, "eglQueryStringImplementationANDROID failed");
     if (strstr(exts, "EGL_ANDROID_native_fence_sync")) {
         // This makes GLConsumer use the EGL_ANDROID_native_fence_sync
         // extension to create Android native fences to signal when all
diff --git a/libs/gui/include/gui/BufferHubConsumer.h b/libs/gui/include/gui/BufferHubConsumer.h
new file mode 100644
index 0000000..d380770
--- /dev/null
+++ b/libs/gui/include/gui/BufferHubConsumer.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_GUI_BUFFERHUBCONSUMER_H_
+#define ANDROID_GUI_BUFFERHUBCONSUMER_H_
+
+#include <gui/IGraphicBufferConsumer.h>
+#include <private/dvr/buffer_hub_queue_client.h>
+#include <private/dvr/buffer_hub_queue_parcelable.h>
+
+namespace android {
+
+class BufferHubConsumer : public IGraphicBufferConsumer {
+public:
+    // Creates a BufferHubConsumer instance by importing an existing producer queue.
+    static sp<BufferHubConsumer> Create(const std::shared_ptr<dvr::ConsumerQueue>& queue);
+
+    // Creates a BufferHubConsumer instance by importing an existing producer
+    // parcelable. Note that this call takes the ownership of the parcelable
+    // object and is guaranteed to succeed if parcelable object is valid.
+    static sp<BufferHubConsumer> Create(dvr::ConsumerQueueParcelable parcelable);
+
+    // See |IGraphicBufferConsumer::acquireBuffer|
+    status_t acquireBuffer(BufferItem* buffer, nsecs_t presentWhen,
+                           uint64_t maxFrameNumber = 0) override;
+
+    // See |IGraphicBufferConsumer::detachBuffer|
+    status_t detachBuffer(int slot) override;
+
+    // See |IGraphicBufferConsumer::attachBuffer|
+    status_t attachBuffer(int* outSlot, const sp<GraphicBuffer>& buffer) override;
+
+    // See |IGraphicBufferConsumer::releaseBuffer|
+    status_t releaseBuffer(int buf, uint64_t frameNumber, EGLDisplay display, EGLSyncKHR fence,
+                           const sp<Fence>& releaseFence) override;
+
+    // See |IGraphicBufferConsumer::consumerConnect|
+    status_t consumerConnect(const sp<IConsumerListener>& consumer, bool controlledByApp) override;
+
+    // See |IGraphicBufferConsumer::consumerDisconnect|
+    status_t consumerDisconnect() override;
+
+    // See |IGraphicBufferConsumer::getReleasedBuffers|
+    status_t getReleasedBuffers(uint64_t* slotMask) override;
+
+    // See |IGraphicBufferConsumer::setDefaultBufferSize|
+    status_t setDefaultBufferSize(uint32_t w, uint32_t h) override;
+
+    // See |IGraphicBufferConsumer::setMaxBufferCount|
+    status_t setMaxBufferCount(int bufferCount) override;
+
+    // See |IGraphicBufferConsumer::setMaxAcquiredBufferCount|
+    status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers) override;
+
+    // See |IGraphicBufferConsumer::setConsumerName|
+    status_t setConsumerName(const String8& name) override;
+
+    // See |IGraphicBufferConsumer::setDefaultBufferFormat|
+    status_t setDefaultBufferFormat(PixelFormat defaultFormat) override;
+
+    // See |IGraphicBufferConsumer::setDefaultBufferDataSpace|
+    status_t setDefaultBufferDataSpace(android_dataspace defaultDataSpace) override;
+
+    // See |IGraphicBufferConsumer::setConsumerUsageBits|
+    status_t setConsumerUsageBits(uint64_t usage) override;
+
+    // See |IGraphicBufferConsumer::setConsumerIsProtected|
+    status_t setConsumerIsProtected(bool isProtected) override;
+
+    // See |IGraphicBufferConsumer::setTransformHint|
+    status_t setTransformHint(uint32_t hint) override;
+
+    // See |IGraphicBufferConsumer::getSidebandStream|
+    status_t getSidebandStream(sp<NativeHandle>* outStream) const override;
+
+    // See |IGraphicBufferConsumer::getOccupancyHistory|
+    status_t getOccupancyHistory(bool forceFlush,
+                                 std::vector<OccupancyTracker::Segment>* outHistory) override;
+
+    // See |IGraphicBufferConsumer::discardFreeBuffers|
+    status_t discardFreeBuffers() override;
+
+    // See |IGraphicBufferConsumer::dumpState|
+    status_t dumpState(const String8& prefix, String8* outResult) const override;
+
+    // BufferHubConsumer provides its own logic to cast to a binder object.
+    IBinder* onAsBinder() override;
+
+private:
+    // Private constructor to force use of |Create|.
+    BufferHubConsumer() = default;
+
+    // Concrete implementation backed by BufferHubBuffer.
+    std::shared_ptr<dvr::ConsumerQueue> mQueue;
+};
+
+} // namespace android
+
+#endif // ANDROID_GUI_BUFFERHUBCONSUMER_H_
diff --git a/libs/gui/include/gui/BufferHubProducer.h b/libs/gui/include/gui/BufferHubProducer.h
new file mode 100644
index 0000000..23c9909
--- /dev/null
+++ b/libs/gui/include/gui/BufferHubProducer.h
@@ -0,0 +1,219 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_GUI_BUFFERHUBPRODUCER_H_
+#define ANDROID_GUI_BUFFERHUBPRODUCER_H_
+
+#include <gui/BufferSlot.h>
+#include <gui/IGraphicBufferProducer.h>
+#include <private/dvr/buffer_hub_queue_client.h>
+#include <private/dvr/buffer_hub_queue_parcelable.h>
+
+namespace android {
+
+class BufferHubProducer : public IGraphicBufferProducer {
+public:
+    static constexpr int kNoConnectedApi = -1;
+
+    // TODO(b/36187402) The actual implementation of BufferHubQueue's consumer
+    // side logic doesn't limit the number of buffer it can acquire
+    // simultaneously. We need a way for consumer logic to configure and enforce
+    // that.
+    static constexpr int kDefaultUndequeuedBuffers = 1;
+
+    // Creates a BufferHubProducer instance by importing an existing prodcuer
+    // queue.
+    static sp<BufferHubProducer> Create(const std::shared_ptr<dvr::ProducerQueue>& producer);
+
+    // Creates a BufferHubProducer instance by importing an existing prodcuer
+    // parcelable. Note that this call takes the ownership of the parcelable
+    // object and is guaranteed to succeed if parcelable object is valid.
+    static sp<BufferHubProducer> Create(dvr::ProducerQueueParcelable parcelable);
+
+    // See |IGraphicBufferProducer::requestBuffer|
+    status_t requestBuffer(int slot, sp<GraphicBuffer>* buf) override;
+
+    // For the BufferHub based implementation. All buffers in the queue are
+    // allowed to be dequeued from the consumer side. It call always returns
+    // 0 for |NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS| query. Thus setting
+    // |max_dequeued_buffers| here can be considered the same as setting queue
+    // capacity.
+    //
+    // See |IGraphicBufferProducer::setMaxDequeuedBufferCount| for more info
+    status_t setMaxDequeuedBufferCount(int max_dequeued_buffers) override;
+
+    // See |IGraphicBufferProducer::setAsyncMode|
+    status_t setAsyncMode(bool async) override;
+
+    // See |IGraphicBufferProducer::dequeueBuffer|
+    status_t dequeueBuffer(int* out_slot, sp<Fence>* out_fence, uint32_t width, uint32_t height,
+                           PixelFormat format, uint64_t usage, uint64_t* outBufferAge,
+                           FrameEventHistoryDelta* outTimestamps) override;
+
+    // See |IGraphicBufferProducer::detachBuffer|
+    status_t detachBuffer(int slot) override;
+
+    // See |IGraphicBufferProducer::detachNextBuffer|
+    status_t detachNextBuffer(sp<GraphicBuffer>* out_buffer, sp<Fence>* out_fence) override;
+
+    // See |IGraphicBufferProducer::attachBuffer|
+    status_t attachBuffer(int* out_slot, const sp<GraphicBuffer>& buffer) override;
+
+    // See |IGraphicBufferProducer::queueBuffer|
+    status_t queueBuffer(int slot, const QueueBufferInput& input,
+                         QueueBufferOutput* output) override;
+
+    // See |IGraphicBufferProducer::cancelBuffer|
+    status_t cancelBuffer(int slot, const sp<Fence>& fence) override;
+
+    // See |IGraphicBufferProducer::query|
+    status_t query(int what, int* out_value) override;
+
+    // See |IGraphicBufferProducer::connect|
+    status_t connect(const sp<IProducerListener>& listener, int api,
+                     bool producer_controlled_by_app, QueueBufferOutput* output) override;
+
+    // See |IGraphicBufferProducer::disconnect|
+    status_t disconnect(int api, DisconnectMode mode = DisconnectMode::Api) override;
+
+    // See |IGraphicBufferProducer::setSidebandStream|
+    status_t setSidebandStream(const sp<NativeHandle>& stream) override;
+
+    // See |IGraphicBufferProducer::allocateBuffers|
+    void allocateBuffers(uint32_t width, uint32_t height, PixelFormat format,
+                         uint64_t usage) override;
+
+    // See |IGraphicBufferProducer::allowAllocation|
+    status_t allowAllocation(bool allow) override;
+
+    // See |IGraphicBufferProducer::setGenerationNumber|
+    status_t setGenerationNumber(uint32_t generation_number) override;
+
+    // See |IGraphicBufferProducer::getConsumerName|
+    String8 getConsumerName() const override;
+
+    // See |IGraphicBufferProducer::setSharedBufferMode|
+    status_t setSharedBufferMode(bool shared_buffer_mode) override;
+
+    // See |IGraphicBufferProducer::setAutoRefresh|
+    status_t setAutoRefresh(bool auto_refresh) override;
+
+    // See |IGraphicBufferProducer::setDequeueTimeout|
+    status_t setDequeueTimeout(nsecs_t timeout) override;
+
+    // See |IGraphicBufferProducer::getLastQueuedBuffer|
+    status_t getLastQueuedBuffer(sp<GraphicBuffer>* out_buffer, sp<Fence>* out_fence,
+                                 float out_transform_matrix[16]) override;
+
+    // See |IGraphicBufferProducer::getFrameTimestamps|
+    void getFrameTimestamps(FrameEventHistoryDelta* /*outDelta*/) override;
+
+    // See |IGraphicBufferProducer::getUniqueId|
+    status_t getUniqueId(uint64_t* out_id) const override;
+
+    // See |IGraphicBufferProducer::getConsumerUsage|
+    status_t getConsumerUsage(uint64_t* out_usage) const override;
+
+    // Takes out the current producer as a binder parcelable object. Note that the
+    // producer must be disconnected to be exportable. After successful export,
+    // the producer queue can no longer be connected again. Returns NO_ERROR when
+    // takeout is successful and out_parcelable will hold the new parcelable
+    // object. Also note that out_parcelable cannot be NULL and must points to an
+    // invalid parcelable.
+    status_t TakeAsParcelable(dvr::ProducerQueueParcelable* out_parcelable);
+
+    IBinder* onAsBinder() override;
+
+protected:
+    // See |IGraphicBufferProducer::exportToParcel|
+    status_t exportToParcel(Parcel* parcel) override;
+
+private:
+    using LocalHandle = pdx::LocalHandle;
+
+    // Private constructor to force use of |Create|.
+    BufferHubProducer() {}
+
+    static uint64_t genUniqueId() {
+        static std::atomic<uint32_t> counter{0};
+        static uint64_t id = static_cast<uint64_t>(getpid()) << 32;
+        return id | counter++;
+    }
+
+    // Allocate new buffer through BufferHub and add it into |queue_| for
+    // bookkeeping.
+    status_t AllocateBuffer(uint32_t width, uint32_t height, uint32_t layer_count,
+                            PixelFormat format, uint64_t usage);
+
+    // Remove a buffer via BufferHubRPC.
+    status_t RemoveBuffer(size_t slot);
+
+    // Free all buffers which are owned by the prodcuer. Note that if graphic
+    // buffers are acquired by the consumer, we can't .
+    status_t FreeAllBuffers();
+
+    // Concreate implementation backed by BufferHubBuffer.
+    std::shared_ptr<dvr::ProducerQueue> queue_;
+
+    // Mutex for thread safety.
+    std::mutex mutex_;
+
+    // Connect client API, should be one of the NATIVE_WINDOW_API_* flags.
+    int connected_api_{kNoConnectedApi};
+
+    // |max_buffer_count_| sets the capacity of the underlying buffer queue.
+    int32_t max_buffer_count_{dvr::BufferHubQueue::kMaxQueueCapacity};
+
+    // |max_dequeued_buffer_count_| set the maximum number of buffers that can
+    // be dequeued at the same momment.
+    int32_t max_dequeued_buffer_count_{1};
+
+    // Sets how long dequeueBuffer or attachBuffer will block if a buffer or
+    // slot is not yet available. The timeout is stored in milliseconds.
+    int dequeue_timeout_ms_{dvr::BufferHubQueue::kNoTimeOut};
+
+    // |generation_number_| stores the current generation number of the attached
+    // producer. Any attempt to attach a buffer with a different generation
+    // number will fail.
+    // TOOD(b/38137191) Currently not used as we don't support
+    // IGraphicBufferProducer::detachBuffer.
+    uint32_t generation_number_{0};
+
+    // |buffers_| stores the buffers that have been dequeued from
+    // |dvr::BufferHubQueue|, It is initialized to invalid buffers, and gets
+    // filled in with the result of |Dequeue|.
+    // TODO(jwcai) The buffer allocated to a slot will also be replaced if the
+    // requested buffer usage or geometry differs from that of the buffer
+    // allocated to a slot.
+    struct BufferHubSlot : public BufferSlot {
+        BufferHubSlot() : mBufferProducer(nullptr), mIsReallocating(false) {}
+        // BufferSlot comes from android framework, using m prefix to comply with
+        // the name convention with the reset of data fields from BufferSlot.
+        std::shared_ptr<dvr::BufferProducer> mBufferProducer;
+        bool mIsReallocating;
+    };
+    BufferHubSlot buffers_[dvr::BufferHubQueue::kMaxQueueCapacity];
+
+    // A uniqueId used by IGraphicBufferProducer interface.
+    const uint64_t unique_id_{genUniqueId()};
+
+    // A pending parcelable object which keeps the bufferhub channel alive.
+    dvr::ProducerQueueParcelable pending_producer_parcelable_;
+};
+
+} // namespace android
+
+#endif // ANDROID_GUI_BUFFERHUBPRODUCER_H_
diff --git a/libs/gui/include/gui/BufferItem.h b/libs/gui/include/gui/BufferItem.h
index 55637a9..218bb42 100644
--- a/libs/gui/include/gui/BufferItem.h
+++ b/libs/gui/include/gui/BufferItem.h
@@ -17,6 +17,8 @@
 #ifndef ANDROID_GUI_BUFFERITEM_H
 #define ANDROID_GUI_BUFFERITEM_H
 
+#include <gui/HdrMetadata.h>
+
 #include <ui/FenceTime.h>
 #include <ui/Rect.h>
 #include <ui/Region.h>
@@ -86,6 +88,9 @@
     // dataSpace is format-dependent.
     android_dataspace mDataSpace;
 
+    // mHdrMetadata is the HDR metadata associated with this buffer slot.
+    HdrMetadata mHdrMetadata;
+
     // mFrameNumber is the number of the queued frame for this slot.
     uint64_t mFrameNumber;
 
@@ -122,6 +127,9 @@
     // Indicates that this BufferItem contains a stale buffer which has already
     // been released by the BufferQueue.
     bool mIsStale;
+
+    // Indicates the API (NATIVE_WINDOW_API_xxx) that queues the buffer.
+    int mApi;
 };
 
 } // namespace android
diff --git a/libs/gui/include/gui/BufferItemConsumer.h b/libs/gui/include/gui/BufferItemConsumer.h
index d9c5775..a905610 100644
--- a/libs/gui/include/gui/BufferItemConsumer.h
+++ b/libs/gui/include/gui/BufferItemConsumer.h
@@ -57,10 +57,6 @@
 
     ~BufferItemConsumer() override;
 
-    // set the name of the BufferItemConsumer that will be used to identify it in
-    // 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);
diff --git a/libs/gui/include/gui/BufferQueue.h b/libs/gui/include/gui/BufferQueue.h
index ba5cbf7..da95274 100644
--- a/libs/gui/include/gui/BufferQueue.h
+++ b/libs/gui/include/gui/BufferQueue.h
@@ -79,6 +79,12 @@
             sp<IGraphicBufferConsumer>* outConsumer,
             bool consumerIsSurfaceFlinger = false);
 
+#ifndef NO_BUFFERHUB
+    // Creates an IGraphicBufferProducer and IGraphicBufferConsumer pair backed by BufferHub.
+    static void createBufferHubQueue(sp<IGraphicBufferProducer>* outProducer,
+                                     sp<IGraphicBufferConsumer>* outConsumer);
+#endif
+
     BufferQueue() = delete; // Create through createBufferQueue
 };
 
diff --git a/libs/gui/include/gui/ConsumerBase.h b/libs/gui/include/gui/ConsumerBase.h
index e9fc8fd..366ced3 100644
--- a/libs/gui/include/gui/ConsumerBase.h
+++ b/libs/gui/include/gui/ConsumerBase.h
@@ -89,6 +89,18 @@
     // See IGraphicBufferConsumer::setDefaultBufferDataSpace
     status_t setDefaultBufferDataSpace(android_dataspace defaultDataSpace);
 
+    // See IGraphicBufferConsumer::setConsumerUsageBits
+    status_t setConsumerUsageBits(uint64_t usage);
+
+    // See IGraphicBufferConsumer::setTransformHint
+    status_t setTransformHint(uint32_t hint);
+
+    // See IGraphicBufferConsumer::setMaxAcquiredBufferCount
+    status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers);
+
+    // See IGraphicBufferConsumer::getSidebandStream
+    sp<NativeHandle> getSidebandStream() const;
+
     // See IGraphicBufferConsumer::getOccupancyHistory
     status_t getOccupancyHistory(bool forceFlush,
             std::vector<OccupancyTracker::Segment>* outHistory);
@@ -187,7 +199,7 @@
     // ConsumerBase::releaseBufferLocked.
     virtual status_t releaseBufferLocked(int slot,
             const sp<GraphicBuffer> graphicBuffer,
-            EGLDisplay display, EGLSyncKHR eglFence);
+            EGLDisplay display = EGL_NO_DISPLAY, EGLSyncKHR eglFence = EGL_NO_SYNC_KHR);
 
     // returns true iff the slot still has the graphicBuffer in it.
     bool stillTracking(int slot, const sp<GraphicBuffer> graphicBuffer);
diff --git a/libs/gui/include/gui/CpuConsumer.h b/libs/gui/include/gui/CpuConsumer.h
index 58602bf..d375611 100644
--- a/libs/gui/include/gui/CpuConsumer.h
+++ b/libs/gui/include/gui/CpuConsumer.h
@@ -94,12 +94,6 @@
     CpuConsumer(const sp<IGraphicBufferConsumer>& bq,
             size_t maxLockedBuffers, bool controlledByApp = false);
 
-    virtual ~CpuConsumer();
-
-    // set the name of the CpuConsumer that will be used to identify it in
-    // log messages.
-    void setName(const String8& name);
-
     // Gets the next graphics buffer from the producer and locks it for CPU use,
     // filling out the passed-in locked buffer structure with the native pointer
     // and metadata. Returns BAD_VALUE if no new buffer is available, and
@@ -119,31 +113,39 @@
 
   private:
     // Maximum number of buffers that can be locked at a time
-    size_t mMaxLockedBuffers;
-
-    status_t releaseAcquiredBufferLocked(size_t lockedIdx);
-
-    virtual void freeBufferLocked(int slotIndex);
+    const size_t mMaxLockedBuffers;
 
     // Tracking for buffers acquired by the user
     struct AcquiredBuffer {
+        static constexpr uintptr_t kUnusedId = 0;
+
         // Need to track the original mSlot index and the buffer itself because
         // the mSlot entry may be freed/reused before the acquired buffer is
         // released.
         int mSlot;
         sp<GraphicBuffer> mGraphicBuffer;
-        void *mBufferPointer;
+        uintptr_t mLockedBufferId;
 
         AcquiredBuffer() :
                 mSlot(BufferQueue::INVALID_BUFFER_SLOT),
-                mBufferPointer(NULL) {
+                mLockedBufferId(kUnusedId) {
+        }
+
+        void reset() {
+            mSlot = BufferQueue::INVALID_BUFFER_SLOT;
+            mGraphicBuffer.clear();
+            mLockedBufferId = kUnusedId;
         }
     };
+
+    size_t findAcquiredBufferLocked(uintptr_t id) const;
+
+    status_t lockBufferItem(const BufferItem& item, LockedBuffer* outBuffer) const;
+
     Vector<AcquiredBuffer> mAcquiredBuffers;
 
     // Count of currently locked buffers
     size_t mCurrentLockedBuffers;
-
 };
 
 } // namespace android
diff --git a/libs/gui/include/gui/GLConsumer.h b/libs/gui/include/gui/GLConsumer.h
index 75f2cca..71ed3bf 100644
--- a/libs/gui/include/gui/GLConsumer.h
+++ b/libs/gui/include/gui/GLConsumer.h
@@ -138,6 +138,10 @@
             const sp<GraphicBuffer>& buf, const Rect& cropRect,
             uint32_t transform, bool filtering);
 
+    // Scale the crop down horizontally or vertically such that it has the
+    // same aspect ratio as the buffer does.
+    static Rect scaleDownCrop(const Rect& crop, uint32_t bufferWidth, uint32_t bufferHeight);
+
     // getTimestamp retrieves the timestamp associated with the texture image
     // set by the most recent call to updateTexImage.
     //
@@ -197,22 +201,9 @@
     // buffer is ready to be read from.
     std::shared_ptr<FenceTime> getCurrentFenceTime() const;
 
-    // doGLFenceWait inserts a wait command into the OpenGL ES command stream
-    // to ensure that it is safe for future OpenGL ES commands to access the
-    // current texture buffer.
-    status_t doGLFenceWait() const;
-
-    // set the name of the GLConsumer that will be used to identify it in
-    // log messages.
-    void setName(const String8& name);
-
-    // These functions call the corresponding BufferQueue implementation
-    // so the refactoring can proceed smoothly
-    status_t setDefaultBufferFormat(PixelFormat defaultFormat);
-    status_t setDefaultBufferDataSpace(android_dataspace defaultDataSpace);
+    // setConsumerUsageBits overrides the ConsumerBase method to OR
+    // DEFAULT_USAGE_FLAGS to usage.
     status_t setConsumerUsageBits(uint64_t usage);
-    status_t setTransformHint(uint32_t hint);
-    status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers);
 
     // detachFromContext detaches the GLConsumer from the calling thread's
     // current OpenGL ES context.  This context must be the same as the context
@@ -267,8 +258,6 @@
         return releaseBufferLocked(slot, graphicBuffer, mEglDisplay, eglFence);
     }
 
-    static bool isExternalFormat(PixelFormat format);
-
     struct PendingRelease {
         PendingRelease() : isPending(false), currentTexture(-1),
                 graphicBuffer(), display(nullptr), fence(nullptr) {}
diff --git a/libs/gui/include/gui/HdrMetadata.h b/libs/gui/include/gui/HdrMetadata.h
new file mode 100644
index 0000000..9800602
--- /dev/null
+++ b/libs/gui/include/gui/HdrMetadata.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+#include <system/graphics.h>
+#include <utils/Flattenable.h>
+
+namespace android {
+
+struct HdrMetadata : public LightFlattenable<HdrMetadata> {
+    enum Type : uint32_t {
+        SMPTE2086 = 1 << 0,
+        CTA861_3  = 1 << 1,
+    };
+    uint32_t validTypes{0};
+
+    android_smpte2086_metadata smpte2086{};
+    android_cta861_3_metadata cta8613{};
+
+    // LightFlattenable
+    bool isFixedSize() const { return false; }
+    size_t getFlattenedSize() const;
+    status_t flatten(void* buffer, size_t size) const;
+    status_t unflatten(void const* buffer, size_t size);
+
+    bool operator==(const HdrMetadata& rhs) const;
+};
+
+} // namespace android
diff --git a/libs/gui/include/gui/IGraphicBufferProducer.h b/libs/gui/include/gui/IGraphicBufferProducer.h
index 039dc0d..887654e 100644
--- a/libs/gui/include/gui/IGraphicBufferProducer.h
+++ b/libs/gui/include/gui/IGraphicBufferProducer.h
@@ -31,6 +31,7 @@
 #include <ui/Region.h>
 
 #include <gui/FrameTimestamps.h>
+#include <gui/HdrMetadata.h>
 
 #include <hidl/HybridInterface.h>
 #include <android/hardware/graphics/bufferqueue/1.0/IGraphicBufferProducer.h>
@@ -72,6 +73,14 @@
         RELEASE_ALL_BUFFERS       = 0x2,
     };
 
+    enum {
+        // A parcelable magic indicates using Binder BufferQueue as transport
+        // backend.
+        USE_BUFFER_QUEUE = 0x62717565, // 'bque'
+        // A parcelable magic indicates using BufferHub as transport backend.
+        USE_BUFFER_HUB = 0x62687562, // 'bhub'
+    };
+
     // requestBuffer requests a new buffer for the given index. The server (i.e.
     // the IGraphicBufferProducer implementation) assigns the newly created
     // buffer to the given slot index, and the client is expected to mirror the
@@ -354,6 +363,9 @@
         const Region& getSurfaceDamage() const { return surfaceDamage; }
         void setSurfaceDamage(const Region& damage) { surfaceDamage = damage; }
 
+        const HdrMetadata& getHdrMetadata() const { return hdrMetadata; }
+        void setHdrMetadata(const HdrMetadata& metadata) { hdrMetadata = metadata; }
+
     private:
         int64_t timestamp{0};
         int isAutoTimestamp{0};
@@ -365,6 +377,7 @@
         sp<Fence> fence;
         Region surfaceDamage;
         bool getFrameTimestamps{false};
+        HdrMetadata hdrMetadata;
     };
 
     struct QueueBufferOutput : public Flattenable<QueueBufferOutput> {
@@ -599,6 +612,24 @@
     // returned by querying the now deprecated
     // NATIVE_WINDOW_CONSUMER_USAGE_BITS attribute.
     virtual status_t getConsumerUsage(uint64_t* outUsage) const = 0;
+
+    // Static method exports any IGraphicBufferProducer object to a parcel. It
+    // handles null producer as well.
+    static status_t exportToParcel(const sp<IGraphicBufferProducer>& producer,
+                                   Parcel* parcel);
+
+    // Factory method that creates a new IBGP instance from the parcel.
+    static sp<IGraphicBufferProducer> createFromParcel(const Parcel* parcel);
+
+protected:
+    // Exports the current producer as a binder parcelable object. Note that the
+    // producer must be disconnected to be exportable. After successful export,
+    // the producer queue can no longer be connected again. Returns NO_ERROR
+    // when the export is successful and writes an implementation defined
+    // parcelable object into the parcel. For traditional Android BufferQueue,
+    // it writes a strong binder object; for BufferHub, it writes a
+    // ProducerQueueParcelable object.
+    virtual status_t exportToParcel(Parcel* parcel);
 };
 
 // ----------------------------------------------------------------------------
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index b226742..e401572 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -29,6 +29,8 @@
 
 #include <ui/FrameStats.h>
 #include <ui/PixelFormat.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/GraphicTypes.h>
 
 #include <vector>
 
@@ -59,6 +61,11 @@
     enum {
         eSynchronous = 0x01,
         eAnimation   = 0x02,
+
+        // Indicates that this transaction will likely result in a lot of layers being composed, and
+        // thus, SurfaceFlinger should wake-up earlier to avoid missing frame deadlines. In this
+        // case SurfaceFlinger will wake up at (sf vsync offset - debug.sf.early_phase_offset_ns)
+        eEarlyWakeup = 0x04
     };
 
     enum {
@@ -159,20 +166,25 @@
     virtual status_t setActiveConfig(const sp<IBinder>& display, int id) = 0;
 
     virtual status_t getDisplayColorModes(const sp<IBinder>& display,
-            Vector<android_color_mode_t>* outColorModes) = 0;
-    virtual android_color_mode_t getActiveColorMode(const sp<IBinder>& display) = 0;
+            Vector<ui::ColorMode>* outColorModes) = 0;
+    virtual ui::ColorMode getActiveColorMode(const sp<IBinder>& display) = 0;
     virtual status_t setActiveColorMode(const sp<IBinder>& display,
-            android_color_mode_t colorMode) = 0;
+            ui::ColorMode colorMode) = 0;
 
     /* Capture the specified screen. requires READ_FRAME_BUFFER permission
      * This function will fail if there is a secure window on screen.
      */
-    virtual status_t captureScreen(const sp<IBinder>& display,
-            const sp<IGraphicBufferProducer>& producer,
-            Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
-            int32_t minLayerZ, int32_t maxLayerZ,
-            bool useIdentityTransform,
-            Rotation rotation = eRotateNone) = 0;
+    virtual status_t captureScreen(const sp<IBinder>& display, sp<GraphicBuffer>* outBuffer,
+                                   Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
+                                   int32_t minLayerZ, int32_t maxLayerZ, bool useIdentityTransform,
+                                   Rotation rotation = eRotateNone) = 0;
+
+    /**
+     * Capture a subtree of the layer hierarchy, potentially ignoring the root node.
+     */
+    virtual status_t captureLayers(const sp<IBinder>& layerHandleBinder,
+                                   sp<GraphicBuffer>* outBuffer, const Rect& sourceCrop,
+                                   float frameScale = 1.0, bool childrenOnly = false) = 0;
 
     /* Clears the frame statistics for animations.
      *
@@ -226,6 +238,7 @@
         SET_ACTIVE_CONFIG,
         CONNECT_DISPLAY,
         CAPTURE_SCREEN,
+        CAPTURE_LAYERS,
         CLEAR_ANIMATION_FRAME_STATS,
         GET_ANIMATION_FRAME_STATS,
         SET_POWER_MODE,
diff --git a/libs/gui/include/gui/ISurfaceComposerClient.h b/libs/gui/include/gui/ISurfaceComposerClient.h
index 2c613ea..8dfc99a 100644
--- a/libs/gui/include/gui/ISurfaceComposerClient.h
+++ b/libs/gui/include/gui/ISurfaceComposerClient.h
@@ -41,7 +41,7 @@
         eCursorWindow = 0x00002000,
 
         eFXSurfaceNormal = 0x00000000,
-        eFXSurfaceDim = 0x00020000,
+        eFXSurfaceColor = 0x00020000,
         eFXSurfaceMask = 0x000F0000,
     };
 
@@ -49,8 +49,8 @@
      * Requires ACCESS_SURFACE_FLINGER permission
      */
     virtual status_t createSurface(const String8& name, uint32_t w, uint32_t h, PixelFormat format,
-                                   uint32_t flags, const sp<IBinder>& parent, uint32_t windowType,
-                                   uint32_t ownerUid, sp<IBinder>* handle,
+                                   uint32_t flags, const sp<IBinder>& parent, int32_t windowType,
+                                   int32_t ownerUid, sp<IBinder>* handle,
                                    sp<IGraphicBufferProducer>* gbp) = 0;
 
     /*
diff --git a/libs/gui/include/gui/LayerDebugInfo.h b/libs/gui/include/gui/LayerDebugInfo.h
index 8453e04..92bd8c5 100644
--- a/libs/gui/include/gui/LayerDebugInfo.h
+++ b/libs/gui/include/gui/LayerDebugInfo.h
@@ -22,6 +22,7 @@
 #include <ui/Region.h>
 
 #include <string>
+#include <math/vec4.h>
 
 namespace android {
 
@@ -52,7 +53,7 @@
     int32_t mHeight = -1;
     Rect mCrop = Rect::INVALID_RECT;
     Rect mFinalCrop = Rect::INVALID_RECT;
-    float mAlpha = 0.f;
+    half4 mColor = half4(1.0_hf, 1.0_hf, 1.0_hf, 0.0_hf);
     uint32_t mFlags = 0;
     PixelFormat mPixelFormat = PIXEL_FORMAT_NONE;
     android_dataspace mDataSpace = HAL_DATASPACE_UNKNOWN;
diff --git a/libs/gui/include/private/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
similarity index 84%
rename from libs/gui/include/private/gui/LayerState.h
rename to libs/gui/include/gui/LayerState.h
index 307c764..788962e 100644
--- a/libs/gui/include/private/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -25,6 +25,7 @@
 #include <ui/Region.h>
 #include <ui/Rect.h>
 #include <gui/IGraphicBufferProducer.h>
+#include <math/vec3.h>
 
 namespace android {
 
@@ -59,7 +60,10 @@
         eGeometryAppliesWithResize  = 0x00001000,
         eReparentChildren           = 0x00002000,
         eDetachChildren             = 0x00004000,
-        eRelativeLayerChanged       = 0x00008000
+        eRelativeLayerChanged       = 0x00008000,
+        eReparent                   = 0x00010000,
+        eColorChanged               = 0x00020000,
+        eDestroySurface             = 0x00040000
     };
 
     layer_state_t()
@@ -74,6 +78,7 @@
         matrix.dsdy = matrix.dtdx = 0.0f;
     }
 
+    void merge(const layer_state_t& other);
     status_t    write(Parcel& output) const;
     status_t    read(const Parcel& input);
 
@@ -107,6 +112,10 @@
 
             sp<IBinder>     relativeLayerHandle;
 
+            sp<IBinder>     parentHandleForChild;
+
+            half3           color;
+
             // non POD must be last. see write/read
             Region          transparentRegion;
 };
@@ -137,6 +146,7 @@
     };
 
     DisplayState();
+    void merge(const DisplayState& other);
 
     uint32_t what;
     sp<IBinder> token;
@@ -150,6 +160,20 @@
     status_t read(const Parcel& input);
 };
 
+static inline
+int compare_type(const ComposerState& lhs, const ComposerState& rhs) {
+    if (lhs.client < rhs.client) return -1;
+    if (lhs.client > rhs.client) return 1;
+    if (lhs.state.surface < rhs.state.surface)  return -1;
+    if (lhs.state.surface > rhs.state.surface)  return 1;
+    return 0;
+}
+
+static inline
+int compare_type(const DisplayState& lhs, const DisplayState& rhs) {
+    return compare_type(lhs.token, rhs.token);
+}
+
 }; // namespace android
 
 #endif // ANDROID_SF_LAYER_STATE_H
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index 55dd6bf..9aeafae 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -17,10 +17,12 @@
 #ifndef ANDROID_GUI_SURFACE_H
 #define ANDROID_GUI_SURFACE_H
 
-#include <gui/IGraphicBufferProducer.h>
 #include <gui/BufferQueueDefs.h>
+#include <gui/HdrMetadata.h>
+#include <gui/IGraphicBufferProducer.h>
 
 #include <ui/ANativeObjectBase.h>
+#include <ui/GraphicTypes.h>
 #include <ui/Region.h>
 
 #include <utils/Condition.h>
@@ -214,6 +216,8 @@
     int dispatchUnlockAndPost(va_list args);
     int dispatchSetSidebandStream(va_list args);
     int dispatchSetBuffersDataSpace(va_list args);
+    int dispatchSetBuffersSmpte2086Metadata(va_list args);
+    int dispatchSetBuffersCta8613Metadata(va_list args);
     int dispatchSetSurfaceDamage(va_list args);
     int dispatchSetSharedBufferMode(va_list args);
     int dispatchSetAutoRefresh(va_list args);
@@ -242,7 +246,9 @@
     virtual int setBuffersTransform(uint32_t transform);
     virtual int setBuffersStickyTransform(uint32_t transform);
     virtual int setBuffersTimestamp(int64_t timestamp);
-    virtual int setBuffersDataSpace(android_dataspace dataSpace);
+    virtual int setBuffersDataSpace(ui::Dataspace dataSpace);
+    virtual int setBuffersSmpte2086Metadata(const android_smpte2086_metadata* metadata);
+    virtual int setBuffersCta8613Metadata(const android_cta861_3_metadata* metadata);
     virtual int setCrop(Rect const* rect);
     virtual int setUsage(uint64_t reqUsage);
     virtual void setSurfaceDamage(android_native_rect_t* rects, size_t numRects);
@@ -281,6 +287,10 @@
     // detachNextBuffer, or attachBuffer call.
     status_t getAndFlushRemovedBuffers(std::vector<sp<GraphicBuffer>>* out);
 
+    ui::Dataspace getBuffersDataSpace();
+
+    static status_t attachAndQueueBuffer(Surface* surface, sp<GraphicBuffer> buffer);
+
 protected:
     enum { NUM_BUFFER_SLOTS = BufferQueueDefs::NUM_BUFFER_SLOTS };
     enum { DEFAULT_FORMAT = PIXEL_FORMAT_RGBA_8888 };
@@ -331,9 +341,13 @@
     int64_t mTimestamp;
 
     // mDataSpace is the buffer dataSpace that will be used for the next buffer
-    // queue operation. It defaults to HAL_DATASPACE_UNKNOWN, which
+    // queue operation. It defaults to Dataspace::UNKNOWN, which
     // means that the buffer contains some type of color data.
-    android_dataspace mDataSpace;
+    ui::Dataspace mDataSpace;
+
+    // mHdrMetadata is the HDR metadata that will be used for the next buffer
+    // queue operation.  There is no HDR metadata by default.
+    HdrMetadata mHdrMetadata;
 
     // mCrop is the crop rectangle that will be used for the next buffer
     // that gets queued. It is set by calling setCrop.
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 145c059..377fe68 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -19,6 +19,7 @@
 
 #include <stdint.h>
 #include <sys/types.h>
+#include <unordered_map>
 
 #include <binder/IBinder.h>
 
@@ -28,17 +29,19 @@
 #include <utils/threads.h>
 
 #include <ui/FrameStats.h>
+#include <ui/GraphicTypes.h>
 #include <ui/PixelFormat.h>
 
 #include <gui/CpuConsumer.h>
 #include <gui/SurfaceControl.h>
+#include <math/vec3.h>
+#include <gui/LayerState.h>
 
 namespace android {
 
 // ---------------------------------------------------------------------------
 
 struct DisplayInfo;
-class Composer;
 class HdrCapabilities;
 class ISurfaceComposerClient;
 class IGraphicBufferProducer;
@@ -51,6 +54,7 @@
     friend class Composer;
 public:
                 SurfaceComposerClient();
+                SurfaceComposerClient(const sp<ISurfaceComposerClient>& client);
                 SurfaceComposerClient(const sp<IGraphicBufferProducer>& parent);
     virtual     ~SurfaceComposerClient();
 
@@ -85,13 +89,14 @@
 
     // Gets the list of supported color modes for the given display
     static status_t getDisplayColorModes(const sp<IBinder>& display,
-            Vector<android_color_mode_t>* outColorModes);
+            Vector<ui::ColorMode>* outColorModes);
 
     // Gets the active color mode for the given display
-    static android_color_mode_t getActiveColorMode(const sp<IBinder>& display);
+    static ui::ColorMode getActiveColorMode(const sp<IBinder>& display);
 
     // Sets the active color mode for the given display
-    static status_t setActiveColorMode(const sp<IBinder>& display, android_color_mode_t colorMode);
+    static status_t setActiveColorMode(const sp<IBinder>& display,
+            ui::ColorMode colorMode);
 
     /* Triggers screen on/off or low power mode and waits for it to complete */
     static void setDisplayPowerMode(const sp<IBinder>& display, int mode);
@@ -107,8 +112,20 @@
             PixelFormat format, // pixel-format desired
             uint32_t flags = 0, // usage flags
             SurfaceControl* parent = nullptr, // parent
-            uint32_t windowType = 0, // from WindowManager.java (STATUS_BAR, INPUT_METHOD, etc.)
-            uint32_t ownerUid = 0 // UID of the task
+            int32_t windowType = -1, // from WindowManager.java (STATUS_BAR, INPUT_METHOD, etc.)
+            int32_t ownerUid = -1 // UID of the task
+    );
+
+    status_t createSurfaceChecked(
+            const String8& name,// name of the surface
+            uint32_t w,         // width in pixel
+            uint32_t h,         // height in pixel
+            PixelFormat format, // pixel-format desired
+            sp<SurfaceControl>* outSurface,
+            uint32_t flags = 0, // usage flags
+            SurfaceControl* parent = nullptr, // parent
+            int32_t windowType = -1, // from WindowManager.java (STATUS_BAR, INPUT_METHOD, etc.)
+            int32_t ownerUid = -1 // UID of the task
     );
 
     //! Create a virtual display
@@ -121,157 +138,185 @@
     //! Possible values for id are eDisplayIdMain and eDisplayIdHdmi.
     static sp<IBinder> getBuiltInDisplay(int32_t id);
 
-    // ------------------------------------------------------------------------
-    // Composer parameters
-    // All composer parameters must be changed within a transaction
-    // several surfaces can be updated in one transaction, all changes are
-    // committed at once when the transaction is closed.
-    // closeGlobalTransaction() requires an IPC with the server.
-
-    //! Open a composer transaction on all active SurfaceComposerClients.
-    static void openGlobalTransaction();
-
-    //! Close a composer transaction on all active SurfaceComposerClients.
-    static void closeGlobalTransaction(bool synchronous = false);
-
     static status_t enableVSyncInjections(bool enable);
 
     static status_t injectVSync(nsecs_t when);
 
-    //! Flag the currently open transaction as an animation transaction.
-    static void setAnimationTransaction();
+    struct SCHash {
+        std::size_t operator()(const sp<SurfaceControl>& sc) const {
+            return std::hash<SurfaceControl *>{}(sc.get());
+        }
+    };
 
-    status_t    hide(const sp<IBinder>& id);
-    status_t    show(const sp<IBinder>& id);
-    status_t    setFlags(const sp<IBinder>& id, uint32_t flags, uint32_t mask);
-    status_t    setTransparentRegionHint(const sp<IBinder>& id, const Region& transparent);
-    status_t    setLayer(const sp<IBinder>& id, int32_t layer);
-    status_t    setRelativeLayer(const sp<IBinder>& id,
-            const sp<IBinder>& relativeTo, int32_t layer);
-    status_t    setAlpha(const sp<IBinder>& id, float alpha=1.0f);
-    status_t    setMatrix(const sp<IBinder>& id, float dsdx, float dtdx, float dtdy, float dsdy);
-    status_t    setPosition(const sp<IBinder>& id, float x, float y);
-    status_t    setSize(const sp<IBinder>& id, uint32_t w, uint32_t h);
-    status_t    setCrop(const sp<IBinder>& id, const Rect& crop);
-    status_t    setFinalCrop(const sp<IBinder>& id, const Rect& crop);
-    status_t    setLayerStack(const sp<IBinder>& id, uint32_t layerStack);
-    status_t    deferTransactionUntil(const sp<IBinder>& id,
-            const sp<IBinder>& handle, uint64_t frameNumber);
-    status_t    deferTransactionUntil(const sp<IBinder>& id,
-            const sp<Surface>& handle, uint64_t frameNumber);
-    status_t    reparentChildren(const sp<IBinder>& id,
-            const sp<IBinder>& newParentHandle);
-    status_t    detachChildren(const sp<IBinder>& id);
-    status_t    setOverrideScalingMode(const sp<IBinder>& id,
-            int32_t overrideScalingMode);
-    status_t    setGeometryAppliesWithResize(const sp<IBinder>& id);
+    class Transaction {
+        std::unordered_map<sp<SurfaceControl>, ComposerState, SCHash> mComposerStates;
+        SortedVector<DisplayState > mDisplayStates;
+        uint32_t                    mForceSynchronous = 0;
+        uint32_t                    mTransactionNestCount = 0;
+        bool                        mAnimation = false;
+        bool                        mEarlyWakeup = false;
+
+        int mStatus = NO_ERROR;
+
+        layer_state_t* getLayerState(const sp<SurfaceControl>& sc);
+        DisplayState& getDisplayState(const sp<IBinder>& token);
+
+    public:
+        Transaction() = default;
+        virtual ~Transaction() = default;
+        Transaction(Transaction const& other);
+
+        status_t apply(bool synchronous = false);
+        // Merge another transaction in to this one, clearing other
+        // as if it had been applied.
+        Transaction& merge(Transaction&& other);
+        Transaction& show(const sp<SurfaceControl>& sc);
+        Transaction& hide(const sp<SurfaceControl>& sc);
+        Transaction& setPosition(const sp<SurfaceControl>& sc,
+                float x, float y);
+        Transaction& setSize(const sp<SurfaceControl>& sc,
+                uint32_t w, uint32_t h);
+        Transaction& setLayer(const sp<SurfaceControl>& sc,
+                int32_t z);
+
+        // Sets a Z order relative to the Surface specified by "relativeTo" but
+        // without becoming a full child of the relative. Z-ordering works exactly
+        // as if it were a child however.
+        //
+        // As a nod to sanity, only non-child surfaces may have a relative Z-order.
+        //
+        // This overrides any previous call and is overriden by any future calls
+        // to setLayer.
+        //
+        // If the relative is removed, the Surface will have no layer and be
+        // invisible, until the next time set(Relative)Layer is called.
+        Transaction& setRelativeLayer(const sp<SurfaceControl>& sc,
+                const sp<IBinder>& relativeTo, int32_t z);
+        Transaction& setFlags(const sp<SurfaceControl>& sc,
+                uint32_t flags, uint32_t mask);
+        Transaction& setTransparentRegionHint(const sp<SurfaceControl>& sc,
+                const Region& transparentRegion);
+        Transaction& setAlpha(const sp<SurfaceControl>& sc,
+                float alpha);
+        Transaction& setMatrix(const sp<SurfaceControl>& sc,
+                float dsdx, float dtdx, float dtdy, float dsdy);
+        Transaction& setCrop(const sp<SurfaceControl>& sc, const Rect& crop);
+        Transaction& setFinalCrop(const sp<SurfaceControl>& sc, const Rect& crop);
+        Transaction& setLayerStack(const sp<SurfaceControl>& sc, uint32_t layerStack);
+        // Defers applying any changes made in this transaction until the Layer
+        // identified by handle reaches the given frameNumber. If the Layer identified
+        // by handle is removed, then we will apply this transaction regardless of
+        // what frame number has been reached.
+        Transaction& deferTransactionUntil(const sp<SurfaceControl>& sc,
+                const sp<IBinder>& handle,
+                uint64_t frameNumber);
+        // A variant of deferTransactionUntil which identifies the Layer we wait for by
+        // Surface instead of Handle. Useful for clients which may not have the
+        // SurfaceControl for some of their Surfaces. Otherwise behaves identically.
+        Transaction& deferTransactionUntil(const sp<SurfaceControl>& sc,
+                const sp<Surface>& barrierSurface,
+                uint64_t frameNumber);
+        // Reparents all children of this layer to the new parent handle.
+        Transaction& reparentChildren(const sp<SurfaceControl>& sc,
+                const sp<IBinder>& newParentHandle);
+
+        /// Reparents the current layer to the new parent handle. The new parent must not be null.
+        // This can be used instead of reparentChildren if the caller wants to
+        // only re-parent a specific child.
+        Transaction& reparent(const sp<SurfaceControl>& sc,
+                const sp<IBinder>& newParentHandle);
+
+        Transaction& setColor(const sp<SurfaceControl>& sc, const half3& color);
+
+        // Detaches all child surfaces (and their children recursively)
+        // from their SurfaceControl.
+        // The child SurfaceControls will not throw exceptions or return errors,
+        // but transactions will have no effect.
+        // The child surfaces will continue to follow their parent surfaces,
+        // and remain eligible for rendering, but their relative state will be
+        // frozen. We use this in the WindowManager, in app shutdown/relaunch
+        // scenarios, where the app would otherwise clean up its child Surfaces.
+        // Sometimes the WindowManager needs to extend their lifetime slightly
+        // in order to perform an exit animation or prevent flicker.
+        Transaction& detachChildren(const sp<SurfaceControl>& sc);
+        // Set an override scaling mode as documented in <system/window.h>
+        // the override scaling mode will take precedence over any client
+        // specified scaling mode. -1 will clear the override scaling mode.
+        Transaction& setOverrideScalingMode(const sp<SurfaceControl>& sc,
+                int32_t overrideScalingMode);
+
+        // If the size changes in this transaction, all geometry updates specified
+        // in this transaction will not complete until a buffer of the new size
+        // arrives. As some elements normally apply immediately, this enables
+        // freezing the total geometry of a surface until a resize is completed.
+        Transaction& setGeometryAppliesWithResize(const sp<SurfaceControl>& sc);
+
+        Transaction& destroySurface(const sp<SurfaceControl>& sc);
+
+        status_t setDisplaySurface(const sp<IBinder>& token,
+                const sp<IGraphicBufferProducer>& bufferProducer);
+
+        void setDisplayLayerStack(const sp<IBinder>& token, uint32_t layerStack);
+
+        /* setDisplayProjection() defines the projection of layer stacks
+         * to a given display.
+         *
+         * - orientation defines the display's orientation.
+         * - layerStackRect defines which area of the window manager coordinate
+         * space will be used.
+         * - displayRect defines where on the display will layerStackRect be
+         * mapped to. displayRect is specified post-orientation, that is
+         * it uses the orientation seen by the end-user.
+         */
+        void setDisplayProjection(const sp<IBinder>& token,
+                uint32_t orientation,
+                const Rect& layerStackRect,
+                const Rect& displayRect);
+        void setDisplaySize(const sp<IBinder>& token, uint32_t width, uint32_t height);
+        void setAnimationTransaction();
+        void setEarlyWakeup();
+    };
 
     status_t    destroySurface(const sp<IBinder>& id);
 
     status_t clearLayerFrameStats(const sp<IBinder>& token) const;
     status_t getLayerFrameStats(const sp<IBinder>& token, FrameStats* outStats) const;
-
     static status_t clearAnimationFrameStats();
     static status_t getAnimationFrameStats(FrameStats* outStats);
 
     static status_t getHdrCapabilities(const sp<IBinder>& display,
             HdrCapabilities* outCapabilities);
 
-    static status_t setDisplaySurface(const sp<IBinder>& token,
-            sp<IGraphicBufferProducer> bufferProducer);
-    static void setDisplayLayerStack(const sp<IBinder>& token,
-            uint32_t layerStack);
-    static void setDisplaySize(const sp<IBinder>& token, uint32_t width, uint32_t height);
-
-    /* setDisplayProjection() defines the projection of layer stacks
-     * to a given display.
-     *
-     * - orientation defines the display's orientation.
-     * - layerStackRect defines which area of the window manager coordinate
-     * space will be used.
-     * - displayRect defines where on the display will layerStackRect be
-     * mapped to. displayRect is specified post-orientation, that is
-     * it uses the orientation seen by the end-user.
-     */
     static void setDisplayProjection(const sp<IBinder>& token,
             uint32_t orientation,
             const Rect& layerStackRect,
             const Rect& displayRect);
 
+    inline sp<ISurfaceComposerClient> getClient() { return mClient; }
+
 private:
     virtual void onFirstRef();
-    Composer& getComposer();
 
     mutable     Mutex                       mLock;
                 status_t                    mStatus;
                 sp<ISurfaceComposerClient>  mClient;
-                Composer&                   mComposer;
                 wp<IGraphicBufferProducer>  mParent;
 };
 
 // ---------------------------------------------------------------------------
 
-class ScreenshotClient
-{
+class ScreenshotClient {
 public:
     // if cropping isn't required, callers may pass in a default Rect, e.g.:
     //   capture(display, producer, Rect(), reqWidth, ...);
-    static status_t capture(
-            const sp<IBinder>& display,
-            const sp<IGraphicBufferProducer>& producer,
-            Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
-            int32_t minLayerZ, int32_t maxLayerZ,
-            bool useIdentityTransform);
-    static status_t captureToBuffer(
-            const sp<IBinder>& display,
-            Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
-            int32_t minLayerZ, int32_t maxLayerZ,
-            bool useIdentityTransform,
-            uint32_t rotation,
-            sp<GraphicBuffer>* outbuffer);
-private:
-    mutable sp<CpuConsumer> mCpuConsumer;
-    mutable sp<IGraphicBufferProducer> mProducer;
-    CpuConsumer::LockedBuffer mBuffer;
-    bool mHaveBuffer;
-
-public:
-    ScreenshotClient();
-    ~ScreenshotClient();
-
-    // frees the previous screenshot and captures a new one
-    // if cropping isn't required, callers may pass in a default Rect, e.g.:
-    //   update(display, Rect(), useIdentityTransform);
-    status_t update(const sp<IBinder>& display,
-            Rect sourceCrop, bool useIdentityTransform);
-    status_t update(const sp<IBinder>& display,
-            Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
-            bool useIdentityTransform);
-    status_t update(const sp<IBinder>& display,
-            Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
-            int32_t minLayerZ, int32_t maxLayerZ,
-            bool useIdentityTransform);
-    status_t update(const sp<IBinder>& display,
-            Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
-            int32_t minLayerZ, int32_t maxLayerZ,
-            bool useIdentityTransform, uint32_t rotation);
-
-    sp<CpuConsumer> getCpuConsumer() const;
-
-    // release memory occupied by the screenshot
-    void release();
-
-    // pixels are valid until this object is freed or
-    // release() or update() is called
-    void const* getPixels() const;
-
-    uint32_t getWidth() const;
-    uint32_t getHeight() const;
-    PixelFormat getFormat() const;
-    uint32_t getStride() const;
-    // size of allocated memory in bytes
-    size_t getSize() const;
-    android_dataspace getDataSpace() const;
+    static status_t capture(const sp<IBinder>& display, Rect sourceCrop, uint32_t reqWidth,
+                            uint32_t reqHeight, int32_t minLayerZ, int32_t maxLayerZ,
+                            bool useIdentityTransform, uint32_t rotation,
+                            sp<GraphicBuffer>* outBuffer);
+    static status_t captureLayers(const sp<IBinder>& layerHandle, Rect sourceCrop, float frameScale,
+                                  sp<GraphicBuffer>* outBuffer);
+    static status_t captureChildLayers(const sp<IBinder>& layerHandle, Rect sourceCrop,
+                                       float frameScale, sp<GraphicBuffer>* outBuffer);
 };
 
 // ---------------------------------------------------------------------------
diff --git a/libs/gui/include/gui/SurfaceControl.h b/libs/gui/include/gui/SurfaceControl.h
index c15209d..bd987dd 100644
--- a/libs/gui/include/gui/SurfaceControl.h
+++ b/libs/gui/include/gui/SurfaceControl.h
@@ -29,6 +29,7 @@
 #include <ui/Region.h>
 
 #include <gui/ISurfaceComposerClient.h>
+#include <math/vec3.h>
 
 namespace android {
 
@@ -43,6 +44,9 @@
 class SurfaceControl : public RefBase
 {
 public:
+    static sp<SurfaceControl> readFromParcel(Parcel* parcel);
+    void writeToParcel(Parcel* parcel);
+
     static bool isValid(const sp<SurfaceControl>& surface) {
         return (surface != 0) && surface->isValid();
     }
@@ -60,87 +64,6 @@
     // disconnect any api that's connected
     void        disconnect();
 
-    status_t    setLayerStack(uint32_t layerStack);
-    status_t    setLayer(int32_t layer);
-
-    // Sets a Z order relative to the Surface specified by "relativeTo" but
-    // without becoming a full child of the relative. Z-ordering works exactly
-    // as if it were a child however.
-    //
-    // As a nod to sanity, only non-child surfaces may have a relative Z-order.
-    //
-    // This overrides any previous and is overriden by any future calls
-    // to setLayer.
-    //
-    // If the relative dissapears, the Surface will have no layer and be
-    // invisible, until the next time set(Relative)Layer is called.
-    //
-    // TODO: This is probably a hack. Currently it exists only to work around
-    // some framework usage of the hidden APPLICATION_MEDIA_OVERLAY window type
-    // which allows inserting a window between a SurfaceView and it's main application
-    // window. However, since we are using child windows for the SurfaceView, but not using
-    // child windows elsewhere in O, the WindowManager can't set the layer appropriately.
-    // This is only used by the "TvInputService" and following the port of ViewRootImpl
-    // to child surfaces, we can then port this and remove this method.
-    status_t    setRelativeLayer(const sp<IBinder>& relativeTo, int32_t layer);
-    status_t    setPosition(float x, float y);
-    status_t    setSize(uint32_t w, uint32_t h);
-    status_t    hide();
-    status_t    show();
-    status_t    setFlags(uint32_t flags, uint32_t mask);
-    status_t    setTransparentRegionHint(const Region& transparent);
-    status_t    setAlpha(float alpha=1.0f);
-
-    // Experimentarily it appears that the matrix transforms the
-    // on-screen rectangle and it's contents before the position is
-    // applied.
-    //
-    // TODO: Test with other combinations to find approximate transformation rules.
-    //
-    // For example:
-    // Layer sized (W,H) set to position (x,y) with matrix M=[-1, 0, 0, 1] (Horizontal flip) gives
-    // [((0, 0), (W, H)) x M] + (x,y) = ((-W, 0), (0, H)) + (x,y) = ((-W + x, y), (x, H+y))
-    status_t    setMatrix(float dsdx, float dtdx, float dtdy, float dsdy);
-    status_t    setCrop(const Rect& crop);
-    status_t    setFinalCrop(const Rect& crop);
-
-    // If the size changes in this transaction, all geometry updates specified
-    // in this transaction will not complete until a buffer of the new size
-    // arrives. As some elements normally apply immediately, this enables
-    // freezing the total geometry of a surface until a resize is completed.
-    status_t    setGeometryAppliesWithResize();
-
-    // Defers applying any changes made in this transaction until the Layer
-    // identified by handle reaches the given frameNumber. If the Layer identified
-    // by handle is removed, then we will apply this transaction regardless of
-    // what frame number has been reached.
-    status_t deferTransactionUntil(const sp<IBinder>& handle, uint64_t frameNumber);
-
-    // A variant of deferTransactionUntil which identifies the Layer we wait for by
-    // Surface instead of Handle. Useful for clients which may not have the
-    // SurfaceControl for some of their Surfaces. Otherwise behaves identically.
-    status_t deferTransactionUntil(const sp<Surface>& barrier, uint64_t frameNumber);
-
-    // Reparents all children of this layer to the new parent handle.
-    status_t reparentChildren(const sp<IBinder>& newParentHandle);
-
-    // Detaches all child surfaces (and their children recursively)
-    // from their SurfaceControl.
-    // The child SurfaceControl's will not throw exceptions or return errors,
-    // but transactions will have no effect.
-    // The child surfaces will continue to follow their parent surfaces,
-    // and remain eligible for rendering, but their relative state will be
-    // frozen. We use this in the WindowManager, in app shutdown/relaunch
-    // scenarios, where the app would otherwise clean up its child Surfaces.
-    // Sometimes the WindowManager needs to extend their lifetime slightly
-    // in order to perform an exit animation or prevent flicker.
-    status_t detachChildren();
-
-    // Set an override scaling mode as documented in <system/window.h>
-    // the override scaling mode will take precedence over any client
-    // specified scaling mode. -1 will clear the override scaling mode.
-    status_t setOverrideScalingMode(int32_t overrideScalingMode);
-
     static status_t writeSurfaceToParcel(
             const sp<SurfaceControl>& control, Parcel* parcel);
 
@@ -151,6 +74,8 @@
     status_t clearLayerFrameStats() const;
     status_t getLayerFrameStats(FrameStats* outStats) const;
 
+    sp<SurfaceComposerClient> getClient() const;
+
 private:
     // can't be copied
     SurfaceControl& operator = (SurfaceControl& rhs);
@@ -162,7 +87,8 @@
     SurfaceControl(
             const sp<SurfaceComposerClient>& client,
             const sp<IBinder>& handle,
-            const sp<IGraphicBufferProducer>& gbp);
+            const sp<IGraphicBufferProducer>& gbp,
+            bool owned);
 
     ~SurfaceControl();
 
@@ -175,6 +101,7 @@
     sp<IGraphicBufferProducer>  mGraphicBufferProducer;
     mutable Mutex               mLock;
     mutable sp<Surface>         mSurfaceData;
+    bool                        mOwned;
 };
 
 }; // namespace android
diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp
index 908959c..01e90e0 100644
--- a/libs/gui/tests/Android.bp
+++ b/libs/gui/tests/Android.bp
@@ -49,3 +49,35 @@
         "libnativewindow"
     ],
 }
+
+// Build a separate binary for each source file to $(TARGET_OUT_DATA_NATIVE_TESTS)/$(LOCAL_MODULE)
+cc_test {
+    name: "libgui_separate_binary_test",
+    test_suites: ["device-tests"],
+
+    clang: true,
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+
+    test_per_src: true,
+    srcs: [
+        "SurfaceParcelable_test.cpp",
+    ],
+
+    shared_libs: [
+        "liblog",
+        "libbinder",
+        "libcutils",
+        "libgui",
+        "libui",
+        "libutils",
+        "libbufferhubqueue",  // TODO(b/70046255): Remove these once BufferHub is integrated into libgui.
+        "libpdx_default_transport",
+    ],
+
+    header_libs: [
+        "libdvr_headers",
+    ],
+}
diff --git a/libs/gui/tests/CpuConsumer_test.cpp b/libs/gui/tests/CpuConsumer_test.cpp
index 588e541..36be7d9 100644
--- a/libs/gui/tests/CpuConsumer_test.cpp
+++ b/libs/gui/tests/CpuConsumer_test.cpp
@@ -33,6 +33,7 @@
 #include <utils/Mutex.h>
 #include <utils/Condition.h>
 
+#include <thread>
 #include <vector>
 #define CPU_CONSUMER_TEST_FORMAT_RAW 0
 #define CPU_CONSUMER_TEST_FORMAT_Y8 0
@@ -681,6 +682,70 @@
     }
 }
 
+TEST_P(CpuConsumerTest, FromCpuInvalid) {
+    status_t err = mCC->lockNextBuffer(nullptr);
+    ASSERT_EQ(BAD_VALUE, err) << "lockNextBuffer did not fail";
+
+    CpuConsumer::LockedBuffer b;
+    err = mCC->unlockBuffer(b);
+    ASSERT_EQ(BAD_VALUE, err) << "unlockBuffer did not fail";
+}
+
+TEST_P(CpuConsumerTest, FromCpuMultiThread) {
+    CpuConsumerTestParams params = GetParam();
+    ASSERT_NO_FATAL_FAILURE(configureANW(mANW, params, params.maxLockedBuffers + 1));
+
+    for (int i = 0; i < 10; i++) {
+        std::atomic<int> threadReadyCount(0);
+        auto lockAndUnlock = [&]() {
+            threadReadyCount++;
+            // busy wait
+            while (threadReadyCount < params.maxLockedBuffers + 1);
+
+            CpuConsumer::LockedBuffer b;
+            status_t err = mCC->lockNextBuffer(&b);
+            if (err == NO_ERROR) {
+                usleep(1000);
+                err = mCC->unlockBuffer(b);
+                ASSERT_NO_ERROR(err, "Could not unlock buffer: ");
+            } else if (err == NOT_ENOUGH_DATA) {
+                // there are params.maxLockedBuffers+1 threads so one of the
+                // threads might get this error
+            } else {
+                FAIL() << "Could not lock buffer";
+            }
+        };
+
+        // produce buffers
+        for (int j = 0; j < params.maxLockedBuffers + 1; j++) {
+            const int64_t time = 1234L;
+            uint32_t stride;
+            ASSERT_NO_FATAL_FAILURE(produceOneFrame(mANW, params, time, &stride));
+        }
+
+        // spawn threads
+        std::vector<std::thread> threads;
+        for (int j = 0; j < params.maxLockedBuffers + 1; j++) {
+            threads.push_back(std::thread(lockAndUnlock));
+        }
+
+        // join threads
+        for (auto& thread : threads) {
+            thread.join();
+        }
+
+        // we produced N+1 buffers, but the threads might only consume N
+        CpuConsumer::LockedBuffer b;
+        if (mCC->lockNextBuffer(&b) == NO_ERROR) {
+            mCC->unlockBuffer(b);
+        }
+
+        if (HasFatalFailure()) {
+            break;
+        }
+    }
+}
+
 CpuConsumerTestParams y8TestSets[] = {
     { 512,   512, 1, HAL_PIXEL_FORMAT_Y8},
     { 512,   512, 3, HAL_PIXEL_FORMAT_Y8},
diff --git a/libs/gui/tests/GLTest.cpp b/libs/gui/tests/GLTest.cpp
index 1739d9c..a91552f 100644
--- a/libs/gui/tests/GLTest.cpp
+++ b/libs/gui/tests/GLTest.cpp
@@ -22,6 +22,8 @@
 
 namespace android {
 
+using Transaction = SurfaceComposerClient::Transaction;
+
 static int abs(int value) {
     return value > 0 ? value : -value;
 }
@@ -68,10 +70,10 @@
         ASSERT_TRUE(mSurfaceControl != NULL);
         ASSERT_TRUE(mSurfaceControl->isValid());
 
-        SurfaceComposerClient::openGlobalTransaction();
-        ASSERT_EQ(NO_ERROR, mSurfaceControl->setLayer(0x7FFFFFFF));
-        ASSERT_EQ(NO_ERROR, mSurfaceControl->show());
-        SurfaceComposerClient::closeGlobalTransaction();
+        Transaction t;
+        ASSERT_EQ(NO_ERROR, t.setLayer(mSurfaceControl, 0x7FFFFFFF)
+                .show(mSurfaceControl)
+                .apply());
 
         sp<ANativeWindow> window = mSurfaceControl->getSurface();
         mEglSurface = createWindowSurface(mEglDisplay, mGlConfig, window);
diff --git a/libs/gui/tests/IGraphicBufferProducer_test.cpp b/libs/gui/tests/IGraphicBufferProducer_test.cpp
index dd23bd4..a35cf11 100644
--- a/libs/gui/tests/IGraphicBufferProducer_test.cpp
+++ b/libs/gui/tests/IGraphicBufferProducer_test.cpp
@@ -42,6 +42,10 @@
 #define TEST_CONTROLLED_BY_APP false
 #define TEST_PRODUCER_USAGE_BITS (0)
 
+#ifndef USE_BUFFER_HUB_AS_BUFFER_QUEUE
+#define USE_BUFFER_HUB_AS_BUFFER_QUEUE 0
+#endif
+
 namespace android {
 
 namespace {
@@ -66,9 +70,15 @@
     const int QUEUE_BUFFER_INPUT_SCALING_MODE = 0;
     const int QUEUE_BUFFER_INPUT_TRANSFORM = 0;
     const sp<Fence> QUEUE_BUFFER_INPUT_FENCE = Fence::NO_FENCE;
+
+    // Enums to control which IGraphicBufferProducer backend to test.
+    enum IGraphicBufferProducerTestCode {
+        USE_BUFFER_QUEUE_PRODUCER = 0,
+        USE_BUFFER_HUB_PRODUCER,
+    };
 }; // namespace anonymous
 
-class IGraphicBufferProducerTest : public ::testing::Test {
+class IGraphicBufferProducerTest : public ::testing::TestWithParam<uint32_t> {
 protected:
 
     IGraphicBufferProducerTest() {}
@@ -81,10 +91,27 @@
 
         mDC = new DummyConsumer;
 
-        BufferQueue::createBufferQueue(&mProducer, &mConsumer);
+        switch (GetParam()) {
+            case USE_BUFFER_QUEUE_PRODUCER: {
+                BufferQueue::createBufferQueue(&mProducer, &mConsumer);
+                break;
+            }
+            case USE_BUFFER_HUB_PRODUCER: {
+                BufferQueue::createBufferHubQueue(&mProducer, &mConsumer);
+                break;
+            }
+            default: {
+                // Should never reach here.
+                LOG_ALWAYS_FATAL("Invalid test params: %u", GetParam());
+                break;
+            }
+        }
 
         // Test check: Can't connect producer if no consumer yet
-        ASSERT_EQ(NO_INIT, TryConnectProducer());
+        if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) {
+            // TODO(b/73267953): Make BufferHub honor producer and consumer connection.
+            ASSERT_EQ(NO_INIT, TryConnectProducer());
+        }
 
         // Must connect consumer before producer connects will succeed.
         ASSERT_OK(mConsumer->consumerConnect(mDC, /*controlledByApp*/false));
@@ -229,7 +256,7 @@
     sp<IGraphicBufferConsumer> mConsumer;
 };
 
-TEST_F(IGraphicBufferProducerTest, ConnectFirst_ReturnsError) {
+TEST_P(IGraphicBufferProducerTest, ConnectFirst_ReturnsError) {
     IGraphicBufferProducer::QueueBufferOutput output;
 
     // NULL output returns BAD_VALUE
@@ -247,7 +274,7 @@
     // TODO: get a token from a dead process somehow
 }
 
-TEST_F(IGraphicBufferProducerTest, ConnectAgain_ReturnsError) {
+TEST_P(IGraphicBufferProducerTest, ConnectAgain_ReturnsError) {
     ASSERT_NO_FATAL_FAILURE(ConnectProducer());
 
     // Can't connect when there is already a producer connected
@@ -259,20 +286,23 @@
 
     ASSERT_OK(mConsumer->consumerDisconnect());
     // Can't connect when IGBP is abandoned
-    EXPECT_EQ(NO_INIT, mProducer->connect(TEST_TOKEN,
-                                          TEST_API,
-                                          TEST_CONTROLLED_BY_APP,
-                                          &output));
+    if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) {
+        // TODO(b/73267953): Make BufferHub honor producer and consumer connection.
+        EXPECT_EQ(NO_INIT, mProducer->connect(TEST_TOKEN,
+                                              TEST_API,
+                                              TEST_CONTROLLED_BY_APP,
+                                              &output));
+    }
 }
 
-TEST_F(IGraphicBufferProducerTest, Disconnect_Succeeds) {
+TEST_P(IGraphicBufferProducerTest, Disconnect_Succeeds) {
     ASSERT_NO_FATAL_FAILURE(ConnectProducer());
 
     ASSERT_OK(mProducer->disconnect(TEST_API));
 }
 
 
-TEST_F(IGraphicBufferProducerTest, Disconnect_ReturnsError) {
+TEST_P(IGraphicBufferProducerTest, Disconnect_ReturnsError) {
     ASSERT_NO_FATAL_FAILURE(ConnectProducer());
 
     // Must disconnect with same API number
@@ -283,7 +313,7 @@
     // TODO: somehow kill mProducer so that this returns DEAD_OBJECT
 }
 
-TEST_F(IGraphicBufferProducerTest, Query_Succeeds) {
+TEST_P(IGraphicBufferProducerTest, Query_Succeeds) {
     ASSERT_NO_FATAL_FAILURE(ConnectProducer());
 
     int32_t value = -1;
@@ -308,7 +338,7 @@
 
 }
 
-TEST_F(IGraphicBufferProducerTest, Query_ReturnsError) {
+TEST_P(IGraphicBufferProducerTest, Query_ReturnsError) {
     ASSERT_NO_FATAL_FAILURE(ConnectProducer());
 
     // One past the end of the last 'query' enum value. Update this if we add more enums.
@@ -334,14 +364,17 @@
     ASSERT_OK(mConsumer->consumerDisconnect());
 
     // BQ was abandoned
-    EXPECT_EQ(NO_INIT, mProducer->query(NATIVE_WINDOW_FORMAT, &value));
+    if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) {
+        // TODO(b/73267953): Make BufferHub honor producer and consumer connection.
+        EXPECT_EQ(NO_INIT, mProducer->query(NATIVE_WINDOW_FORMAT, &value));
+    }
 
     // TODO: other things in window.h that are supported by Surface::query
     // but not by BufferQueue::query
 }
 
 // TODO: queue under more complicated situations not involving just a single buffer
-TEST_F(IGraphicBufferProducerTest, Queue_Succeeds) {
+TEST_P(IGraphicBufferProducerTest, Queue_Succeeds) {
     ASSERT_NO_FATAL_FAILURE(ConnectProducer());
 
     int dequeuedSlot = -1;
@@ -371,16 +404,21 @@
         EXPECT_EQ(DEFAULT_WIDTH, output.width);
         EXPECT_EQ(DEFAULT_HEIGHT, output.height);
         EXPECT_EQ(DEFAULT_TRANSFORM_HINT, output.transformHint);
+
         // Since queueBuffer was called exactly once
-        EXPECT_EQ(1u, output.numPendingBuffers);
-        EXPECT_EQ(2u, output.nextFrameNumber);
+        if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) {
+            // TODO(b/70041889): BufferHubProducer need to support metadata: numPendingBuffers
+            EXPECT_EQ(1u, output.numPendingBuffers);
+            // TODO(b/70041952): BufferHubProducer need to support metadata: nextFrameNumber
+            EXPECT_EQ(2u, output.nextFrameNumber);
+        }
     }
 
     // Buffer was not in the dequeued state
     EXPECT_EQ(BAD_VALUE, mProducer->queueBuffer(dequeuedSlot, input, &output));
 }
 
-TEST_F(IGraphicBufferProducerTest, Queue_ReturnsError) {
+TEST_P(IGraphicBufferProducerTest, Queue_ReturnsError) {
     ASSERT_NO_FATAL_FAILURE(ConnectProducer());
 
     // Invalid slot number
@@ -463,15 +501,16 @@
     ASSERT_OK(mConsumer->consumerDisconnect());
 
     // The buffer queue has been abandoned.
-    {
+    if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) {
         IGraphicBufferProducer::QueueBufferInput input = CreateBufferInput();
         IGraphicBufferProducer::QueueBufferOutput output;
 
+        // TODO(b/73267953): Make BufferHub honor producer and consumer connection.
         EXPECT_EQ(NO_INIT, mProducer->queueBuffer(dequeuedSlot, input, &output));
     }
 }
 
-TEST_F(IGraphicBufferProducerTest, CancelBuffer_DoesntCrash) {
+TEST_P(IGraphicBufferProducerTest, CancelBuffer_DoesntCrash) {
     ASSERT_NO_FATAL_FAILURE(ConnectProducer());
 
     int dequeuedSlot = -1;
@@ -488,7 +527,7 @@
     mProducer->cancelBuffer(dequeuedSlot, dequeuedFence);
 }
 
-TEST_F(IGraphicBufferProducerTest, SetMaxDequeuedBufferCount_Succeeds) {
+TEST_P(IGraphicBufferProducerTest, SetMaxDequeuedBufferCount_Succeeds) {
     ASSERT_NO_FATAL_FAILURE(ConnectProducer());
     int minUndequeuedBuffers;
     ASSERT_OK(mProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
@@ -540,7 +579,7 @@
     ASSERT_OK(mProducer->setMaxDequeuedBufferCount(maxBuffers-1));
 }
 
-TEST_F(IGraphicBufferProducerTest, SetMaxDequeuedBufferCount_Fails) {
+TEST_P(IGraphicBufferProducerTest, SetMaxDequeuedBufferCount_Fails) {
     ASSERT_NO_FATAL_FAILURE(ConnectProducer());
     int minUndequeuedBuffers;
     ASSERT_OK(mProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
@@ -578,12 +617,19 @@
     ASSERT_OK(mConsumer->consumerDisconnect());
 
     // Fail because the buffer queue was abandoned
-    EXPECT_EQ(NO_INIT, mProducer->setMaxDequeuedBufferCount(minBuffers))
-            << "bufferCount: " << minBuffers;
-
+    if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) {
+        // TODO(b/73267953): Make BufferHub honor producer and consumer connection.
+        EXPECT_EQ(NO_INIT, mProducer->setMaxDequeuedBufferCount(minBuffers))
+                << "bufferCount: " << minBuffers;
+    }
 }
 
-TEST_F(IGraphicBufferProducerTest, SetAsyncMode_Succeeds) {
+TEST_P(IGraphicBufferProducerTest, SetAsyncMode_Succeeds) {
+    if (GetParam() == USE_BUFFER_HUB_PRODUCER) {
+        // TODO(b/36724099): Add support for BufferHubProducer::setAsyncMode(true)
+        return;
+    }
+
     ASSERT_OK(mConsumer->setMaxAcquiredBufferCount(1)) << "maxAcquire: " << 1;
     ASSERT_NO_FATAL_FAILURE(ConnectProducer());
     ASSERT_OK(mProducer->setAsyncMode(true)) << "async mode: " << true;
@@ -609,7 +655,7 @@
     }
 }
 
-TEST_F(IGraphicBufferProducerTest, SetAsyncMode_Fails) {
+TEST_P(IGraphicBufferProducerTest, SetAsyncMode_Fails) {
     ASSERT_NO_FATAL_FAILURE(ConnectProducer());
     // Prerequisite to fail out a valid setBufferCount call
     {
@@ -628,11 +674,13 @@
     ASSERT_OK(mConsumer->consumerDisconnect());
 
     // Fail because the buffer queue was abandoned
-    EXPECT_EQ(NO_INIT, mProducer->setAsyncMode(false)) << "asyncMode: "
-            << false;
+    if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) {
+        // TODO(b/36724099): Make BufferHub honor producer and consumer connection.
+        EXPECT_EQ(NO_INIT, mProducer->setAsyncMode(false)) << "asyncMode: " << false;
+    }
 }
 
-TEST_F(IGraphicBufferProducerTest,
+TEST_P(IGraphicBufferProducerTest,
         DisconnectedProducerReturnsError_dequeueBuffer) {
     int slot = -1;
     sp<Fence> fence;
@@ -642,15 +690,18 @@
                                        TEST_PRODUCER_USAGE_BITS, nullptr, nullptr));
 }
 
-TEST_F(IGraphicBufferProducerTest,
+TEST_P(IGraphicBufferProducerTest,
         DisconnectedProducerReturnsError_detachNextBuffer) {
     sp<Fence> fence;
     sp<GraphicBuffer> buffer;
 
-    ASSERT_EQ(NO_INIT, mProducer->detachNextBuffer(&buffer, &fence));
+    if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) {
+        // TODO(b/38137191): Implement BufferHubProducer::detachBuffer
+        ASSERT_EQ(NO_INIT, mProducer->detachNextBuffer(&buffer, &fence));
+    }
 }
 
-TEST_F(IGraphicBufferProducerTest,
+TEST_P(IGraphicBufferProducerTest,
         DisconnectedProducerReturnsError_requestBuffer) {
     ASSERT_NO_FATAL_FAILURE(ConnectProducer());
 
@@ -674,7 +725,7 @@
 }
 
 
-TEST_F(IGraphicBufferProducerTest,
+TEST_P(IGraphicBufferProducerTest,
         DisconnectedProducerReturnsError_detachBuffer) {
     int slot = -1;
     sp<Fence> fence;
@@ -684,10 +735,13 @@
 
     ASSERT_OK(mProducer->disconnect(TEST_API));
 
-    ASSERT_EQ(NO_INIT, mProducer->detachBuffer(slot));
+    if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) {
+        // TODO(b/38137191): Implement BufferHubProducer::detachBuffer
+        ASSERT_EQ(NO_INIT, mProducer->detachBuffer(slot));
+    }
 }
 
-TEST_F(IGraphicBufferProducerTest,
+TEST_P(IGraphicBufferProducerTest,
         DisconnectedProducerReturnsError_queueBuffer) {
     int slot = -1;
     sp<Fence> fence;
@@ -704,7 +758,7 @@
     ASSERT_EQ(NO_INIT, mProducer->queueBuffer(slot, input, &output));
 }
 
-TEST_F(IGraphicBufferProducerTest,
+TEST_P(IGraphicBufferProducerTest,
         DisconnectedProducerReturnsError_cancelBuffer) {
     int slot = -1;
     sp<Fence> fence;
@@ -717,7 +771,7 @@
     ASSERT_EQ(NO_INIT, mProducer->cancelBuffer(slot, fence));
 }
 
-TEST_F(IGraphicBufferProducerTest,
+TEST_P(IGraphicBufferProducerTest,
         DisconnectedProducerReturnsError_attachBuffer) {
     int slot = -1;
     sp<Fence> fence;
@@ -725,11 +779,27 @@
 
     setupDequeueRequestBuffer(&slot, &fence, &buffer);
 
-    ASSERT_OK(mProducer->detachBuffer(slot));
+    if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) {
+        // TODO(b/38137191): Implement BufferHubProducer::detachBuffer
+        ASSERT_OK(mProducer->detachBuffer(slot));
+    }
 
     ASSERT_OK(mProducer->disconnect(TEST_API));
 
-    ASSERT_EQ(NO_INIT, mProducer->attachBuffer(&slot, buffer));
+    if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) {
+        // TODO(b/69981968): Implement BufferHubProducer::attachBuffer
+        ASSERT_EQ(NO_INIT, mProducer->attachBuffer(&slot, buffer));
+    }
 }
 
+#if USE_BUFFER_HUB_AS_BUFFER_QUEUE
+INSTANTIATE_TEST_CASE_P(IGraphicBufferProducerBackends, IGraphicBufferProducerTest,
+                        ::testing::Values(USE_BUFFER_QUEUE_PRODUCER, USE_BUFFER_HUB_PRODUCER));
+#else
+// TODO(b/70046255): Remove the #ifdef here and always tests both backends once BufferHubQueue can
+// pass all existing libgui tests.
+INSTANTIATE_TEST_CASE_P(IGraphicBufferProducerBackends, IGraphicBufferProducerTest,
+                        ::testing::Values(USE_BUFFER_QUEUE_PRODUCER));
+#endif
+
 } // namespace android
diff --git a/libs/gui/tests/SurfaceParcelable_test.cpp b/libs/gui/tests/SurfaceParcelable_test.cpp
new file mode 100644
index 0000000..686dc82
--- /dev/null
+++ b/libs/gui/tests/SurfaceParcelable_test.cpp
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2018 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 "SurfaceParcelable_test"
+
+#include <gtest/gtest.h>
+
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <gui/BufferHubProducer.h>
+#include <gui/BufferQueue.h>
+#include <gui/view/Surface.h>
+#include <utils/Log.h>
+
+namespace android {
+
+static const String16 kTestServiceName = String16("SurfaceParcelableTestService");
+static const String16 kSurfaceName = String16("TEST_SURFACE");
+static const uint32_t kBufferWidth = 100;
+static const uint32_t kBufferHeight = 1;
+static const uint32_t kBufferFormat = HAL_PIXEL_FORMAT_BLOB;
+
+enum SurfaceParcelableTestServiceCode {
+    CREATE_BUFFER_QUEUE_SURFACE = IBinder::FIRST_CALL_TRANSACTION,
+    CREATE_BUFFER_HUB_SURFACE,
+};
+
+class SurfaceParcelableTestService : public BBinder {
+public:
+    SurfaceParcelableTestService() {
+        // BufferQueue
+        BufferQueue::createBufferQueue(&mBufferQueueProducer, &mBufferQueueConsumer);
+
+        // BufferHub
+        dvr::ProducerQueueConfigBuilder configBuilder;
+        mProducerQueue = dvr::ProducerQueue::Create(configBuilder.SetDefaultWidth(kBufferWidth)
+                                                            .SetDefaultHeight(kBufferHeight)
+                                                            .SetDefaultFormat(kBufferFormat)
+                                                            .Build(),
+                                                    dvr::UsagePolicy{});
+        mBufferHubProducer = BufferHubProducer::Create(mProducerQueue);
+    }
+
+    ~SurfaceParcelableTestService() = default;
+
+    virtual status_t onTransact(uint32_t code, const Parcel& /*data*/, Parcel* reply,
+                                uint32_t /*flags*/ = 0) {
+        switch (code) {
+            case CREATE_BUFFER_QUEUE_SURFACE: {
+                view::Surface surfaceShim;
+                surfaceShim.name = kSurfaceName;
+                surfaceShim.graphicBufferProducer = mBufferQueueProducer;
+                return surfaceShim.writeToParcel(reply);
+            }
+            case CREATE_BUFFER_HUB_SURFACE: {
+                view::Surface surfaceShim;
+                surfaceShim.name = kSurfaceName;
+                surfaceShim.graphicBufferProducer = mBufferHubProducer;
+                return surfaceShim.writeToParcel(reply);
+            }
+            default:
+                return UNKNOWN_TRANSACTION;
+        };
+    }
+
+protected:
+    sp<IGraphicBufferProducer> mBufferQueueProducer;
+    sp<IGraphicBufferConsumer> mBufferQueueConsumer;
+
+    std::shared_ptr<dvr::ProducerQueue> mProducerQueue;
+    sp<IGraphicBufferProducer> mBufferHubProducer;
+};
+
+static int runBinderServer() {
+    ProcessState::self()->startThreadPool();
+
+    sp<IServiceManager> sm = defaultServiceManager();
+    sp<SurfaceParcelableTestService> service = new SurfaceParcelableTestService;
+    sm->addService(kTestServiceName, service, false);
+
+    ALOGI("Binder server running...");
+
+    while (true) {
+        int stat, retval;
+        retval = wait(&stat);
+        if (retval == -1 && errno == ECHILD) {
+            break;
+        }
+    }
+
+    ALOGI("Binder server exiting...");
+    return 0;
+}
+
+class SurfaceParcelableTest : public ::testing::TestWithParam<uint32_t> {
+protected:
+    virtual void SetUp() {
+        mService = defaultServiceManager()->getService(kTestServiceName);
+        if (mService == nullptr) {
+            ALOGE("Failed to connect to the test service.");
+            return;
+        }
+
+        ALOGI("Binder service is ready for client.");
+    }
+
+    status_t GetSurface(view::Surface* surfaceShim) {
+        ALOGI("...Test: %d", GetParam());
+
+        uint32_t opCode = GetParam();
+        Parcel data;
+        Parcel reply;
+        status_t error = mService->transact(opCode, data, &reply);
+        if (error != NO_ERROR) {
+            ALOGE("Failed to get surface over binder, error=%d.", error);
+            return error;
+        }
+
+        error = surfaceShim->readFromParcel(&reply);
+        if (error != NO_ERROR) {
+            ALOGE("Failed to get surface from parcel, error=%d.", error);
+            return error;
+        }
+
+        return NO_ERROR;
+    }
+
+private:
+    sp<IBinder> mService;
+};
+
+TEST_P(SurfaceParcelableTest, SendOverBinder) {
+    view::Surface surfaceShim;
+    EXPECT_EQ(GetSurface(&surfaceShim), NO_ERROR);
+    EXPECT_EQ(surfaceShim.name, kSurfaceName);
+    EXPECT_FALSE(surfaceShim.graphicBufferProducer == nullptr);
+}
+
+INSTANTIATE_TEST_CASE_P(SurfaceBackends, SurfaceParcelableTest,
+                        ::testing::Values(CREATE_BUFFER_QUEUE_SURFACE, CREATE_BUFFER_HUB_SURFACE));
+
+} // namespace android
+
+int main(int argc, char** argv) {
+    pid_t pid = fork();
+    if (pid == 0) {
+        android::ProcessState::self()->startThreadPool();
+        ::testing::InitGoogleTest(&argc, argv);
+        return RUN_ALL_TESTS();
+
+    } else {
+        ALOGI("Test process pid: %d.", pid);
+        return android::runBinderServer();
+    }
+}
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index ca43c68..2c02ba6 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -22,6 +22,7 @@
 #include <binder/ProcessState.h>
 #include <configstore/Utils.h>
 #include <cutils/properties.h>
+#include <inttypes.h>
 #include <gui/BufferItemConsumer.h>
 #include <gui/IDisplayEventConnection.h>
 #include <gui/IProducerListener.h>
@@ -41,10 +42,16 @@
 // retrieve wide-color and hdr settings from configstore
 using namespace android::hardware::configstore;
 using namespace android::hardware::configstore::V1_0;
+using ui::ColorMode;
+
+using Transaction = SurfaceComposerClient::Transaction;
 
 static bool hasWideColorDisplay =
         getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasWideColorDisplay>(false);
 
+static bool hasHdrDisplay =
+        getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasHDRDisplay>(false);
+
 class FakeSurfaceComposer;
 class FakeProducerFrameEventHistory;
 
@@ -52,7 +59,6 @@
 
 class SurfaceTest : public ::testing::Test {
 protected:
-
     SurfaceTest() {
         ProcessState::self()->startThreadPool();
     }
@@ -69,10 +75,10 @@
         ASSERT_TRUE(mSurfaceControl != NULL);
         ASSERT_TRUE(mSurfaceControl->isValid());
 
-        SurfaceComposerClient::openGlobalTransaction();
-        ASSERT_EQ(NO_ERROR, mSurfaceControl->setLayer(0x7fffffff));
-        ASSERT_EQ(NO_ERROR, mSurfaceControl->show());
-        SurfaceComposerClient::closeGlobalTransaction();
+        Transaction t;
+        ASSERT_EQ(NO_ERROR, t.setLayer(mSurfaceControl, 0x7fffffff)
+                .show(mSurfaceControl)
+                .apply());
 
         mSurface = mSurfaceControl->getSurface();
         ASSERT_TRUE(mSurface != NULL);
@@ -87,6 +93,16 @@
     sp<SurfaceControl> mSurfaceControl;
 };
 
+TEST_F(SurfaceTest, CreateSurfaceReturnsErrorBadClient) {
+    mComposerClient->dispose();
+    ASSERT_EQ(NO_INIT, mComposerClient->initCheck());
+
+    sp<SurfaceControl> sc;
+    status_t err = mComposerClient->createSurfaceChecked(
+            String8("Test Surface"), 32, 32, PIXEL_FORMAT_RGBA_8888, &sc, 0);
+    ASSERT_EQ(NO_INIT, err);
+}
+
 TEST_F(SurfaceTest, QueuesToWindowComposerIsTrueWhenVisible) {
     sp<ANativeWindow> anw(mSurface);
     int result = -123;
@@ -114,14 +130,11 @@
     sp<ANativeWindow> anw(mSurface);
 
     // Verify the screenshot works with no protected buffers.
-    sp<IGraphicBufferProducer> producer;
-    sp<IGraphicBufferConsumer> consumer;
-    BufferQueue::createBufferQueue(&producer, &consumer);
-    sp<CpuConsumer> cpuConsumer = new CpuConsumer(consumer, 1);
     sp<ISurfaceComposer> sf(ComposerService::getComposerService());
     sp<IBinder> display(sf->getBuiltInDisplay(
             ISurfaceComposer::eDisplayIdMain));
-    ASSERT_EQ(NO_ERROR, sf->captureScreen(display, producer, Rect(),
+    sp<GraphicBuffer> outBuffer;
+    ASSERT_EQ(NO_ERROR, sf->captureScreen(display, &outBuffer, Rect(),
             64, 64, 0, 0x7fffffff, false));
 
     ASSERT_EQ(NO_ERROR, native_window_api_connect(anw.get(),
@@ -152,7 +165,7 @@
                 &buf));
         ASSERT_EQ(NO_ERROR, anw->queueBuffer(anw.get(), buf, -1));
     }
-    ASSERT_EQ(NO_ERROR, sf->captureScreen(display, producer, Rect(),
+    ASSERT_EQ(NO_ERROR, sf->captureScreen(display, &outBuffer, Rect(),
             64, 64, 0, 0x7fffffff, false));
 }
 
@@ -295,6 +308,68 @@
     ASSERT_EQ(hasWideColorDisplay, supported);
 }
 
+TEST_F(SurfaceTest, GetHdrSupport) {
+    sp<IGraphicBufferProducer> producer;
+    sp<IGraphicBufferConsumer> consumer;
+    BufferQueue::createBufferQueue(&producer, &consumer);
+
+    sp<DummyConsumer> dummyConsumer(new DummyConsumer);
+    consumer->consumerConnect(dummyConsumer, false);
+    consumer->setConsumerName(String8("TestConsumer"));
+
+    sp<Surface> surface = new Surface(producer);
+    sp<ANativeWindow> window(surface);
+    native_window_api_connect(window.get(), NATIVE_WINDOW_API_CPU);
+
+    bool supported;
+    status_t result = surface->getHdrSupport(&supported);
+    ASSERT_EQ(NO_ERROR, result);
+
+    // NOTE: This is not a CTS test.
+    // This test verifies that when the BoardConfig TARGET_HAS_HDR_DISPLAY
+    // is TRUE, getHdrSupport is also true.
+    // TODO: Add check for an HDR color mode on the primary display.
+    ASSERT_EQ(hasHdrDisplay, supported);
+}
+
+TEST_F(SurfaceTest, SetHdrMetadata) {
+    sp<IGraphicBufferProducer> producer;
+    sp<IGraphicBufferConsumer> consumer;
+    BufferQueue::createBufferQueue(&producer, &consumer);
+
+    sp<DummyConsumer> dummyConsumer(new DummyConsumer);
+    consumer->consumerConnect(dummyConsumer, false);
+    consumer->setConsumerName(String8("TestConsumer"));
+
+    sp<Surface> surface = new Surface(producer);
+    sp<ANativeWindow> window(surface);
+    native_window_api_connect(window.get(), NATIVE_WINDOW_API_CPU);
+
+    bool supported;
+    status_t result = surface->getHdrSupport(&supported);
+    ASSERT_EQ(NO_ERROR, result);
+
+    if (!hasHdrDisplay || !supported) {
+        return;
+    }
+    const android_smpte2086_metadata smpte2086 = {
+        {0.680, 0.320},
+        {0.265, 0.690},
+        {0.150, 0.060},
+        {0.3127, 0.3290},
+        100.0,
+        0.1,
+    };
+    const android_cta861_3_metadata cta861_3 = {
+        78.0,
+        62.0,
+    };
+    int error = native_window_set_buffers_smpte2086_metadata(window.get(), &smpte2086);
+    ASSERT_EQ(error, NO_ERROR);
+    error = native_window_set_buffers_cta861_3_metadata(window.get(), &cta861_3);
+    ASSERT_EQ(error, NO_ERROR);
+}
+
 TEST_F(SurfaceTest, DynamicSetBufferCount) {
     sp<IGraphicBufferProducer> producer;
     sp<IGraphicBufferConsumer> consumer;
@@ -512,21 +587,26 @@
         return NO_ERROR;
     }
     status_t getDisplayColorModes(const sp<IBinder>& /*display*/,
-            Vector<android_color_mode_t>* /*outColorModes*/) override {
+            Vector<ColorMode>* /*outColorModes*/) override {
         return NO_ERROR;
     }
-    android_color_mode_t getActiveColorMode(const sp<IBinder>& /*display*/)
+    ColorMode getActiveColorMode(const sp<IBinder>& /*display*/)
             override {
-        return HAL_COLOR_MODE_NATIVE;
+        return ColorMode::NATIVE;
     }
     status_t setActiveColorMode(const sp<IBinder>& /*display*/,
-            android_color_mode_t /*colorMode*/) override { return NO_ERROR; }
+        ColorMode /*colorMode*/) override { return NO_ERROR; }
     status_t captureScreen(const sp<IBinder>& /*display*/,
-            const sp<IGraphicBufferProducer>& /*producer*/,
+            sp<GraphicBuffer>* /*outBuffer*/,
             Rect /*sourceCrop*/, uint32_t /*reqWidth*/, uint32_t /*reqHeight*/,
             int32_t /*minLayerZ*/, int32_t /*maxLayerZ*/,
             bool /*useIdentityTransform*/,
             Rotation /*rotation*/) override { return NO_ERROR; }
+    virtual status_t captureLayers(const sp<IBinder>& /*parentHandle*/,
+                                   sp<GraphicBuffer>* /*outBuffer*/, const Rect& /*sourceCrop*/,
+                                   float /*frameScale*/, bool /*childrenOnly*/) override {
+        return NO_ERROR;
+    }
     status_t clearAnimationFrameStats() override { return NO_ERROR; }
     status_t getAnimationFrameStats(FrameStats* /*outStats*/) const override {
         return NO_ERROR;
@@ -800,7 +880,7 @@
                 (iOldFrame == NO_FRAME_INDEX) ? nullptr : &mFrames[iOldFrame];
         FrameEvents* newFrame = &mFrames[iNewFrame];
 
-        uint64_t nOldFrame = iOldFrame + 1;
+        uint64_t nOldFrame = (iOldFrame == NO_FRAME_INDEX) ? 0 : iOldFrame + 1;
         uint64_t nNewFrame = iNewFrame + 1;
 
         // Latch, Composite, and Release the frames in a plausible order.
diff --git a/libs/gui/view/Surface.cpp b/libs/gui/view/Surface.cpp
index 5ed3d3b..d64dfd5 100644
--- a/libs/gui/view/Surface.cpp
+++ b/libs/gui/view/Surface.cpp
@@ -45,10 +45,7 @@
         if (res != OK) return res;
     }
 
-    res = parcel->writeStrongBinder(
-            IGraphicBufferProducer::asBinder(graphicBufferProducer));
-
-    return res;
+    return IGraphicBufferProducer::exportToParcel(graphicBufferProducer, parcel);
 }
 
 status_t Surface::readFromParcel(const Parcel* parcel) {
@@ -70,16 +67,7 @@
         }
     }
 
-    sp<IBinder> binder;
-
-    res = parcel->readNullableStrongBinder(&binder);
-    if (res != OK) {
-        ALOGE("%s: Can't read strong binder", __FUNCTION__);
-        return res;
-    }
-
-    graphicBufferProducer = interface_cast<IGraphicBufferProducer>(binder);
-
+    graphicBufferProducer = IGraphicBufferProducer::createFromParcel(parcel);
     return OK;
 }
 
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index 905d336..aa0bf17 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -99,34 +99,34 @@
 
 // --- InputChannel ---
 
-InputChannel::InputChannel(const String8& name, int fd) :
+InputChannel::InputChannel(const std::string& name, int fd) :
         mName(name), mFd(fd) {
 #if DEBUG_CHANNEL_LIFECYCLE
     ALOGD("Input channel constructed: name='%s', fd=%d",
-            mName.string(), fd);
+            mName.c_str(), fd);
 #endif
 
     int result = fcntl(mFd, F_SETFL, O_NONBLOCK);
     LOG_ALWAYS_FATAL_IF(result != 0, "channel '%s' ~ Could not make socket "
-            "non-blocking.  errno=%d", mName.string(), errno);
+            "non-blocking.  errno=%d", mName.c_str(), errno);
 }
 
 InputChannel::~InputChannel() {
 #if DEBUG_CHANNEL_LIFECYCLE
     ALOGD("Input channel destroyed: name='%s', fd=%d",
-            mName.string(), mFd);
+            mName.c_str(), mFd);
 #endif
 
     ::close(mFd);
 }
 
-status_t InputChannel::openInputChannelPair(const String8& name,
+status_t InputChannel::openInputChannelPair(const std::string& name,
         sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {
     int sockets[2];
     if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {
         status_t result = -errno;
         ALOGE("channel '%s' ~ Could not create socket pair.  errno=%d",
-                name.string(), errno);
+                name.c_str(), errno);
         outServerChannel.clear();
         outClientChannel.clear();
         return result;
@@ -138,12 +138,12 @@
     setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
     setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));
 
-    String8 serverChannelName = name;
-    serverChannelName.append(" (server)");
+    std::string serverChannelName = name;
+    serverChannelName += " (server)";
     outServerChannel = new InputChannel(serverChannelName, sockets[0]);
 
-    String8 clientChannelName = name;
-    clientChannelName.append(" (client)");
+    std::string clientChannelName = name;
+    clientChannelName += " (client)";
     outClientChannel = new InputChannel(clientChannelName, sockets[1]);
     return OK;
 }
@@ -158,7 +158,7 @@
     if (nWrite < 0) {
         int error = errno;
 #if DEBUG_CHANNEL_MESSAGES
-        ALOGD("channel '%s' ~ error sending message of type %d, errno=%d", mName.string(),
+        ALOGD("channel '%s' ~ error sending message of type %d, errno=%d", mName.c_str(),
                 msg->header.type, error);
 #endif
         if (error == EAGAIN || error == EWOULDBLOCK) {
@@ -173,13 +173,13 @@
     if (size_t(nWrite) != msgLength) {
 #if DEBUG_CHANNEL_MESSAGES
         ALOGD("channel '%s' ~ error sending message type %d, send was incomplete",
-                mName.string(), msg->header.type);
+                mName.c_str(), msg->header.type);
 #endif
         return DEAD_OBJECT;
     }
 
 #if DEBUG_CHANNEL_MESSAGES
-    ALOGD("channel '%s' ~ sent message of type %d", mName.string(), msg->header.type);
+    ALOGD("channel '%s' ~ sent message of type %d", mName.c_str(), msg->header.type);
 #endif
     return OK;
 }
@@ -193,7 +193,7 @@
     if (nRead < 0) {
         int error = errno;
 #if DEBUG_CHANNEL_MESSAGES
-        ALOGD("channel '%s' ~ receive message failed, errno=%d", mName.string(), errno);
+        ALOGD("channel '%s' ~ receive message failed, errno=%d", mName.c_str(), errno);
 #endif
         if (error == EAGAIN || error == EWOULDBLOCK) {
             return WOULD_BLOCK;
@@ -206,20 +206,20 @@
 
     if (nRead == 0) { // check for EOF
 #if DEBUG_CHANNEL_MESSAGES
-        ALOGD("channel '%s' ~ receive message failed because peer was closed", mName.string());
+        ALOGD("channel '%s' ~ receive message failed because peer was closed", mName.c_str());
 #endif
         return DEAD_OBJECT;
     }
 
     if (!msg->isValid(nRead)) {
 #if DEBUG_CHANNEL_MESSAGES
-        ALOGD("channel '%s' ~ received invalid message", mName.string());
+        ALOGD("channel '%s' ~ received invalid message", mName.c_str());
 #endif
         return BAD_VALUE;
     }
 
 #if DEBUG_CHANNEL_MESSAGES
-    ALOGD("channel '%s' ~ received message of type %d", mName.string(), msg->header.type);
+    ALOGD("channel '%s' ~ received message of type %d", mName.c_str(), msg->header.type);
 #endif
     return OK;
 }
@@ -254,8 +254,8 @@
 #if DEBUG_TRANSPORT_ACTIONS
     ALOGD("channel '%s' publisher ~ publishKeyEvent: seq=%u, deviceId=%d, source=0x%x, "
             "action=0x%x, flags=0x%x, keyCode=%d, scanCode=%d, metaState=0x%x, repeatCount=%d,"
-            "downTime=%lld, eventTime=%lld",
-            mChannel->getName().string(), seq,
+            "downTime=%" PRId64 ", eventTime=%" PRId64,
+            mChannel->getName().c_str(), seq,
             deviceId, source, action, flags, keyCode, scanCode, metaState, repeatCount,
             downTime, eventTime);
 #endif
@@ -305,9 +305,9 @@
     ALOGD("channel '%s' publisher ~ publishMotionEvent: seq=%u, deviceId=%d, source=0x%x, "
             "action=0x%x, actionButton=0x%08x, flags=0x%x, edgeFlags=0x%x, "
             "metaState=0x%x, buttonState=0x%x, xOffset=%f, yOffset=%f, "
-            "xPrecision=%f, yPrecision=%f, downTime=%lld, eventTime=%lld, "
+            "xPrecision=%f, yPrecision=%f, downTime=%" PRId64 ", eventTime=%" PRId64 ", "
             "pointerCount=%" PRIu32,
-            mChannel->getName().string(), seq,
+            mChannel->getName().c_str(), seq,
             deviceId, source, action, actionButton, flags, edgeFlags, metaState, buttonState,
             xOffset, yOffset, xPrecision, yPrecision, downTime, eventTime, pointerCount);
 #endif
@@ -319,7 +319,7 @@
 
     if (pointerCount > MAX_POINTERS || pointerCount < 1) {
         ALOGE("channel '%s' publisher ~ Invalid number of pointers provided: %" PRIu32 ".",
-                mChannel->getName().string(), pointerCount);
+                mChannel->getName().c_str(), pointerCount);
         return BAD_VALUE;
     }
 
@@ -352,7 +352,7 @@
 status_t InputPublisher::receiveFinishedSignal(uint32_t* outSeq, bool* outHandled) {
 #if DEBUG_TRANSPORT_ACTIONS
     ALOGD("channel '%s' publisher ~ receiveFinishedSignal",
-            mChannel->getName().string());
+            mChannel->getName().c_str());
 #endif
 
     InputMessage msg;
@@ -364,7 +364,7 @@
     }
     if (msg.header.type != InputMessage::TYPE_FINISHED) {
         ALOGE("channel '%s' publisher ~ Received unexpected message of type %d from consumer",
-                mChannel->getName().string(), msg.header.type);
+                mChannel->getName().c_str(), msg.header.type);
         return UNKNOWN_ERROR;
     }
     *outSeq = msg.body.finished.seq;
@@ -401,8 +401,8 @@
         bool consumeBatches, nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent,
         int32_t* displayId) {
 #if DEBUG_TRANSPORT_ACTIONS
-    ALOGD("channel '%s' consumer ~ consume: consumeBatches=%s, frameTime=%lld",
-            mChannel->getName().string(), consumeBatches ? "true" : "false", frameTime);
+    ALOGD("channel '%s' consumer ~ consume: consumeBatches=%s, frameTime=%" PRId64,
+            mChannel->getName().c_str(), consumeBatches ? "true" : "false", frameTime);
 #endif
 
     *outSeq = 0;
@@ -426,7 +426,7 @@
                     if (*outEvent) {
 #if DEBUG_TRANSPORT_ACTIONS
                         ALOGD("channel '%s' consumer ~ consumed batch event, seq=%u",
-                                mChannel->getName().string(), *outSeq);
+                                mChannel->getName().c_str(), *outSeq);
 #endif
                         break;
                     }
@@ -445,7 +445,7 @@
             *outEvent = keyEvent;
 #if DEBUG_TRANSPORT_ACTIONS
             ALOGD("channel '%s' consumer ~ consumed key event, seq=%u",
-                    mChannel->getName().string(), *outSeq);
+                    mChannel->getName().c_str(), *outSeq);
 #endif
             break;
         }
@@ -458,7 +458,7 @@
                     batch.samples.push(mMsg);
 #if DEBUG_TRANSPORT_ACTIONS
                     ALOGD("channel '%s' consumer ~ appended to batch event",
-                            mChannel->getName().string());
+                            mChannel->getName().c_str());
 #endif
                     break;
                 } else {
@@ -474,7 +474,7 @@
 #if DEBUG_TRANSPORT_ACTIONS
                     ALOGD("channel '%s' consumer ~ consumed batch event and "
                             "deferred current event, seq=%u",
-                            mChannel->getName().string(), *outSeq);
+                            mChannel->getName().c_str(), *outSeq);
 #endif
                     break;
                 }
@@ -488,7 +488,7 @@
                 batch.samples.push(mMsg);
 #if DEBUG_TRANSPORT_ACTIONS
                 ALOGD("channel '%s' consumer ~ started batch event",
-                        mChannel->getName().string());
+                        mChannel->getName().c_str());
 #endif
                 break;
             }
@@ -503,14 +503,14 @@
             *displayId = mMsg.body.motion.displayId;
 #if DEBUG_TRANSPORT_ACTIONS
             ALOGD("channel '%s' consumer ~ consumed motion event, seq=%u",
-                    mChannel->getName().string(), *outSeq);
+                    mChannel->getName().c_str(), *outSeq);
 #endif
             break;
         }
 
         default:
             ALOGE("channel '%s' consumer ~ Received unexpected message of type %d",
-                    mChannel->getName().string(), mMsg.header.type);
+                    mChannel->getName().c_str(), mMsg.header.type);
             return UNKNOWN_ERROR;
         }
     }
@@ -841,7 +841,7 @@
 status_t InputConsumer::sendFinishedSignal(uint32_t seq, bool handled) {
 #if DEBUG_TRANSPORT_ACTIONS
     ALOGD("channel '%s' consumer ~ sendFinishedSignal: seq=%u, handled=%s",
-            mChannel->getName().string(), seq, handled ? "true" : "false");
+            mChannel->getName().c_str(), seq, handled ? "true" : "false");
 #endif
 
     if (!seq) {
diff --git a/libs/input/KeyCharacterMap.cpp b/libs/input/KeyCharacterMap.cpp
index 0627ca6..cba1111 100644
--- a/libs/input/KeyCharacterMap.cpp
+++ b/libs/input/KeyCharacterMap.cpp
@@ -824,6 +824,9 @@
     } else if (typeToken == "FULL") {
         type = KEYBOARD_TYPE_FULL;
     } else if (typeToken == "SPECIAL_FUNCTION") {
+        ALOGW("The SPECIAL_FUNCTION type is now declared in the device's IDC file, please set "
+                "the property 'keyboard.specialFunction' to '1' there instead.");
+        // TODO: return BAD_VALUE here in Q
         type = KEYBOARD_TYPE_SPECIAL_FUNCTION;
     } else if (typeToken == "OVERLAY") {
         type = KEYBOARD_TYPE_OVERLAY;
diff --git a/libs/input/Keyboard.cpp b/libs/input/Keyboard.cpp
index 07f2289..11842ee 100644
--- a/libs/input/Keyboard.cpp
+++ b/libs/input/Keyboard.cpp
@@ -148,9 +148,19 @@
 
 // --- Global functions ---
 
+bool isKeyboardSpecialFunction(const PropertyMap* config) {
+    if (config == nullptr) {
+        return false;
+    }
+    bool isSpecialFunction = false;
+    config->tryGetProperty(String8("keyboard.specialFunction"), isSpecialFunction);
+    return isSpecialFunction;
+}
+
 bool isEligibleBuiltInKeyboard(const InputDeviceIdentifier& deviceIdentifier,
         const PropertyMap* deviceConfiguration, const KeyMap* keyMap) {
-    if (!keyMap->haveKeyCharacterMap()
+    // TODO: remove the third OR statement (SPECIAL_FUNCTION) in Q
+    if (!keyMap->haveKeyCharacterMap() || isKeyboardSpecialFunction(deviceConfiguration)
             || keyMap->keyCharacterMap->getKeyboardType()
                     == KeyCharacterMap::KEYBOARD_TYPE_SPECIAL_FUNCTION) {
         return false;
diff --git a/libs/input/VelocityTracker.cpp b/libs/input/VelocityTracker.cpp
index 62acea3..c07a812 100644
--- a/libs/input/VelocityTracker.cpp
+++ b/libs/input/VelocityTracker.cpp
@@ -75,7 +75,9 @@
     str += " ]";
     return str;
 }
+#endif
 
+#if DEBUG_STRATEGY
 static std::string matrixToString(const float* a, uint32_t m, uint32_t n, bool rowMajor) {
     std::string str;
     str = "[";
@@ -141,6 +143,11 @@
 }
 
 VelocityTrackerStrategy* VelocityTracker::createStrategy(const char* strategy) {
+    if (!strcmp("impulse", strategy)) {
+        // Physical model of pushing an object.  Quality: VERY GOOD.
+        // Works with duplicate coordinates, unclean finger liftoff.
+        return new ImpulseVelocityTrackerStrategy();
+    }
     if (!strcmp("lsq1", strategy)) {
         // 1st order least squares.  Quality: POOR.
         // Frequently underfits the touch data especially when the finger accelerates
@@ -318,8 +325,8 @@
         eventTime = event->getHistoricalEventTime(h);
         for (size_t i = 0; i < pointerCount; i++) {
             uint32_t index = pointerIndex[i];
-            positions[index].x = event->getHistoricalX(i, h);
-            positions[index].y = event->getHistoricalY(i, h);
+            positions[index].x = event->getHistoricalRawX(i, h);
+            positions[index].y = event->getHistoricalRawY(i, h);
         }
         addMovement(eventTime, idBits, positions);
     }
@@ -327,8 +334,8 @@
     eventTime = event->getEventTime();
     for (size_t i = 0; i < pointerCount; i++) {
         uint32_t index = pointerIndex[i];
-        positions[index].x = event->getX(i);
-        positions[index].y = event->getY(i);
+        positions[index].x = event->getRawX(i);
+        positions[index].y = event->getRawY(i);
     }
     addMovement(eventTime, idBits, positions);
 }
@@ -352,9 +359,6 @@
 
 // --- LeastSquaresVelocityTrackerStrategy ---
 
-const nsecs_t LeastSquaresVelocityTrackerStrategy::HORIZON;
-const uint32_t LeastSquaresVelocityTrackerStrategy::HISTORY_SIZE;
-
 LeastSquaresVelocityTrackerStrategy::LeastSquaresVelocityTrackerStrategy(
         uint32_t degree, Weighting weighting) :
         mDegree(degree), mWeighting(weighting) {
@@ -863,10 +867,6 @@
 
 // --- LegacyVelocityTrackerStrategy ---
 
-const nsecs_t LegacyVelocityTrackerStrategy::HORIZON;
-const uint32_t LegacyVelocityTrackerStrategy::HISTORY_SIZE;
-const nsecs_t LegacyVelocityTrackerStrategy::MIN_DURATION;
-
 LegacyVelocityTrackerStrategy::LegacyVelocityTrackerStrategy() {
     clear();
 }
@@ -979,4 +979,194 @@
     return true;
 }
 
+// --- ImpulseVelocityTrackerStrategy ---
+
+ImpulseVelocityTrackerStrategy::ImpulseVelocityTrackerStrategy() {
+    clear();
+}
+
+ImpulseVelocityTrackerStrategy::~ImpulseVelocityTrackerStrategy() {
+}
+
+void ImpulseVelocityTrackerStrategy::clear() {
+    mIndex = 0;
+    mMovements[0].idBits.clear();
+}
+
+void ImpulseVelocityTrackerStrategy::clearPointers(BitSet32 idBits) {
+    BitSet32 remainingIdBits(mMovements[mIndex].idBits.value & ~idBits.value);
+    mMovements[mIndex].idBits = remainingIdBits;
+}
+
+void ImpulseVelocityTrackerStrategy::addMovement(nsecs_t eventTime, BitSet32 idBits,
+        const VelocityTracker::Position* positions) {
+    if (++mIndex == HISTORY_SIZE) {
+        mIndex = 0;
+    }
+
+    Movement& movement = mMovements[mIndex];
+    movement.eventTime = eventTime;
+    movement.idBits = idBits;
+    uint32_t count = idBits.count();
+    for (uint32_t i = 0; i < count; i++) {
+        movement.positions[i] = positions[i];
+    }
+}
+
+/**
+ * Calculate the total impulse provided to the screen and the resulting velocity.
+ *
+ * The touchscreen is modeled as a physical object.
+ * Initial condition is discussed below, but for now suppose that v(t=0) = 0
+ *
+ * The kinetic energy of the object at the release is E=0.5*m*v^2
+ * Then vfinal = sqrt(2E/m). The goal is to calculate E.
+ *
+ * The kinetic energy at the release is equal to the total work done on the object by the finger.
+ * The total work W is the sum of all dW along the path.
+ *
+ * dW = F*dx, where dx is the piece of path traveled.
+ * Force is change of momentum over time, F = dp/dt = m dv/dt.
+ * Then substituting:
+ * dW = m (dv/dt) * dx = m * v * dv
+ *
+ * Summing along the path, we get:
+ * W = sum(dW) = sum(m * v * dv) = m * sum(v * dv)
+ * Since the mass stays constant, the equation for final velocity is:
+ * vfinal = sqrt(2*sum(v * dv))
+ *
+ * Here,
+ * dv : change of velocity = (v[i+1]-v[i])
+ * dx : change of distance = (x[i+1]-x[i])
+ * dt : change of time = (t[i+1]-t[i])
+ * v : instantaneous velocity = dx/dt
+ *
+ * The final formula is:
+ * vfinal = sqrt(2) * sqrt(sum((v[i]-v[i-1])*|v[i]|)) for all i
+ * The absolute value is needed to properly account for the sign. If the velocity over a
+ * particular segment descreases, then this indicates braking, which means that negative
+ * work was done. So for two positive, but decreasing, velocities, this contribution would be
+ * negative and will cause a smaller final velocity.
+ *
+ * Initial condition
+ * There are two ways to deal with initial condition:
+ * 1) Assume that v(0) = 0, which would mean that the screen is initially at rest.
+ * This is not entirely accurate. We are only taking the past X ms of touch data, where X is
+ * currently equal to 100. However, a touch event that created a fling probably lasted for longer
+ * than that, which would mean that the user has already been interacting with the touchscreen
+ * and it has probably already been moving.
+ * 2) Assume that the touchscreen has already been moving at a certain velocity, calculate this
+ * initial velocity and the equivalent energy, and start with this initial energy.
+ * Consider an example where we have the following data, consisting of 3 points:
+ *                 time: t0, t1, t2
+ *                 x   : x0, x1, x2
+ *                 v   : 0 , v1, v2
+ * Here is what will happen in each of these scenarios:
+ * 1) By directly applying the formula above with the v(0) = 0 boundary condition, we will get
+ * vfinal = sqrt(2*(|v1|*(v1-v0) + |v2|*(v2-v1))). This can be simplified since v0=0
+ * vfinal = sqrt(2*(|v1|*v1 + |v2|*(v2-v1))) = sqrt(2*(v1^2 + |v2|*(v2 - v1)))
+ * since velocity is a real number
+ * 2) If we treat the screen as already moving, then it must already have an energy (per mass)
+ * equal to 1/2*v1^2. Then the initial energy should be 1/2*v1*2, and only the second segment
+ * will contribute to the total kinetic energy (since we can effectively consider that v0=v1).
+ * This will give the following expression for the final velocity:
+ * vfinal = sqrt(2*(1/2*v1^2 + |v2|*(v2-v1)))
+ * This analysis can be generalized to an arbitrary number of samples.
+ *
+ *
+ * Comparing the two equations above, we see that the only mathematical difference
+ * is the factor of 1/2 in front of the first velocity term.
+ * This boundary condition would allow for the "proper" calculation of the case when all of the
+ * samples are equally spaced in time and distance, which should suggest a constant velocity.
+ *
+ * Note that approach 2) is sensitive to the proper ordering of the data in time, since
+ * the boundary condition must be applied to the oldest sample to be accurate.
+ */
+static float kineticEnergyToVelocity(float work) {
+    static constexpr float sqrt2 = 1.41421356237;
+    return (work < 0 ? -1.0 : 1.0) * sqrtf(fabsf(work)) * sqrt2;
+}
+
+static float calculateImpulseVelocity(const nsecs_t* t, const float* x, size_t count) {
+    // The input should be in reversed time order (most recent sample at index i=0)
+    // t[i] is in nanoseconds, but due to FP arithmetic, convert to seconds inside this function
+    static constexpr float SECONDS_PER_NANO = 1E-9;
+
+    if (count < 2) {
+        return 0; // if 0 or 1 points, velocity is zero
+    }
+    if (t[1] > t[0]) { // Algorithm will still work, but not perfectly
+        ALOGE("Samples provided to calculateImpulseVelocity in the wrong order");
+    }
+    if (count == 2) { // if 2 points, basic linear calculation
+        if (t[1] == t[0]) {
+            ALOGE("Events have identical time stamps t=%" PRId64 ", setting velocity = 0", t[0]);
+            return 0;
+        }
+        return (x[1] - x[0]) / (SECONDS_PER_NANO * (t[1] - t[0]));
+    }
+    // Guaranteed to have at least 3 points here
+    float work = 0;
+    for (size_t i = count - 1; i > 0 ; i--) { // start with the oldest sample and go forward in time
+        if (t[i] == t[i-1]) {
+            ALOGE("Events have identical time stamps t=%" PRId64 ", skipping sample", t[i]);
+            continue;
+        }
+        float vprev = kineticEnergyToVelocity(work); // v[i-1]
+        float vcurr = (x[i] - x[i-1]) / (SECONDS_PER_NANO * (t[i] - t[i-1])); // v[i]
+        work += (vcurr - vprev) * fabsf(vcurr);
+        if (i == count - 1) {
+            work *= 0.5; // initial condition, case 2) above
+        }
+    }
+    return kineticEnergyToVelocity(work);
+}
+
+bool ImpulseVelocityTrackerStrategy::getEstimator(uint32_t id,
+        VelocityTracker::Estimator* outEstimator) const {
+    outEstimator->clear();
+
+    // Iterate over movement samples in reverse time order and collect samples.
+    float x[HISTORY_SIZE];
+    float y[HISTORY_SIZE];
+    nsecs_t time[HISTORY_SIZE];
+    size_t m = 0; // number of points that will be used for fitting
+    size_t index = mIndex;
+    const Movement& newestMovement = mMovements[mIndex];
+    do {
+        const Movement& movement = mMovements[index];
+        if (!movement.idBits.hasBit(id)) {
+            break;
+        }
+
+        nsecs_t age = newestMovement.eventTime - movement.eventTime;
+        if (age > HORIZON) {
+            break;
+        }
+
+        const VelocityTracker::Position& position = movement.getPosition(id);
+        x[m] = position.x;
+        y[m] = position.y;
+        time[m] = movement.eventTime;
+        index = (index == 0 ? HISTORY_SIZE : index) - 1;
+    } while (++m < HISTORY_SIZE);
+
+    if (m == 0) {
+        return false; // no data
+    }
+    outEstimator->xCoeff[0] = 0;
+    outEstimator->yCoeff[0] = 0;
+    outEstimator->xCoeff[1] = calculateImpulseVelocity(time, x, m);
+    outEstimator->yCoeff[1] = calculateImpulseVelocity(time, y, m);
+    outEstimator->xCoeff[2] = 0;
+    outEstimator->yCoeff[2] = 0;
+    outEstimator->time = newestMovement.eventTime;
+    outEstimator->degree = 2; // similar results to 2nd degree fit
+    outEstimator->confidence = 1;
+#if DEBUG_STRATEGY
+    ALOGD("velocity: (%f, %f)", outEstimator->xCoeff[1], outEstimator->yCoeff[1]);
+#endif
+    return true;
+}
+
 } // namespace android
diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp
index 8137e3d..aca9521 100644
--- a/libs/input/tests/Android.bp
+++ b/libs/input/tests/Android.bp
@@ -6,6 +6,7 @@
         "InputChannel_test.cpp",
         "InputEvent_test.cpp",
         "InputPublisherAndConsumer_test.cpp",
+        "VelocityTracker_test.cpp",
     ],
     cflags: [
         "-Wall",
@@ -19,6 +20,7 @@
         "libutils",
         "libbinder",
         "libui",
+        "libbase",
     ]
 }
 
diff --git a/libs/input/tests/InputChannel_test.cpp b/libs/input/tests/InputChannel_test.cpp
index e71ebe2..96c165c 100644
--- a/libs/input/tests/InputChannel_test.cpp
+++ b/libs/input/tests/InputChannel_test.cpp
@@ -41,9 +41,9 @@
     // of a pipe and to check for EPIPE on the other end after the channel is destroyed.
     Pipe pipe;
 
-    sp<InputChannel> inputChannel = new InputChannel(String8("channel name"), pipe.sendFd);
+    sp<InputChannel> inputChannel = new InputChannel("channel name", pipe.sendFd);
 
-    EXPECT_STREQ("channel name", inputChannel->getName().string())
+    EXPECT_STREQ("channel name", inputChannel->getName().c_str())
             << "channel should have provided name";
     EXPECT_EQ(pipe.sendFd, inputChannel->getFd())
             << "channel should have provided fd";
@@ -60,16 +60,16 @@
 TEST_F(InputChannelTest, OpenInputChannelPair_ReturnsAPairOfConnectedChannels) {
     sp<InputChannel> serverChannel, clientChannel;
 
-    status_t result = InputChannel::openInputChannelPair(String8("channel name"),
+    status_t result = InputChannel::openInputChannelPair("channel name",
             serverChannel, clientChannel);
 
     ASSERT_EQ(OK, result)
             << "should have successfully opened a channel pair";
 
     // Name
-    EXPECT_STREQ("channel name (server)", serverChannel->getName().string())
+    EXPECT_STREQ("channel name (server)", serverChannel->getName().c_str())
             << "server channel should have suffixed name";
-    EXPECT_STREQ("channel name (client)", clientChannel->getName().string())
+    EXPECT_STREQ("channel name (client)", clientChannel->getName().c_str())
             << "client channel should have suffixed name";
 
     // Server->Client communication
@@ -111,7 +111,7 @@
 TEST_F(InputChannelTest, ReceiveSignal_WhenNoSignalPresent_ReturnsAnError) {
     sp<InputChannel> serverChannel, clientChannel;
 
-    status_t result = InputChannel::openInputChannelPair(String8("channel name"),
+    status_t result = InputChannel::openInputChannelPair("channel name",
             serverChannel, clientChannel);
 
     ASSERT_EQ(OK, result)
@@ -125,7 +125,7 @@
 TEST_F(InputChannelTest, ReceiveSignal_WhenPeerClosed_ReturnsAnError) {
     sp<InputChannel> serverChannel, clientChannel;
 
-    status_t result = InputChannel::openInputChannelPair(String8("channel name"),
+    status_t result = InputChannel::openInputChannelPair("channel name",
             serverChannel, clientChannel);
 
     ASSERT_EQ(OK, result)
@@ -141,7 +141,7 @@
 TEST_F(InputChannelTest, SendSignal_WhenPeerClosed_ReturnsAnError) {
     sp<InputChannel> serverChannel, clientChannel;
 
-    status_t result = InputChannel::openInputChannelPair(String8("channel name"),
+    status_t result = InputChannel::openInputChannelPair("channel name",
             serverChannel, clientChannel);
 
     ASSERT_EQ(OK, result)
diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp
index 34c52d0..c532241 100644
--- a/libs/input/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp
@@ -36,7 +36,7 @@
     PreallocatedInputEventFactory mEventFactory;
 
     virtual void SetUp() {
-        status_t result = InputChannel::openInputChannelPair(String8("channel name"),
+        status_t result = InputChannel::openInputChannelPair("channel name",
                 serverChannel, clientChannel);
 
         mPublisher = new InputPublisher(serverChannel);
@@ -254,11 +254,15 @@
     ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent());
 }
 
-TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountLessThan1_ReturnsError) {
+TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenSequenceNumberIsZero_ReturnsError) {
     status_t status;
-    const size_t pointerCount = 0;
+    const size_t pointerCount = 1;
     PointerProperties pointerProperties[pointerCount];
     PointerCoords pointerCoords[pointerCount];
+    for (size_t i = 0; i < pointerCount; i++) {
+        pointerProperties[i].clear();
+        pointerCoords[i].clear();
+    }
 
     status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
             pointerCount, pointerProperties, pointerCoords);
@@ -266,7 +270,20 @@
             << "publisher publishMotionEvent should return BAD_VALUE";
 }
 
-TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountGreaterThanMax_ReturnsError) {
+TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountLessThan1_ReturnsError) {
+    status_t status;
+    const size_t pointerCount = 0;
+    PointerProperties pointerProperties[pointerCount];
+    PointerCoords pointerCoords[pointerCount];
+
+    status = mPublisher->publishMotionEvent(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+            pointerCount, pointerProperties, pointerCoords);
+    ASSERT_EQ(BAD_VALUE, status)
+            << "publisher publishMotionEvent should return BAD_VALUE";
+}
+
+TEST_F(InputPublisherAndConsumerTest,
+        PublishMotionEvent_WhenPointerCountGreaterThanMax_ReturnsError) {
     status_t status;
     const size_t pointerCount = MAX_POINTERS + 1;
     PointerProperties pointerProperties[pointerCount];
@@ -276,7 +293,7 @@
         pointerCoords[i].clear();
     }
 
-    status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    status = mPublisher->publishMotionEvent(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
             pointerCount, pointerProperties, pointerCoords);
     ASSERT_EQ(BAD_VALUE, status)
             << "publisher publishMotionEvent should return BAD_VALUE";
diff --git a/libs/input/tests/VelocityTracker_test.cpp b/libs/input/tests/VelocityTracker_test.cpp
new file mode 100644
index 0000000..43b6012
--- /dev/null
+++ b/libs/input/tests/VelocityTracker_test.cpp
@@ -0,0 +1,664 @@
+/*
+ * 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 "VelocityTracker_test"
+
+#include <math.h>
+
+#include <android-base/stringprintf.h>
+#include <gtest/gtest.h>
+#include <input/VelocityTracker.h>
+
+using android::base::StringPrintf;
+
+namespace android {
+
+constexpr int32_t DEFAULT_POINTER_ID = 0; // pointer ID used for manually defined tests
+
+// velocity must be in the range (1-tol)*EV <= velocity <= (1+tol)*EV
+// here EV = expected value, tol = VELOCITY_TOLERANCE
+constexpr float VELOCITY_TOLERANCE = 0.2;
+
+// --- VelocityTrackerTest ---
+class VelocityTrackerTest : public testing::Test { };
+
+static void checkVelocity(float Vactual, float Vtarget) {
+    // Compare directions
+    if ((Vactual > 0 && Vtarget <= 0) || (Vactual < 0 && Vtarget >= 0)) {
+        FAIL() << StringPrintf("Velocity %f does not have the same direction"
+                " as the target velocity %f", Vactual, Vtarget);
+    }
+
+    // Compare magnitudes
+    const float Vlower = fabsf(Vtarget * (1 - VELOCITY_TOLERANCE));
+    const float Vupper = fabsf(Vtarget * (1 + VELOCITY_TOLERANCE));
+    if (fabsf(Vactual) < Vlower) {
+        FAIL() << StringPrintf("Velocity %f is more than %.0f%% below target velocity %f",
+                Vactual, VELOCITY_TOLERANCE * 100, Vtarget);
+    }
+    if (fabsf(Vactual) > Vupper) {
+        FAIL() << StringPrintf("Velocity %f is more than %.0f%% above target velocity %f",
+                Vactual, VELOCITY_TOLERANCE * 100, Vtarget);
+    }
+    SUCCEED() << StringPrintf("Velocity %f within %.0f%% of target %f)",
+            Vactual, VELOCITY_TOLERANCE * 100, Vtarget);
+}
+
+void failWithMessage(std::string message) {
+    FAIL() << message; // cannot do this directly from a non-void function
+}
+
+struct Position {
+      nsecs_t time;
+      float x;
+      float y;
+};
+
+
+MotionEvent* createSimpleMotionEvent(const Position* positions, size_t numSamples) {
+    /**
+     * Only populate the basic fields of a MotionEvent, such as time and a single axis
+     * Designed for use with manually-defined tests.
+     * Create a new MotionEvent on the heap, caller responsible for destroying the object.
+     */
+    if (numSamples < 1) {
+        failWithMessage(StringPrintf("Need at least 1 sample to create a MotionEvent."
+                " Received numSamples=%zu", numSamples));
+    }
+
+    MotionEvent* event = new MotionEvent();
+    PointerCoords coords;
+    PointerProperties properties[1];
+
+    properties[0].id = DEFAULT_POINTER_ID;
+    properties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
+
+    // First sample added separately with initialize
+    coords.setAxisValue(AMOTION_EVENT_AXIS_X, positions[0].x);
+    coords.setAxisValue(AMOTION_EVENT_AXIS_Y, positions[0].y);
+    event->initialize(0, AINPUT_SOURCE_TOUCHSCREEN, AMOTION_EVENT_ACTION_MOVE,
+            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, positions[0].time, 1, properties, &coords);
+
+    for (size_t i = 1; i < numSamples; i++) {
+        coords.setAxisValue(AMOTION_EVENT_AXIS_X, positions[i].x);
+        coords.setAxisValue(AMOTION_EVENT_AXIS_Y, positions[i].y);
+        event->addSample(positions[i].time, &coords);
+    }
+    return event;
+}
+
+static void computeAndCheckVelocity(const Position* positions, size_t numSamples,
+            int32_t axis, float targetVelocity) {
+    VelocityTracker vt(nullptr);
+    float Vx, Vy;
+
+    MotionEvent* event = createSimpleMotionEvent(positions, numSamples);
+    vt.addMovement(event);
+
+    vt.getVelocity(DEFAULT_POINTER_ID, &Vx, &Vy);
+
+    switch (axis) {
+    case AMOTION_EVENT_AXIS_X:
+        checkVelocity(Vx, targetVelocity);
+        break;
+    case AMOTION_EVENT_AXIS_Y:
+        checkVelocity(Vy, targetVelocity);
+        break;
+    default:
+        FAIL() << "Axis must be either AMOTION_EVENT_AXIS_X or AMOTION_EVENT_AXIS_Y";
+    }
+    delete event;
+}
+
+/*
+ * ================== VelocityTracker tests generated manually =====================================
+ */
+ // @todo Currently disabled, enable when switching away from lsq2 VelocityTrackerStrategy
+TEST_F(VelocityTrackerTest, DISABLED_ThreePointsPositiveVelocityTest) {
+    // Same coordinate is reported 2 times in a row
+    // It is difficult to determine the correct answer here, but at least the direction
+    // of the reported velocity should be positive.
+    Position values[] = {
+        { 0, 273, NAN },
+        { 12585000, 293, NAN },
+        { 14730000, 293, NAN },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 1600);
+}
+
+TEST_F(VelocityTrackerTest, ThreePointsZeroVelocityTest) {
+    // Same coordinate is reported 3 times in a row
+    Position values[] = {
+        { 0, 293, NAN },
+        { 6132000, 293, NAN },
+        { 11283000, 293, NAN },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 0);
+}
+
+TEST_F(VelocityTrackerTest, ThreePointsLinearVelocityTest) {
+    // Fixed velocity at 5 points per 10 milliseconds
+    Position values[] = {
+        { 0, 0, NAN },
+        { 10000000, 5, NAN },
+        { 20000000, 10, NAN },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 500);
+}
+
+
+/**
+ * ================== VelocityTracker tests generated by recording real events =====================
+ *
+ * To add a test, record the input coordinates and event times to all calls
+ * to void VelocityTracker::addMovement(const MotionEvent* event).
+ * Also record all calls to VelocityTracker::clear().
+ * Finally, record the output of VelocityTracker::getVelocity(...)
+ * This will give you the necessary data to create a new test.
+ */
+
+// --------------- Recorded by hand on swordfish ---------------------------------------------------
+// @todo Currently disabled, enable when switching away from lsq2 VelocityTrackerStrategy
+TEST_F(VelocityTrackerTest, DISABLED_SwordfishFlingDown) {
+    // Recording of a fling on Swordfish that could cause a fling in the wrong direction
+    Position values[] = {
+        { 0, 271, 96 },
+        { 16071042, 269.786346, 106.922775 },
+        { 35648403, 267.983063, 156.660034 },
+        { 52313925, 262.638397, 220.339081 },
+        { 68976522, 266.138824, 331.581116 },
+        { 85639375, 274.79245, 428.113159 },
+        { 96948871, 274.79245, 428.113159 },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 623.577637);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 8523.348633);
+}
+
+// --------------- Recorded by hand on sailfish, generated by a script -----------------------------
+// For some of these tests, the X-direction velocity checking has been removed, because the lsq2
+// and the impulse VelocityTrackerStrategies did not agree within 20%.
+// Since the flings were recorded in the Y-direction, the intentional user action should only
+// be relevant for the Y axis.
+// There have been also cases where lsq2 and impulse disagreed more than 20% in the Y-direction.
+// Those recordings have been discarded because we didn't feel one strategy's interpretation was
+// more correct than another's but didn't want to increase the tolerance for the entire test suite.
+//
+// There are 18 tests total below: 9 in the positive Y direction and 9 in the opposite.
+// The recordings were loosely binned into 3 categories - slow, faster, and fast, which roughly
+// characterizes the velocity of the finger motion.
+// These can be treated approximately as:
+// slow - less than 1 page gets scrolled
+// faster - more than 1 page gets scrolled, but less than 3
+// fast - entire list is scrolled (fling is done as hard as possible)
+
+TEST_F(VelocityTrackerTest, SailfishFlingUpSlow1) {
+    // Sailfish - fling up - slow - 1
+    Position values[] = {
+        { 235089067457000, 528.00, 983.00 },
+        { 235089084684000, 527.00, 981.00 },
+        { 235089093349000, 527.00, 977.00 },
+        { 235089095677625, 527.00, 975.93 },
+        { 235089101859000, 527.00, 970.00 },
+        { 235089110378000, 528.00, 960.00 },
+        { 235089112497111, 528.25, 957.51 },
+        { 235089118760000, 531.00, 946.00 },
+        { 235089126686000, 535.00, 931.00 },
+        { 235089129316820, 536.33, 926.02 },
+        { 235089135199000, 540.00, 914.00 },
+        { 235089144297000, 546.00, 896.00 },
+        { 235089146136443, 547.21, 892.36 },
+        { 235089152923000, 553.00, 877.00 },
+        { 235089160784000, 559.00, 851.00 },
+        { 235089162955851, 560.66, 843.82 },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 872.794617); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 951.698181); // lsq2
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -3604.819336); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -3044.966064); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingUpSlow2) {
+    // Sailfish - fling up - slow - 2
+    Position values[] = {
+        { 235110560704000, 522.00, 1107.00 },
+        { 235110575764000, 522.00, 1107.00 },
+        { 235110584385000, 522.00, 1107.00 },
+        { 235110588421179, 521.52, 1106.52 },
+        { 235110592830000, 521.00, 1106.00 },
+        { 235110601385000, 520.00, 1104.00 },
+        { 235110605088160, 519.14, 1102.27 },
+        { 235110609952000, 518.00, 1100.00 },
+        { 235110618353000, 517.00, 1093.00 },
+        { 235110621755146, 516.60, 1090.17 },
+        { 235110627010000, 517.00, 1081.00 },
+        { 235110634785000, 518.00, 1063.00 },
+        { 235110638422450, 518.87, 1052.58 },
+        { 235110643161000, 520.00, 1039.00 },
+        { 235110651767000, 524.00, 1011.00 },
+        { 235110655089581, 525.54, 1000.19 },
+        { 235110660368000, 530.00, 980.00 },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -4096.583008); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -3455.094238); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingUpSlow3) {
+    // Sailfish - fling up - slow - 3
+    Position values[] = {
+        { 792536237000, 580.00, 1317.00 },
+        { 792541538987, 580.63, 1311.94 },
+        { 792544613000, 581.00, 1309.00 },
+        { 792552301000, 583.00, 1295.00 },
+        { 792558362309, 585.13, 1282.92 },
+        { 792560828000, 586.00, 1278.00 },
+        { 792569446000, 589.00, 1256.00 },
+        { 792575185095, 591.54, 1241.41 },
+        { 792578491000, 593.00, 1233.00 },
+        { 792587044000, 597.00, 1211.00 },
+        { 792592008172, 600.28, 1195.92 },
+        { 792594616000, 602.00, 1188.00 },
+        { 792603129000, 607.00, 1167.00 },
+        { 792608831290, 609.48, 1155.83 },
+        { 792612321000, 611.00, 1149.00 },
+        { 792620768000, 615.00, 1131.00 },
+        { 792625653873, 617.32, 1121.73 },
+        { 792629200000, 619.00, 1115.00 },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 574.33429); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 617.40564); // lsq2
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -2361.982666); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -2500.055664); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingUpFaster1) {
+    // Sailfish - fling up - faster - 1
+    Position values[] = {
+        { 235160420675000, 610.00, 1042.00 },
+        { 235160428220000, 609.00, 1026.00 },
+        { 235160436544000, 609.00, 1024.00 },
+        { 235160441852394, 609.64, 1020.82 },
+        { 235160444878000, 610.00, 1019.00 },
+        { 235160452673000, 613.00, 1006.00 },
+        { 235160458519743, 617.18, 992.06 },
+        { 235160461061000, 619.00, 986.00 },
+        { 235160469798000, 627.00, 960.00 },
+        { 235160475186713, 632.22, 943.02 },
+        { 235160478051000, 635.00, 934.00 },
+        { 235160486489000, 644.00, 906.00 },
+        { 235160491853697, 649.56, 890.56 },
+        { 235160495177000, 653.00, 881.00 },
+        { 235160504148000, 662.00, 858.00 },
+        { 235160509231495, 666.81, 845.37 },
+        { 235160512603000, 670.00, 837.00 },
+        { 235160520366000, 679.00, 814.00 },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 1274.141724); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 1438.53186); // lsq2
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -3877.35498); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -3695.859619); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingUpFaster2) {
+    // Sailfish - fling up - faster - 2
+    Position values[] = {
+        { 847153808000, 576.00, 1264.00 },
+        { 847171174000, 576.00, 1262.00 },
+        { 847179640000, 576.00, 1257.00 },
+        { 847185187540, 577.41, 1249.22 },
+        { 847187487000, 578.00, 1246.00 },
+        { 847195710000, 581.00, 1227.00 },
+        { 847202027059, 583.93, 1209.40 },
+        { 847204324000, 585.00, 1203.00 },
+        { 847212672000, 590.00, 1176.00 },
+        { 847218861395, 594.36, 1157.11 },
+        { 847221190000, 596.00, 1150.00 },
+        { 847230484000, 602.00, 1124.00 },
+        { 847235701400, 607.56, 1103.83 },
+        { 847237986000, 610.00, 1095.00 },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -4280.07959); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -4241.004395); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingUpFaster3) {
+    // Sailfish - fling up - faster - 3
+    Position values[] = {
+        { 235200532789000, 507.00, 1084.00 },
+        { 235200549221000, 507.00, 1083.00 },
+        { 235200557841000, 507.00, 1081.00 },
+        { 235200558051189, 507.00, 1080.95 },
+        { 235200566314000, 507.00, 1078.00 },
+        { 235200574876586, 508.97, 1070.12 },
+        { 235200575006000, 509.00, 1070.00 },
+        { 235200582900000, 514.00, 1054.00 },
+        { 235200591276000, 525.00, 1023.00 },
+        { 235200591701829, 525.56, 1021.42 },
+        { 235200600064000, 542.00, 976.00 },
+        { 235200608519000, 563.00, 911.00 },
+        { 235200608527086, 563.02, 910.94 },
+        { 235200616933000, 590.00, 844.00 },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -8715.686523); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -7639.026367); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingUpFast1) {
+    // Sailfish - fling up - fast - 1
+    Position values[] = {
+        { 920922149000, 561.00, 1412.00 },
+        { 920930185000, 559.00, 1377.00 },
+        { 920930262463, 558.98, 1376.66 },
+        { 920938547000, 559.00, 1371.00 },
+        { 920947096857, 562.91, 1342.68 },
+        { 920947302000, 563.00, 1342.00 },
+        { 920955502000, 577.00, 1272.00 },
+        { 920963931021, 596.87, 1190.54 },
+        { 920963987000, 597.00, 1190.00 },
+        { 920972530000, 631.00, 1093.00 },
+        { 920980765511, 671.31, 994.68 },
+        { 920980906000, 672.00, 993.00 },
+        { 920989261000, 715.00, 903.00 },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 5670.329102); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 5991.866699); // lsq2
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -13021.101562); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -15093.995117); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingUpFast2) {
+    // Sailfish - fling up - fast - 2
+    Position values[] = {
+        { 235247153233000, 518.00, 1168.00 },
+        { 235247170452000, 517.00, 1167.00 },
+        { 235247178908000, 515.00, 1159.00 },
+        { 235247179556213, 514.85, 1158.39 },
+        { 235247186821000, 515.00, 1125.00 },
+        { 235247195265000, 521.00, 1051.00 },
+        { 235247196389476, 521.80, 1041.15 },
+        { 235247203649000, 538.00, 932.00 },
+        { 235247212253000, 571.00, 794.00 },
+        { 235247213222491, 574.72, 778.45 },
+        { 235247220736000, 620.00, 641.00 },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -20286.958984); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -20494.587891); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingUpFast3) {
+    // Sailfish - fling up - fast - 3
+    Position values[] = {
+        { 235302568736000, 529.00, 1167.00 },
+        { 235302576644000, 523.00, 1140.00 },
+        { 235302579395063, 520.91, 1130.61 },
+        { 235302585140000, 522.00, 1130.00 },
+        { 235302593615000, 527.00, 1065.00 },
+        { 235302596207444, 528.53, 1045.12 },
+        { 235302602102000, 559.00, 872.00 },
+        { 235302610545000, 652.00, 605.00 },
+        { 235302613019881, 679.26, 526.73 },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -39295.941406); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -36461.421875); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingDownSlow1) {
+    // Sailfish - fling down - slow - 1
+    Position values[] = {
+        { 235655749552755, 582.00, 432.49 },
+        { 235655750638000, 582.00, 433.00 },
+        { 235655758865000, 582.00, 440.00 },
+        { 235655766221523, 581.16, 448.43 },
+        { 235655767594000, 581.00, 450.00 },
+        { 235655776044000, 580.00, 462.00 },
+        { 235655782890696, 579.18, 474.35 },
+        { 235655784360000, 579.00, 477.00 },
+        { 235655792795000, 578.00, 496.00 },
+        { 235655799559531, 576.27, 515.04 },
+        { 235655800612000, 576.00, 518.00 },
+        { 235655809535000, 574.00, 542.00 },
+        { 235655816988015, 572.17, 564.86 },
+        { 235655817685000, 572.00, 567.00 },
+        { 235655825981000, 569.00, 595.00 },
+        { 235655833808653, 566.26, 620.60 },
+        { 235655834541000, 566.00, 623.00 },
+        { 235655842893000, 563.00, 649.00 },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -419.749695); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -398.303894); // lsq2
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 3309.016357); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 3969.099854); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingDownSlow2) {
+    // Sailfish - fling down - slow - 2
+    Position values[] = {
+        { 235671152083370, 485.24, 558.28 },
+        { 235671154126000, 485.00, 559.00 },
+        { 235671162497000, 484.00, 566.00 },
+        { 235671168750511, 483.27, 573.29 },
+        { 235671171071000, 483.00, 576.00 },
+        { 235671179390000, 482.00, 588.00 },
+        { 235671185417210, 481.31, 598.98 },
+        { 235671188173000, 481.00, 604.00 },
+        { 235671196371000, 480.00, 624.00 },
+        { 235671202084196, 479.27, 639.98 },
+        { 235671204235000, 479.00, 646.00 },
+        { 235671212554000, 478.00, 673.00 },
+        { 235671219471011, 476.39, 697.12 },
+        { 235671221159000, 476.00, 703.00 },
+        { 235671229592000, 474.00, 734.00 },
+        { 235671236281462, 472.43, 758.38 },
+        { 235671238098000, 472.00, 765.00 },
+        { 235671246532000, 470.00, 799.00 },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -262.80426); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -243.665344); // lsq2
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 4215.682129); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 4587.986816); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingDownSlow3) {
+    // Sailfish - fling down - slow - 3
+    Position values[] = {
+        { 170983201000, 557.00, 533.00 },
+        { 171000668000, 556.00, 534.00 },
+        { 171007359750, 554.73, 535.27 },
+        { 171011197000, 554.00, 536.00 },
+        { 171017660000, 552.00, 540.00 },
+        { 171024201831, 549.97, 544.73 },
+        { 171027333000, 549.00, 547.00 },
+        { 171034603000, 545.00, 557.00 },
+        { 171041043371, 541.98, 567.55 },
+        { 171043147000, 541.00, 571.00 },
+        { 171051052000, 536.00, 586.00 },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -723.413513); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -651.038452); // lsq2
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 2091.502441); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 1934.517456); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingDownFaster1) {
+    // Sailfish - fling down - faster - 1
+    Position values[] = {
+        { 235695280333000, 558.00, 451.00 },
+        { 235695283971237, 558.43, 454.45 },
+        { 235695289038000, 559.00, 462.00 },
+        { 235695297388000, 561.00, 478.00 },
+        { 235695300638465, 561.83, 486.25 },
+        { 235695305265000, 563.00, 498.00 },
+        { 235695313591000, 564.00, 521.00 },
+        { 235695317305492, 564.43, 532.68 },
+        { 235695322181000, 565.00, 548.00 },
+        { 235695330709000, 565.00, 577.00 },
+        { 235695333972227, 565.00, 588.10 },
+        { 235695339250000, 565.00, 609.00 },
+        { 235695347839000, 565.00, 642.00 },
+        { 235695351313257, 565.00, 656.18 },
+        { 235695356412000, 565.00, 677.00 },
+        { 235695364899000, 563.00, 710.00 },
+        { 235695368118682, 562.24, 722.52 },
+        { 235695373403000, 564.00, 744.00 },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 4254.639648); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 4698.415039); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingDownFaster2) {
+    // Sailfish - fling down - faster - 2
+    Position values[] = {
+        { 235709624766000, 535.00, 579.00 },
+        { 235709642256000, 534.00, 580.00 },
+        { 235709643350278, 533.94, 580.06 },
+        { 235709650760000, 532.00, 584.00 },
+        { 235709658615000, 530.00, 593.00 },
+        { 235709660170495, 529.60, 594.78 },
+        { 235709667095000, 527.00, 606.00 },
+        { 235709675616000, 524.00, 628.00 },
+        { 235709676983261, 523.52, 631.53 },
+        { 235709684289000, 521.00, 652.00 },
+        { 235709692763000, 518.00, 682.00 },
+        { 235709693804993, 517.63, 685.69 },
+        { 235709701438000, 515.00, 709.00 },
+        { 235709709830000, 512.00, 739.00 },
+        { 235709710626776, 511.72, 741.85 },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -430.440247); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -447.600311); // lsq2
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 3953.859375); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 4316.155273); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingDownFaster3) {
+    // Sailfish - fling down - faster - 3
+    Position values[] = {
+        { 235727628927000, 540.00, 440.00 },
+        { 235727636810000, 537.00, 454.00 },
+        { 235727646176000, 536.00, 454.00 },
+        { 235727653586628, 535.12, 456.65 },
+        { 235727654557000, 535.00, 457.00 },
+        { 235727663024000, 534.00, 465.00 },
+        { 235727670410103, 533.04, 479.45 },
+        { 235727670691000, 533.00, 480.00 },
+        { 235727679255000, 531.00, 501.00 },
+        { 235727687233704, 529.09, 526.73 },
+        { 235727687628000, 529.00, 528.00 },
+        { 235727696113000, 526.00, 558.00 },
+        { 235727704057546, 523.18, 588.98 },
+        { 235727704576000, 523.00, 591.00 },
+        { 235727713099000, 520.00, 626.00 },
+        { 235727720880776, 516.33, 655.36 },
+        { 235727721580000, 516.00, 658.00 },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 4484.617676); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 4927.92627); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingDownFast1) {
+    // Sailfish - fling down - fast - 1
+    Position values[] = {
+        { 235762352849000, 467.00, 286.00 },
+        { 235762360250000, 443.00, 344.00 },
+        { 235762362787412, 434.77, 363.89 },
+        { 235762368807000, 438.00, 359.00 },
+        { 235762377220000, 425.00, 423.00 },
+        { 235762379608561, 421.31, 441.17 },
+        { 235762385698000, 412.00, 528.00 },
+        { 235762394133000, 406.00, 648.00 },
+        { 235762396429369, 404.37, 680.67 },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 19084.931641); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 16064.685547); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingDownFast2) {
+    // Sailfish - fling down - fast - 2
+    Position values[] = {
+        { 235772487188000, 576.00, 204.00 },
+        { 235772495159000, 553.00, 236.00 },
+        { 235772503568000, 551.00, 240.00 },
+        { 235772508192247, 545.55, 254.17 },
+        { 235772512051000, 541.00, 266.00 },
+        { 235772520794000, 520.00, 337.00 },
+        { 235772525015263, 508.92, 394.43 },
+        { 235772529174000, 498.00, 451.00 },
+        { 235772537635000, 484.00, 589.00 },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 18660.048828); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 16918.439453); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingDownFast3) {
+    // Sailfish - fling down - fast - 3
+    Position values[] = {
+        { 507650295000, 628.00, 233.00 },
+        { 507658234000, 605.00, 269.00 },
+        { 507666784000, 601.00, 274.00 },
+        { 507669660483, 599.65, 275.68 },
+        { 507675427000, 582.00, 308.00 },
+        { 507683740000, 541.00, 404.00 },
+        { 507686506238, 527.36, 435.95 },
+        { 507692220000, 487.00, 581.00 },
+        { 507700707000, 454.00, 792.00 },
+        { 507703352649, 443.71, 857.77 },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -6772.508301); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -6388.48877); // lsq2
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 29765.908203); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 28354.796875); // lsq2
+}
+
+
+} // namespace android
diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp
index ed292e7..49ffc8f 100644
--- a/libs/nativewindow/AHardwareBuffer.cpp
+++ b/libs/nativewindow/AHardwareBuffer.cpp
@@ -29,7 +29,7 @@
 #include <system/graphics.h>
 
 #include <private/android/AHardwareBufferHelpers.h>
-#include <android/hardware/graphics/common/1.0/types.h>
+#include <android/hardware/graphics/common/1.1/types.h>
 
 
 static constexpr int kFdBufferSize = 128 * sizeof(int);  // 128 ints
@@ -60,6 +60,13 @@
         return BAD_VALUE;
     }
 
+    if ((desc->usage & (AHARDWAREBUFFER_USAGE_CPU_READ_MASK | AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK)) &&
+        (desc->usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT)) {
+        ALOGE("AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT requires AHARDWAREBUFFER_USAGE_CPU_READ_NEVER "
+              "and AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER");
+        return BAD_VALUE;
+    }
+
     uint64_t usage =  AHardwareBuffer_convertToGrallocUsageBits(desc->usage);
     sp<GraphicBuffer> gbuffer(new GraphicBuffer(
             desc->width, desc->height, format, desc->layers, usage,
@@ -311,6 +318,18 @@
             "HAL and AHardwareBuffer pixel format don't match");
     static_assert(HAL_PIXEL_FORMAT_BLOB == AHARDWAREBUFFER_FORMAT_BLOB,
             "HAL and AHardwareBuffer pixel format don't match");
+    static_assert(HAL_PIXEL_FORMAT_DEPTH_16 == AHARDWAREBUFFER_FORMAT_D16_UNORM,
+            "HAL and AHardwareBuffer pixel format don't match");
+    static_assert(HAL_PIXEL_FORMAT_DEPTH_24 == AHARDWAREBUFFER_FORMAT_D24_UNORM,
+            "HAL and AHardwareBuffer pixel format don't match");
+    static_assert(HAL_PIXEL_FORMAT_DEPTH_24_STENCIL_8 == AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT,
+            "HAL and AHardwareBuffer pixel format don't match");
+    static_assert(HAL_PIXEL_FORMAT_DEPTH_32F == AHARDWAREBUFFER_FORMAT_D32_FLOAT,
+            "HAL and AHardwareBuffer pixel format don't match");
+    static_assert(HAL_PIXEL_FORMAT_DEPTH_32F_STENCIL_8 == AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT,
+            "HAL and AHardwareBuffer pixel format don't match");
+    static_assert(HAL_PIXEL_FORMAT_STENCIL_8 == AHARDWAREBUFFER_FORMAT_S8_UINT,
+            "HAL and AHardwareBuffer pixel format don't match");
     static_assert(HAL_PIXEL_FORMAT_BGRA_8888 == AHARDWAREBUFFER_FORMAT_B8G8R8A8_UNORM,
             "HAL and AHardwareBuffer pixel format don't match");
     static_assert(HAL_PIXEL_FORMAT_YV12 == AHARDWAREBUFFER_FORMAT_YV12,
@@ -331,14 +350,6 @@
             "HAL and AHardwareBuffer pixel format don't match");
     static_assert(HAL_PIXEL_FORMAT_YCBCR_420_888 == AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420,
             "HAL and AHardwareBuffer pixel format don't match");
-    static_assert(HAL_PIXEL_FORMAT_YCBCR_422_888 == AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_422,
-            "HAL and AHardwareBuffer pixel format don't match");
-    static_assert(HAL_PIXEL_FORMAT_YCBCR_444_888 == AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_444,
-            "HAL and AHardwareBuffer pixel format don't match");
-    static_assert(HAL_PIXEL_FORMAT_FLEX_RGB_888 == AHARDWAREBUFFER_FORMAT_FLEX_R8G8B8,
-            "HAL and AHardwareBuffer pixel format don't match");
-    static_assert(HAL_PIXEL_FORMAT_FLEX_RGBA_8888 == AHARDWAREBUFFER_FORMAT_FLEX_R8G8B8A8,
-            "HAL and AHardwareBuffer pixel format don't match");
     static_assert(HAL_PIXEL_FORMAT_YCBCR_422_SP == AHARDWAREBUFFER_FORMAT_YCbCr_422_SP,
             "HAL and AHardwareBuffer pixel format don't match");
     static_assert(HAL_PIXEL_FORMAT_YCRCB_420_SP == AHARDWAREBUFFER_FORMAT_YCrCb_420_SP,
@@ -354,6 +365,12 @@
         case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT:
         case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM:
         case AHARDWAREBUFFER_FORMAT_BLOB:
+        case AHARDWAREBUFFER_FORMAT_D16_UNORM:
+        case AHARDWAREBUFFER_FORMAT_D24_UNORM:
+        case AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT:
+        case AHARDWAREBUFFER_FORMAT_D32_FLOAT:
+        case AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT:
+        case AHARDWAREBUFFER_FORMAT_S8_UINT:
             // VNDK formats only -- unfortunately we can't differentiate from where we're called
         case AHARDWAREBUFFER_FORMAT_B8G8R8A8_UNORM:
         case AHARDWAREBUFFER_FORMAT_YV12:
@@ -365,10 +382,6 @@
         case AHARDWAREBUFFER_FORMAT_RAW_OPAQUE:
         case AHARDWAREBUFFER_FORMAT_IMPLEMENTATION_DEFINED:
         case AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420:
-        case AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_422:
-        case AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_444:
-        case AHARDWAREBUFFER_FORMAT_FLEX_R8G8B8:
-        case AHARDWAREBUFFER_FORMAT_FLEX_R8G8B8A8:
         case AHARDWAREBUFFER_FORMAT_YCbCr_422_SP:
         case AHARDWAREBUFFER_FORMAT_YCrCb_420_SP:
         case AHARDWAREBUFFER_FORMAT_YCbCr_422_I:
@@ -388,7 +401,7 @@
 }
 
 uint64_t AHardwareBuffer_convertToGrallocUsageBits(uint64_t usage) {
-    using android::hardware::graphics::common::V1_0::BufferUsage;
+    using android::hardware::graphics::common::V1_1::BufferUsage;
     static_assert(AHARDWAREBUFFER_USAGE_CPU_READ_NEVER == (uint64_t)BufferUsage::CPU_READ_NEVER,
             "gralloc and AHardwareBuffer flags don't match");
     static_assert(AHARDWAREBUFFER_USAGE_CPU_READ_RARELY == (uint64_t)BufferUsage::CPU_READ_RARELY,
@@ -413,6 +426,10 @@
             "gralloc and AHardwareBuffer flags don't match");
     static_assert(AHARDWAREBUFFER_USAGE_SENSOR_DIRECT_DATA == (uint64_t)BufferUsage::SENSOR_DIRECT_DATA,
             "gralloc and AHardwareBuffer flags don't match");
+    static_assert(AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP == (uint64_t)BufferUsage::GPU_CUBE_MAP,
+            "gralloc and AHardwareBuffer flags don't match");
+    static_assert(AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE == (uint64_t)BufferUsage::GPU_MIPMAP_COMPLETE,
+            "gralloc and AHardwareBuffer flags don't match");
     return usage;
 }
 
diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp
index c6994c3..765dcd9 100644
--- a/libs/nativewindow/ANativeWindow.cpp
+++ b/libs/nativewindow/ANativeWindow.cpp
@@ -33,6 +33,27 @@
     return res < 0 ? res : value;
 }
 
+static bool isDataSpaceValid(ANativeWindow* window, int32_t dataSpace) {
+    bool supported = false;
+    switch (dataSpace) {
+        case HAL_DATASPACE_UNKNOWN:
+        case HAL_DATASPACE_V0_SRGB:
+            return true;
+        // These data space need wide gamut support.
+        case HAL_DATASPACE_V0_SCRGB_LINEAR:
+        case HAL_DATASPACE_V0_SCRGB:
+        case HAL_DATASPACE_DISPLAY_P3:
+            native_window_get_wide_color_support(window, &supported);
+            return supported;
+        // These data space need HDR support.
+        case HAL_DATASPACE_BT2020_PQ:
+            native_window_get_hdr_support(window, &supported);
+            return supported;
+        default:
+            return false;
+    }
+}
+
 /**************************************************************************************************
  * NDK
  **************************************************************************************************/
@@ -92,7 +113,10 @@
     constexpr int32_t kAllTransformBits =
             ANATIVEWINDOW_TRANSFORM_MIRROR_HORIZONTAL |
             ANATIVEWINDOW_TRANSFORM_MIRROR_VERTICAL |
-            ANATIVEWINDOW_TRANSFORM_ROTATE_90;
+            ANATIVEWINDOW_TRANSFORM_ROTATE_90 |
+            // We don't expose INVERSE_DISPLAY as an NDK constant, but someone could have read it
+            // from a buffer already set by Camera framework, so we allow it to be forwarded.
+            NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY;
     if (!window || !query(window, NATIVE_WINDOW_IS_VALID))
         return -EINVAL;
     if ((transform & ~kAllTransformBits) != 0)
@@ -101,6 +125,28 @@
     return native_window_set_buffers_transform(window, transform);
 }
 
+int32_t ANativeWindow_setBuffersDataSpace(ANativeWindow* window, int32_t dataSpace) {
+    static_assert(ADATASPACE_UNKNOWN == HAL_DATASPACE_UNKNOWN);
+    static_assert(ADATASPACE_SCRGB_LINEAR == HAL_DATASPACE_V0_SCRGB_LINEAR);
+    static_assert(ADATASPACE_SRGB == HAL_DATASPACE_V0_SRGB);
+    static_assert(ADATASPACE_SCRGB == HAL_DATASPACE_V0_SCRGB);
+    static_assert(ADATASPACE_DISPLAY_P3 == HAL_DATASPACE_DISPLAY_P3);
+    static_assert(ADATASPACE_BT2020_PQ == HAL_DATASPACE_BT2020_PQ);
+
+    if (!window || !query(window, NATIVE_WINDOW_IS_VALID) ||
+            !isDataSpaceValid(window, dataSpace)) {
+        return -EINVAL;
+    }
+    return native_window_set_buffers_data_space(window,
+                                                static_cast<android_dataspace_t>(dataSpace));
+}
+
+int32_t ANativeWindow_getBuffersDataSpace(ANativeWindow* window) {
+    if (!window || !query(window, NATIVE_WINDOW_IS_VALID))
+        return -EINVAL;
+    return query(window, NATIVE_WINDOW_DATASPACE);
+}
+
 /**************************************************************************************************
  * vndk-stable
  **************************************************************************************************/
@@ -209,10 +255,6 @@
     return native_window_set_buffers_timestamp(window, timestamp);
 }
 
-int ANativeWindow_setBufferDataSpace(ANativeWindow* window, android_dataspace_t dataSpace) {
-    return native_window_set_buffers_data_space(window, dataSpace);
-}
-
 int ANativeWindow_setSharedBufferMode(ANativeWindow* window, bool sharedBufferMode) {
     return native_window_set_shared_buffer_mode(window, sharedBufferMode);
 }
diff --git a/libs/nativewindow/Android.bp b/libs/nativewindow/Android.bp
index 29555fd..5fbb3b2 100644
--- a/libs/nativewindow/Android.bp
+++ b/libs/nativewindow/Android.bp
@@ -60,7 +60,7 @@
         "liblog",
         "libutils",
         "libui",
-        "android.hardware.graphics.common@1.0",
+        "android.hardware.graphics.common@1.1",
     ],
 
     static_libs: [
diff --git a/libs/nativewindow/include/android/data_space.h b/libs/nativewindow/include/android/data_space.h
new file mode 100644
index 0000000..3ac1c58
--- /dev/null
+++ b/libs/nativewindow/include/android/data_space.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2018 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.
+ */
+
+/**
+ * @file data_space.h
+ */
+
+#ifndef ANDROID_DATA_SPACE_H
+#define ANDROID_DATA_SPACE_H
+
+#include <inttypes.h>
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/**
+ * ADataSpace.
+ */
+enum ADataSpace {
+    /**
+     * Default-assumption data space, when not explicitly specified.
+     *
+     * It is safest to assume the buffer is an image with sRGB primaries and
+     * encoding ranges, but the consumer and/or the producer of the data may
+     * simply be using defaults. No automatic gamma transform should be
+     * expected, except for a possible display gamma transform when drawn to a
+     * screen.
+     */
+    ADATASPACE_UNKNOWN = 0,
+
+    /**
+     * scRGB linear encoding:
+     *
+     * The red, green, and blue components are stored in extended sRGB space,
+     * but are linear, not gamma-encoded.
+     * The RGB primaries and the white point are the same as BT.709.
+     *
+     * The values are floating point.
+     * A pixel value of 1.0, 1.0, 1.0 corresponds to sRGB white (D65) at 80 nits.
+     * Values beyond the range [0.0 - 1.0] would correspond to other colors
+     * spaces and/or HDR content.
+     */
+    ADATASPACE_SCRGB_LINEAR = 406913024, // STANDARD_BT709 | TRANSFER_LINEAR | RANGE_EXTENDED
+
+    /**
+     * sRGB gamma encoding:
+     *
+     * The red, green and blue components are stored in sRGB space, and
+     * converted to linear space when read, using the SRGB transfer function
+     * for each of the R, G and B components. When written, the inverse
+     * transformation is performed.
+     *
+     * The alpha component, if present, is always stored in linear space and
+     * is left unmodified when read or written.
+     *
+     * Use full range and BT.709 standard.
+     */
+    ADATASPACE_SRGB = 142671872, // STANDARD_BT709 | TRANSFER_SRGB | RANGE_FULL
+
+    /**
+     * scRGB:
+     *
+     * The red, green, and blue components are stored in extended sRGB space,
+     * but are linear, not gamma-encoded.
+     * The RGB primaries and the white point are the same as BT.709.
+     *
+     * The values are floating point.
+     * A pixel value of 1.0, 1.0, 1.0 corresponds to sRGB white (D65) at 80 nits.
+     * Values beyond the range [0.0 - 1.0] would correspond to other colors
+     * spaces and/or HDR content.
+     */
+    ADATASPACE_SCRGB = 411107328, // STANDARD_BT709 | TRANSFER_SRGB | RANGE_EXTENDED
+
+    /**
+     * Display P3
+     *
+     * Use same primaries and white-point as DCI-P3
+     * but sRGB transfer function.
+     */
+    ADATASPACE_DISPLAY_P3 = 143261696, // STANDARD_DCI_P3 | TRANSFER_SRGB | RANGE_FULL
+
+    /**
+     * ITU-R Recommendation 2020 (BT.2020)
+     *
+     * Ultra High-definition television
+     *
+     * Use full range, SMPTE 2084 (PQ) transfer and BT2020 standard
+     */
+    ADATASPACE_BT2020_PQ = 163971072, // STANDARD_BT2020 | TRANSFER_ST2084 | RANGE_FULL
+};
+
+__END_DECLS
+
+#endif // ANDROID_DATA_SPACE_H
diff --git a/libs/nativewindow/include/android/hardware_buffer.h b/libs/nativewindow/include/android/hardware_buffer.h
index ef4875a..32b9266 100644
--- a/libs/nativewindow/include/android/hardware_buffer.h
+++ b/libs/nativewindow/include/android/hardware_buffer.h
@@ -46,9 +46,11 @@
     AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM           = 1,
 
     /**
+     * 32 bits per pixel, 8 bits per channel format where alpha values are
+     * ignored (always opaque).
      * Corresponding formats:
      *   Vulkan: VK_FORMAT_R8G8B8A8_UNORM
-     *   OpenGL ES: GL_RGBA8
+     *   OpenGL ES: GL_RGB8
      */
     AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM           = 2,
 
@@ -85,39 +87,94 @@
      * the buffer size in bytes.
      */
     AHARDWAREBUFFER_FORMAT_BLOB                     = 0x21,
+
+    /**
+     * Corresponding formats:
+     *   Vulkan: VK_FORMAT_D16_UNORM
+     *   OpenGL ES: GL_DEPTH_COMPONENT16
+     */
+    AHARDWAREBUFFER_FORMAT_D16_UNORM                = 0x30,
+
+    /**
+     * Corresponding formats:
+     *   Vulkan: VK_FORMAT_X8_D24_UNORM_PACK32
+     *   OpenGL ES: GL_DEPTH_COMPONENT24
+     */
+    AHARDWAREBUFFER_FORMAT_D24_UNORM                = 0x31,
+
+    /**
+     * Corresponding formats:
+     *   Vulkan: VK_FORMAT_D24_UNORM_S8_UINT
+     *   OpenGL ES: GL_DEPTH24_STENCIL8
+     */
+    AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT        = 0x32,
+
+    /**
+     * Corresponding formats:
+     *   Vulkan: VK_FORMAT_D32_SFLOAT
+     *   OpenGL ES: GL_DEPTH_COMPONENT32F
+     */
+    AHARDWAREBUFFER_FORMAT_D32_FLOAT                = 0x33,
+
+    /**
+     * Corresponding formats:
+     *   Vulkan: VK_FORMAT_D32_SFLOAT_S8_UINT
+     *   OpenGL ES: GL_DEPTH32F_STENCIL8
+     */
+    AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT        = 0x34,
+
+    /**
+     * Corresponding formats:
+     *   Vulkan: VK_FORMAT_S8_UINT
+     *   OpenGL ES: GL_STENCIL_INDEX8
+     */
+    AHARDWAREBUFFER_FORMAT_S8_UINT                  = 0x35,
 };
 
+/**
+ * Buffer usage flags, specifying how the buffer will be accessed.
+ */
 enum {
-    /* The buffer will never be read by the CPU */
+    /// The buffer will never be read by the CPU.
     AHARDWAREBUFFER_USAGE_CPU_READ_NEVER        = 0UL,
-    /* The buffer will sometimes be read by the CPU */
+    /// The buffer will sometimes be read by the CPU.
     AHARDWAREBUFFER_USAGE_CPU_READ_RARELY       = 2UL,
-    /* The buffer will often be read by the CPU */
+    /// The buffer will often be read by the CPU.
     AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN        = 3UL,
-    /* CPU read value mask */
+    /// CPU read value mask.
     AHARDWAREBUFFER_USAGE_CPU_READ_MASK         = 0xFUL,
 
-    /* The buffer will never be written by the CPU */
+    /// The buffer will never be written by the CPU.
     AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER       = 0UL << 4,
-    /* The buffer will sometimes be written to by the CPU */
+    /// The buffer will sometimes be written to by the CPU.
     AHARDWAREBUFFER_USAGE_CPU_WRITE_RARELY      = 2UL << 4,
-    /* The buffer will often be written to by the CPU */
+    /// The buffer will often be written to by the CPU.
     AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN       = 3UL << 4,
-    /* CPU write value mask */
+    /// CPU write value mask.
     AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK        = 0xFUL << 4,
 
-    /* The buffer will be read from by the GPU */
+    /// The buffer will be read from by the GPU as a texture.
     AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE      = 1UL << 8,
-    /* The buffer will be written to by the GPU */
+    /**
+     * The buffer will be written to by the GPU as a framebuffer attachment.
+     * Note that the name of this flag is somewhat misleading: it does not imply
+     * that the buffer contains a color format. A buffer with depth or stencil
+     * format that will be used as a framebuffer attachment should also have
+     * this flag.
+     */
     AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT       = 1UL << 9,
-    /* The buffer must not be used outside of a protected hardware path */
+    /// The buffer must not be used outside of a protected hardware path.
     AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT      = 1UL << 14,
-    /* The buffer will be read by a hardware video encoder */
+    /// The buffer will be read by a hardware video encoder.
     AHARDWAREBUFFER_USAGE_VIDEO_ENCODE           = 1UL << 16,
-    /** The buffer will be used for sensor direct data */
+    /// The buffer will be used for direct writes from sensors.
     AHARDWAREBUFFER_USAGE_SENSOR_DIRECT_DATA     = 1UL << 23,
-    /* The buffer will be used as a shader storage or uniform buffer object*/
+    /// The buffer will be used as a shader storage or uniform buffer object.
     AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER        = 1UL << 24,
+    /// The buffer will be used as a cube map texture.
+    AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP               = 1UL << 25,
+    /// The buffer contains a complete mipmap hierarchy.
+    AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE        = 1UL << 26,
 
     AHARDWAREBUFFER_USAGE_VENDOR_0  = 1ULL << 28,
     AHARDWAREBUFFER_USAGE_VENDOR_1  = 1ULL << 29,
@@ -141,15 +198,19 @@
     AHARDWAREBUFFER_USAGE_VENDOR_19 = 1ULL << 63,
 };
 
+/**
+ * Buffer description. Used for allocating new buffers and querying parameters
+ * of existing ones.
+ */
 typedef struct AHardwareBuffer_Desc {
-    uint32_t    width;      // width in pixels
-    uint32_t    height;     // height in pixels
-    uint32_t    layers;     // number of images
-    uint32_t    format;     // One of AHARDWAREBUFFER_FORMAT_*
-    uint64_t    usage;      // Combination of AHARDWAREBUFFER_USAGE_*
-    uint32_t    stride;     // Stride in pixels, ignored for AHardwareBuffer_allocate()
-    uint32_t    rfu0;       // Initialize to zero, reserved for future use
-    uint64_t    rfu1;       // Initialize to zero, reserved for future use
+    uint32_t    width;      ///< Width in pixels.
+    uint32_t    height;     ///< Height in pixels.
+    uint32_t    layers;     ///< Number of images in an image array.
+    uint32_t    format;     ///< One of AHARDWAREBUFFER_FORMAT_*
+    uint64_t    usage;      ///< Combination of AHARDWAREBUFFER_USAGE_*
+    uint32_t    stride;     ///< Row stride in pixels, ignored for AHardwareBuffer_allocate()
+    uint32_t    rfu0;       ///< Initialize to zero, reserved for future use.
+    uint64_t    rfu1;       ///< Initialize to zero, reserved for future use.
 } AHardwareBuffer_Desc;
 
 typedef struct AHardwareBuffer AHardwareBuffer;
@@ -158,8 +219,8 @@
  * Allocates a buffer that backs an AHardwareBuffer using the passed
  * AHardwareBuffer_Desc.
  *
- * Returns NO_ERROR on success, or an error number of the allocation fails for
- * any reason.
+ * \return 0 on success, or an error number of the allocation fails for
+ * any reason. The returned buffer has a reference count of 1.
  */
 int AHardwareBuffer_allocate(const AHardwareBuffer_Desc* desc,
         AHardwareBuffer** outBuffer);
@@ -182,7 +243,7 @@
 void AHardwareBuffer_describe(const AHardwareBuffer* buffer,
         AHardwareBuffer_Desc* outDesc);
 
-/*
+/**
  * Lock the AHardwareBuffer for reading or writing, depending on the usage flags
  * passed.  This call may block if the hardware needs to finish rendering or if
  * CPU caches need to be synchronized, or possibly for other implementation-
@@ -190,16 +251,16 @@
  * descriptor that will be signaled when the buffer is locked, otherwise the
  * caller will block until the buffer is available.
  *
- * If rect is not NULL, the caller promises to modify only data in the area
+ * If \a rect is not NULL, the caller promises to modify only data in the area
  * specified by rect. If rect is NULL, the caller may modify the contents of the
  * entire buffer.
  *
  * The content of the buffer outside of the specified rect is NOT modified
  * by this call.
  *
- * The buffer usage may only specify AHARDWAREBUFFER_USAGE_CPU_*. If set, then
- * outVirtualAddress is filled with the address of the buffer in virtual memory,
- * otherwise this function will fail.
+ * The \a usage parameter may only specify AHARDWAREBUFFER_USAGE_CPU_*. If set,
+ * then outVirtualAddress is filled with the address of the buffer in virtual
+ * memory.
  *
  * THREADING CONSIDERATIONS:
  *
@@ -211,38 +272,38 @@
  * may return an error or leave the buffer's content into an indeterminate
  * state.
  *
- * Returns NO_ERROR on success, BAD_VALUE if the buffer is NULL or if the usage
+ * \return 0 on success, -EINVAL if \a buffer is NULL or if the usage
  * flags are not a combination of AHARDWAREBUFFER_USAGE_CPU_*, or an error
  * number of the lock fails for any reason.
  */
 int AHardwareBuffer_lock(AHardwareBuffer* buffer, uint64_t usage,
         int32_t fence, const ARect* rect, void** outVirtualAddress);
 
-/*
+/**
  * Unlock the AHardwareBuffer; must be called after all changes to the buffer
  * are completed by the caller. If fence is not NULL then it will be set to a
  * file descriptor that is signaled when all pending work on the buffer is
  * completed. The caller is responsible for closing the fence when it is no
  * longer needed.
  *
- * Returns NO_ERROR on success, BAD_VALUE if the buffer is NULL, or an error
- * number of the lock fails for any reason.
+ * \return 0 on success, -EINVAL if \a buffer is NULL, or an error
+ * number if the unlock fails for any reason.
  */
 int AHardwareBuffer_unlock(AHardwareBuffer* buffer, int32_t* fence);
 
-/*
+/**
  * Send the AHardwareBuffer to an AF_UNIX socket.
  *
- * Returns NO_ERROR on success, BAD_VALUE if the buffer is NULL, or an error
- * number of the lock fails for any reason.
+ * \return 0 on success, -EINVAL if \a buffer is NULL, or an error
+ * number if the operation fails for any reason.
  */
 int AHardwareBuffer_sendHandleToUnixSocket(const AHardwareBuffer* buffer, int socketFd);
 
-/*
+/**
  * Receive the AHardwareBuffer from an AF_UNIX socket.
  *
- * Returns NO_ERROR on success, BAD_VALUE if the buffer is NULL, or an error
- * number of the lock fails for any reason.
+ * \return 0 on success, -EINVAL if \a outBuffer is NULL, or an error
+ * number if the operation fails for any reason.
  */
 int AHardwareBuffer_recvHandleFromUnixSocket(int socketFd, AHardwareBuffer** outBuffer);
 
diff --git a/libs/nativewindow/include/android/native_window.h b/libs/nativewindow/include/android/native_window.h
index 5290dd5..d5e5e9d 100644
--- a/libs/nativewindow/include/android/native_window.h
+++ b/libs/nativewindow/include/android/native_window.h
@@ -29,6 +29,7 @@
 
 #include <sys/cdefs.h>
 
+#include <android/data_space.h>
 #include <android/hardware_buffer.h>
 #include <android/rect.h>
 
@@ -84,23 +85,23 @@
  * A pointer can be obtained using {@link ANativeWindow_lock()}.
  */
 typedef struct ANativeWindow_Buffer {
-    // The number of pixels that are show horizontally.
+    /// The number of pixels that are shown horizontally.
     int32_t width;
 
-    // The number of pixels that are shown vertically.
+    /// The number of pixels that are shown vertically.
     int32_t height;
 
-    // The number of *pixels* that a line in the buffer takes in
-    // memory. This may be >= width.
+    /// The number of *pixels* that a line in the buffer takes in
+    /// memory. This may be >= width.
     int32_t stride;
 
-    // The format of the buffer. One of AHARDWAREBUFFER_FORMAT_*
+    /// The format of the buffer. One of AHARDWAREBUFFER_FORMAT_*
     int32_t format;
 
-    // The actual bits.
+    /// The actual bits.
     void* bits;
 
-    // Do not touch.
+    /// Do not touch.
     uint32_t reserved[6];
 } ANativeWindow_Buffer;
 
@@ -189,6 +190,33 @@
 
 #endif // __ANDROID_API__ >= __ANDROID_API_O__
 
+#if __ANDROID_API__ >= __ANDROID_API_P__
+
+/**
+ * All buffers queued after this call will be associated with the dataSpace
+ * parameter specified.
+ *
+ * dataSpace specifies additional information about the buffer.
+ * For example, it can be used to convey the color space of the image data in
+ * the buffer, or it can be used to indicate that the buffers contain depth
+ * measurement data instead of color images. The default dataSpace is 0,
+ * ADATASPACE_UNKNOWN, unless it has been overridden by the producer.
+ *
+ * \param dataSpace data space of all buffers queued after this call.
+ * \return 0 for success, -EINVAL if window is invalid or the dataspace is not
+ * supported.
+ */
+int32_t ANativeWindow_setBuffersDataSpace(ANativeWindow* window, int32_t dataSpace);
+
+/**
+ * Get the dataspace of the buffers in window.
+ * \return the dataspace of buffers in window, ADATASPACE_UNKNOWN is returned if
+ * dataspace is unknown, or -EINVAL if window is invalid.
+ */
+int32_t ANativeWindow_getBuffersDataSpace(ANativeWindow* window);
+
+#endif // __ANDROID_API__ >= __ANDROID_API_P__
+
 #ifdef __cplusplus
 };
 #endif
diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h
index 6490804..197f73f 100644
--- a/libs/nativewindow/include/system/window.h
+++ b/libs/nativewindow/include/system/window.h
@@ -179,6 +179,16 @@
      * with GRALLOC_USAGE_PROTECTED usage bits on.
      */
     NATIVE_WINDOW_CONSUMER_IS_PROTECTED = 19,
+
+    /*
+     * Returns data space for the buffers.
+     */
+    NATIVE_WINDOW_DATASPACE = 20,
+
+    /*
+     * Returns maxBufferCount set by BufferQueueConsumer
+     */
+    NATIVE_WINDOW_MAX_BUFFER_COUNT = 21,
 };
 
 /* Valid operations for the (*perform)() hook.
@@ -225,6 +235,8 @@
     NATIVE_WINDOW_GET_HDR_SUPPORT               = 29,
     NATIVE_WINDOW_SET_USAGE64                   = 30,
     NATIVE_WINDOW_GET_CONSUMER_USAGE64          = 31,
+    NATIVE_WINDOW_SET_BUFFERS_SMPTE2086_METADATA = 32,
+    NATIVE_WINDOW_SET_BUFFERS_CTA861_3_METADATA = 33,
 // clang-format on
 };
 
@@ -700,6 +712,42 @@
 }
 
 /*
+ * native_window_set_buffers_smpte2086_metadata(..., metadata)
+ * All buffers queued after this call will be associated with the SMPTE
+ * ST.2086 metadata specified.
+ *
+ * metadata specifies additional information about the contents of the buffer
+ * that may affect how it's displayed.  When it is nullptr, it means no such
+ * information is available.  No SMPTE ST.2086 metadata is associated with the
+ * buffers by default.
+ */
+static inline int native_window_set_buffers_smpte2086_metadata(
+        struct ANativeWindow* window,
+        const struct android_smpte2086_metadata* metadata)
+{
+    return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_SMPTE2086_METADATA,
+            metadata);
+}
+
+/*
+ * native_window_set_buffers_cta861_3_metadata(..., metadata)
+ * All buffers queued after this call will be associated with the CTA-861.3
+ * metadata specified.
+ *
+ * metadata specifies additional information about the contents of the buffer
+ * that may affect how it's displayed.  When it is nullptr, it means no such
+ * information is available.  No CTA-861.3 metadata is associated with the
+ * buffers by default.
+ */
+static inline int native_window_set_buffers_cta861_3_metadata(
+        struct ANativeWindow* window,
+        const struct android_cta861_3_metadata* metadata)
+{
+    return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_CTA861_3_METADATA,
+            metadata);
+}
+
+/*
  * native_window_set_buffers_transform(..., int transform)
  * All buffers queued after this call will be displayed transformed according
  * to the transform parameter specified.
diff --git a/libs/nativewindow/include/vndk/hardware_buffer.h b/libs/nativewindow/include/vndk/hardware_buffer.h
index 802edcc..7a4b31f 100644
--- a/libs/nativewindow/include/vndk/hardware_buffer.h
+++ b/libs/nativewindow/include/vndk/hardware_buffer.h
@@ -53,14 +53,6 @@
     AHARDWAREBUFFER_FORMAT_IMPLEMENTATION_DEFINED   = 0x22,
     /* same as HAL_PIXEL_FORMAT_YCBCR_420_888 */
     AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420             = 0x23,
-    /* same as HAL_PIXEL_FORMAT_YCBCR_422_888 */
-    AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_422             = 0x27,
-    /* same as HAL_PIXEL_FORMAT_YCBCR_444_888 */
-    AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_444             = 0x28,
-    /* same as HAL_PIXEL_FORMAT_FLEX_RGB_888 */
-    AHARDWAREBUFFER_FORMAT_FLEX_R8G8B8              = 0x29,
-    /* same as HAL_PIXEL_FORMAT_FLEX_RGBA_8888 */
-    AHARDWAREBUFFER_FORMAT_FLEX_R8G8B8A8            = 0x2A,
     /* same as HAL_PIXEL_FORMAT_YCBCR_422_SP */
     AHARDWAREBUFFER_FORMAT_YCbCr_422_SP             = 0x10,
     /* same as HAL_PIXEL_FORMAT_YCRCB_420_SP */
diff --git a/libs/nativewindow/include/vndk/window.h b/libs/nativewindow/include/vndk/window.h
index a7b340a..995ba44 100644
--- a/libs/nativewindow/include/vndk/window.h
+++ b/libs/nativewindow/include/vndk/window.h
@@ -306,20 +306,6 @@
 
 
 /*
- * All buffers queued after this call will be associated with the dataSpace
- * parameter specified.
- *
- * dataSpace specifies additional information about the buffer that's dependent
- * on the buffer format and the endpoints. For example, it can be used to convey
- * the color space of the image data in the buffer, or it can be used to
- * indicate that the buffers contain depth measurement data instead of color
- * images.  The default dataSpace is 0, HAL_DATASPACE_UNKNOWN, unless it has been
- * overridden by the consumer.
- */
-int ANativeWindow_setBufferDataSpace(ANativeWindow* window, android_dataspace_t dataSpace);
-
-
-/*
  * Enable/disable shared buffer mode
  */
 int ANativeWindow_setSharedBufferMode(ANativeWindow* window, bool sharedBufferMode);
diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt
index 105d01b..d2ba971 100644
--- a/libs/nativewindow/libnativewindow.map.txt
+++ b/libs/nativewindow/libnativewindow.map.txt
@@ -15,6 +15,7 @@
     ANativeWindow_acquire;
     ANativeWindow_cancelBuffer; # vndk
     ANativeWindow_dequeueBuffer; # vndk
+    ANativeWindow_getBuffersDataSpace; # introduced=28
     ANativeWindow_getFormat;
     ANativeWindow_getHeight;
     ANativeWindow_getWidth;
@@ -25,7 +26,7 @@
     ANativeWindow_release;
     ANativeWindow_setAutoRefresh; # vndk
     ANativeWindow_setBufferCount; # vndk
-    ANativeWindow_setBufferDataSpace; # vndk
+    ANativeWindow_setBuffersDataSpace; # introduced=28
     ANativeWindow_setBuffersDimensions; # vndk
     ANativeWindow_setBuffersFormat; # vndk
     ANativeWindow_setBuffersGeometry;
diff --git a/libs/sensor/ISensorServer.cpp b/libs/sensor/ISensorServer.cpp
index efbbf7d..5200545 100644
--- a/libs/sensor/ISensorServer.cpp
+++ b/libs/sensor/ISensorServer.cpp
@@ -27,6 +27,7 @@
 
 #include <binder/Parcel.h>
 #include <binder/IInterface.h>
+#include <binder/IResultReceiver.h>
 
 #include <sensor/Sensor.h>
 #include <sensor/ISensorEventConnection.h>
@@ -227,6 +228,30 @@
             reply->writeInt32(ret);
             return NO_ERROR;
         }
+        case SHELL_COMMAND_TRANSACTION: {
+            int in = data.readFileDescriptor();
+            int out = data.readFileDescriptor();
+            int err = data.readFileDescriptor();
+            int argc = data.readInt32();
+            Vector<String16> args;
+            for (int i = 0; i < argc && data.dataAvail() > 0; i++) {
+               args.add(data.readString16());
+            }
+            sp<IBinder> unusedCallback;
+            sp<IResultReceiver> resultReceiver;
+            status_t status;
+            if ((status = data.readNullableStrongBinder(&unusedCallback)) != NO_ERROR) {
+                return status;
+            }
+            if ((status = data.readNullableStrongBinder(&resultReceiver)) != NO_ERROR) {
+                return status;
+            }
+            status = shellCommand(in, out, err, args);
+            if (resultReceiver != nullptr) {
+                resultReceiver->send(status);
+            }
+            return NO_ERROR;
+        }
     }
     return BBinder::onTransact(code, data, reply, flags);
 }
diff --git a/libs/sensor/OWNERS b/libs/sensor/OWNERS
new file mode 100644
index 0000000..d4393d6
--- /dev/null
+++ b/libs/sensor/OWNERS
@@ -0,0 +1,2 @@
+arthuri@google.com
+bduddie@google.com
diff --git a/libs/sensor/SensorManager.cpp b/libs/sensor/SensorManager.cpp
index 6fe72a1..b9ae524 100644
--- a/libs/sensor/SensorManager.cpp
+++ b/libs/sensor/SensorManager.cpp
@@ -27,6 +27,7 @@
 #include <utils/Singleton.h>
 
 #include <binder/IBinder.h>
+#include <binder/IPermissionController.h>
 #include <binder/IServiceManager.h>
 
 #include <sensor/ISensorServer.h>
diff --git a/libs/sensor/include/sensor/ISensorServer.h b/libs/sensor/include/sensor/ISensorServer.h
index edf3e0f..402678f 100644
--- a/libs/sensor/include/sensor/ISensorServer.h
+++ b/libs/sensor/include/sensor/ISensorServer.h
@@ -60,6 +60,9 @@
 class BnSensorServer : public BnInterface<ISensorServer>
 {
 public:
+    virtual status_t shellCommand(int in, int out, int err,
+                                  Vector<String16>& args) = 0;
+
     virtual status_t    onTransact( uint32_t code,
                                     const Parcel& data,
                                     Parcel* reply,
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index 438fd2a..d25ad1a 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -48,7 +48,7 @@
     ],
 
     sanitize: {
-        //misc_undefined: ["integer"],
+        integer_overflow: true,
     },
 
     srcs: [
@@ -74,7 +74,9 @@
 
     shared_libs: [
         "android.hardware.graphics.allocator@2.0",
+        "android.hardware.graphics.common@1.1",
         "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@2.1",
         "android.hardware.configstore@1.0",
         "android.hardware.configstore-utils",
         "libbase",
@@ -89,6 +91,10 @@
         "liblog",
     ],
 
+    export_shared_lib_headers: [
+        "android.hardware.graphics.common@1.1",
+    ],
+
     static_libs: [
         "libarect",
         "libgrallocusage",
@@ -96,20 +102,23 @@
     ],
 
     header_libs: [
+        "libbase_headers",
         "libnativebase_headers",
         "libhardware_headers",
+        "libui_headers",
+        "libpdx_headers",
     ],
 
-    export_include_dirs: ["include"],
-
     export_static_lib_headers: [
         "libarect",
         "libmath",
     ],
 
     export_header_lib_headers: [
+        "libbase_headers",
         "libnativebase_headers",
         "libhardware_headers",
+        "libui_headers",
     ],
 }
 
@@ -117,6 +126,11 @@
     name: "libui_headers",
     export_include_dirs: ["include"],
     vendor_available: true,
+    target: {
+        vendor: {
+            override_export_include_dirs: ["include_vndk"],
+        },
+    },
 }
 
 subdirs = [
diff --git a/libs/ui/DebugUtils.cpp b/libs/ui/DebugUtils.cpp
index 2d72944..61df02d 100644
--- a/libs/ui/DebugUtils.cpp
+++ b/libs/ui/DebugUtils.cpp
@@ -22,6 +22,8 @@
 #include <string>
 
 using android::base::StringPrintf;
+using android::ui::ColorMode;
+using android::ui::RenderIntent;
 
 std::string decodeStandard(android_dataspace dataspace) {
     const uint32_t dataspaceSelect = (dataspace & HAL_DATASPACE_STANDARD_MASK);
@@ -74,7 +76,7 @@
                 case HAL_DATASPACE_SRGB:
                     return std::string("(deprecated) sRGB");
 
-                case HAL_DATASPACE_V0_BT709:
+                case HAL_DATASPACE_BT709:
                     return std::string("(deprecated) BT709");
 
                 case HAL_DATASPACE_ARBITRARY:
@@ -84,7 +86,7 @@
                 // Fallthrough
                 default:
                     return android::base::StringPrintf("Unknown deprecated dataspace code %d",
-                                                       dataspaceSelect);
+                                                       dataspace);
             }
     }
 
@@ -98,7 +100,7 @@
             case HAL_DATASPACE_JFIF:
             case HAL_DATASPACE_BT601_625:
             case HAL_DATASPACE_BT601_525:
-            case HAL_DATASPACE_V0_BT709:
+            case HAL_DATASPACE_BT709:
                 return std::string("SMPTE_170M");
 
             case HAL_DATASPACE_SRGB_LINEAR:
@@ -159,8 +161,8 @@
 
             case HAL_DATASPACE_BT601_625:
             case HAL_DATASPACE_BT601_525:
-            case HAL_DATASPACE_V0_BT709:
-                return std::string("Limited range)");
+            case HAL_DATASPACE_BT709:
+                return std::string("Limited range");
 
             case HAL_DATASPACE_ARBITRARY:
             case HAL_DATASPACE_UNKNOWN:
@@ -197,42 +199,78 @@
                                        decodeRange(dataspace).c_str());
 }
 
-std::string decodeColorMode(android_color_mode colorMode) {
+std::string decodeColorMode(ColorMode colorMode) {
     switch (colorMode) {
-        case HAL_COLOR_MODE_NATIVE:
-            return std::string("HAL_COLOR_MODE_NATIVE");
+        case ColorMode::NATIVE:
+            return std::string("ColorMode::NATIVE");
 
-        case HAL_COLOR_MODE_STANDARD_BT601_625:
-            return std::string("HAL_COLOR_MODE_BT601_625");
+        case ColorMode::STANDARD_BT601_625:
+            return std::string("ColorMode::BT601_625");
 
-        case HAL_COLOR_MODE_STANDARD_BT601_625_UNADJUSTED:
-            return std::string("HAL_COLOR_MODE_BT601_625_UNADJUSTED");
+        case ColorMode::STANDARD_BT601_625_UNADJUSTED:
+            return std::string("ColorMode::BT601_625_UNADJUSTED");
 
-        case HAL_COLOR_MODE_STANDARD_BT601_525:
-            return std::string("HAL_COLOR_MODE_BT601_525");
+        case ColorMode::STANDARD_BT601_525:
+            return std::string("ColorMode::BT601_525");
 
-        case HAL_COLOR_MODE_STANDARD_BT601_525_UNADJUSTED:
-            return std::string("HAL_COLOR_MODE_BT601_525_UNADJUSTED");
+        case ColorMode::STANDARD_BT601_525_UNADJUSTED:
+            return std::string("ColorMode::BT601_525_UNADJUSTED");
 
-        case HAL_COLOR_MODE_STANDARD_BT709:
-            return std::string("HAL_COLOR_MODE_BT709");
+        case ColorMode::STANDARD_BT709:
+            return std::string("ColorMode::BT709");
 
-        case HAL_COLOR_MODE_DCI_P3:
-            return std::string("HAL_COLOR_MODE_DCI_P3");
+        case ColorMode::DCI_P3:
+            return std::string("ColorMode::DCI_P3");
 
-        case HAL_COLOR_MODE_SRGB:
-            return std::string("HAL_COLOR_MODE_SRGB");
+        case ColorMode::SRGB:
+            return std::string("ColorMode::SRGB");
 
-        case HAL_COLOR_MODE_ADOBE_RGB:
-            return std::string("HAL_COLOR_MODE_ADOBE_RGB");
+        case ColorMode::ADOBE_RGB:
+            return std::string("ColorMode::ADOBE_RGB");
 
-        case HAL_COLOR_MODE_DISPLAY_P3:
-            return std::string("HAL_COLOR_MODE_DISPLAY_P3");
+        case ColorMode::DISPLAY_P3:
+            return std::string("ColorMode::DISPLAY_P3");
+
+        case ColorMode::BT2020:
+            return std::string("ColorMode::BT2020");
+
+        case ColorMode::BT2100_PQ:
+            return std::string("ColorMode::BT2100_PQ");
+
+        case ColorMode::BT2100_HLG:
+            return std::string("ColorMode::BT2100_HLG");
     }
 
     return android::base::StringPrintf("Unknown color mode %d", colorMode);
 }
 
+std::string decodeColorTransform(android_color_transform colorTransform) {
+    switch (colorTransform) {
+        case HAL_COLOR_TRANSFORM_IDENTITY:
+            return std::string("Identity");
+
+        case HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX:
+            return std::string("Arbitrary matrix");
+
+        case HAL_COLOR_TRANSFORM_VALUE_INVERSE:
+            return std::string("Inverse value");
+
+        case HAL_COLOR_TRANSFORM_GRAYSCALE:
+            return std::string("Grayscale");
+
+        case HAL_COLOR_TRANSFORM_CORRECT_PROTANOPIA:
+            return std::string("Correct protanopia");
+
+        case HAL_COLOR_TRANSFORM_CORRECT_DEUTERANOPIA:
+            return std::string("Correct deuteranopia");
+
+        case HAL_COLOR_TRANSFORM_CORRECT_TRITANOPIA:
+            return std::string("Correct tritanopia");
+    }
+
+    return android::base::StringPrintf("Unknown color transform %d", colorTransform);
+}
+
 // Converts a PixelFormat to a human-readable string.  Max 11 chars.
 // (Could use a table of prefab String8 objects.)
 std::string decodePixelFormat(android::PixelFormat format) {
@@ -266,6 +304,20 @@
     }
 }
 
+std::string decodeRenderIntent(RenderIntent renderIntent) {
+    switch(renderIntent) {
+      case RenderIntent::COLORIMETRIC:
+          return std::string("RenderIntent::COLORIMETRIC");
+      case RenderIntent::ENHANCE:
+          return std::string("RenderIntent::ENHANCE");
+      case RenderIntent::TONE_MAP_COLORIMETRIC:
+          return std::string("RenderIntent::TONE_MAP_COLORIMETRIC");
+      case RenderIntent::TONE_MAP_ENHANCE:
+          return std::string("RenderIntent::TONE_MAP_ENHANCE");
+    }
+    return std::string("Unknown RenderIntent");
+}
+
 std::string to_string(const android::Rect& rect) {
     return StringPrintf("(%4d,%4d,%4d,%4d)", rect.left, rect.top, rect.right, rect.bottom);
 }
diff --git a/libs/ui/Fence.cpp b/libs/ui/Fence.cpp
index eb88be1..ed7ccb0b 100644
--- a/libs/ui/Fence.cpp
+++ b/libs/ui/Fence.cpp
@@ -37,18 +37,12 @@
 
 const sp<Fence> Fence::NO_FENCE = sp<Fence>(new Fence);
 
-Fence::Fence() :
-    mFenceFd(-1) {
-}
-
 Fence::Fence(int fenceFd) :
     mFenceFd(fenceFd) {
 }
 
-Fence::~Fence() {
-    if (mFenceFd != -1) {
-        close(mFenceFd);
-    }
+Fence::Fence(base::unique_fd fenceFd) :
+    mFenceFd(std::move(fenceFd)) {
 }
 
 status_t Fence::wait(int timeout) {
@@ -68,7 +62,7 @@
     int warningTimeout = 3000;
     int err = sync_wait(mFenceFd, warningTimeout);
     if (err < 0 && errno == ETIME) {
-        ALOGE("%s: fence %d didn't signal in %u ms", logname, mFenceFd,
+        ALOGE("%s: fence %d didn't signal in %u ms", logname, mFenceFd.get(),
                 warningTimeout);
         err = sync_wait(mFenceFd, TIMEOUT_NEVER);
     }
@@ -94,7 +88,7 @@
     if (result == -1) {
         status_t err = -errno;
         ALOGE("merge: sync_merge(\"%s\", %d, %d) returned an error: %s (%d)",
-                name, f1->mFenceFd, f2->mFenceFd,
+                name, f1->mFenceFd.get(), f2->mFenceFd.get(),
                 strerror(-err), err);
         return NO_FENCE;
     }
@@ -117,7 +111,7 @@
 
     struct sync_file_info* finfo = sync_file_info(mFenceFd);
     if (finfo == NULL) {
-        ALOGE("sync_file_info returned NULL for fd %d", mFenceFd);
+        ALOGE("sync_file_info returned NULL for fd %d", mFenceFd.get());
         return SIGNAL_TIME_INVALID;
     }
     if (finfo->status != 1) {
@@ -181,7 +175,7 @@
     }
 
     if (numFds) {
-        mFenceFd = *fds++;
+        mFenceFd.reset(*fds++);
         count--;
     }
 
diff --git a/libs/ui/Gralloc2.cpp b/libs/ui/Gralloc2.cpp
index 0eb08e5..37cf617 100644
--- a/libs/ui/Gralloc2.cpp
+++ b/libs/ui/Gralloc2.cpp
@@ -20,6 +20,7 @@
 #include <hwbinder/IPCThreadState.h>
 #include <ui/Gralloc2.h>
 
+#include <inttypes.h>
 #include <log/log.h>
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wzero-length-array"
@@ -30,35 +31,104 @@
 
 namespace Gralloc2 {
 
+namespace {
+
 static constexpr Error kTransactionError = Error::NO_RESOURCES;
 
+uint64_t getValid10UsageBits() {
+    static const uint64_t valid10UsageBits = []() -> uint64_t {
+        using hardware::graphics::common::V1_0::BufferUsage;
+        uint64_t bits = 0;
+        for (const auto bit : hardware::hidl_enum_range<BufferUsage>()) {
+            bits = bits | bit;
+        }
+        // TODO(b/72323293, b/72703005): Remove these additional bits
+        bits = bits | (1 << 10) | (1 << 13);
+
+        return bits;
+    }();
+    return valid10UsageBits;
+}
+
+uint64_t getValid11UsageBits() {
+    static const uint64_t valid11UsageBits = []() -> uint64_t {
+        using hardware::graphics::common::V1_1::BufferUsage;
+        uint64_t bits = 0;
+        for (const auto bit : hardware::hidl_enum_range<BufferUsage>()) {
+            bits = bits | bit;
+        }
+        return bits;
+    }();
+    return valid11UsageBits;
+}
+
+}  // anonymous namespace
+
 void Mapper::preload() {
     android::hardware::preloadPassthroughService<hardware::graphics::mapper::V2_0::IMapper>();
 }
 
 Mapper::Mapper()
 {
-    mMapper = IMapper::getService();
-    if (mMapper == nullptr || mMapper->isRemote()) {
+    mMapper = hardware::graphics::mapper::V2_0::IMapper::getService();
+    if (mMapper == nullptr) {
+        LOG_ALWAYS_FATAL("gralloc-mapper is missing");
+    }
+    if (mMapper->isRemote()) {
         LOG_ALWAYS_FATAL("gralloc-mapper must be in passthrough mode");
     }
+
+    // IMapper 2.1 is optional
+    mMapperV2_1 = IMapper::castFrom(mMapper);
+}
+
+Gralloc2::Error Mapper::validateBufferDescriptorInfo(
+        const IMapper::BufferDescriptorInfo& descriptorInfo) const {
+    uint64_t validUsageBits = getValid10UsageBits();
+    if (mMapperV2_1 != nullptr) {
+        validUsageBits = validUsageBits | getValid11UsageBits();
+    }
+
+    if (descriptorInfo.usage & ~validUsageBits) {
+        ALOGE("buffer descriptor contains invalid usage bits 0x%" PRIx64,
+              descriptorInfo.usage & ~validUsageBits);
+        return Error::BAD_VALUE;
+    }
+    return Error::NONE;
 }
 
 Error Mapper::createDescriptor(
         const IMapper::BufferDescriptorInfo& descriptorInfo,
         BufferDescriptor* outDescriptor) const
 {
-    Error error;
-    auto ret = mMapper->createDescriptor(descriptorInfo,
-            [&](const auto& tmpError, const auto& tmpDescriptor)
-            {
-                error = tmpError;
-                if (error != Error::NONE) {
-                    return;
-                }
+    Error error = validateBufferDescriptorInfo(descriptorInfo);
+    if (error != Error::NONE) {
+        return error;
+    }
 
-                *outDescriptor = tmpDescriptor;
-            });
+    auto hidl_cb = [&](const auto& tmpError, const auto& tmpDescriptor)
+                   {
+                       error = tmpError;
+                       if (error != Error::NONE) {
+                           return;
+                       }
+
+                       *outDescriptor = tmpDescriptor;
+                   };
+
+    hardware::Return<void> ret;
+    if (mMapperV2_1 != nullptr) {
+        ret = mMapperV2_1->createDescriptor_2_1(descriptorInfo, hidl_cb);
+    } else {
+        const hardware::graphics::mapper::V2_0::IMapper::BufferDescriptorInfo info = {
+            descriptorInfo.width,
+            descriptorInfo.height,
+            descriptorInfo.layerCount,
+            static_cast<hardware::graphics::common::V1_0::PixelFormat>(descriptorInfo.format),
+            descriptorInfo.usage,
+        };
+        ret = mMapper->createDescriptor(info, hidl_cb);
+    }
 
     return (ret.isOk()) ? error : kTransactionError;
 }
@@ -91,6 +161,50 @@
             buffer, error);
 }
 
+Error Mapper::validateBufferSize(buffer_handle_t bufferHandle,
+        const IMapper::BufferDescriptorInfo& descriptorInfo,
+        uint32_t stride) const
+{
+    if (mMapperV2_1 == nullptr) {
+        return Error::NONE;
+    }
+
+    auto buffer = const_cast<native_handle_t*>(bufferHandle);
+    auto ret = mMapperV2_1->validateBufferSize(buffer, descriptorInfo, stride);
+
+    return (ret.isOk()) ? static_cast<Error>(ret) : kTransactionError;
+}
+
+void Mapper::getTransportSize(buffer_handle_t bufferHandle,
+        uint32_t* outNumFds, uint32_t* outNumInts) const
+{
+    *outNumFds = uint32_t(bufferHandle->numFds);
+    *outNumInts = uint32_t(bufferHandle->numInts);
+
+    if (mMapperV2_1 == nullptr) {
+        return;
+    }
+
+    Error error;
+    auto buffer = const_cast<native_handle_t*>(bufferHandle);
+    auto ret = mMapperV2_1->getTransportSize(buffer,
+            [&](const auto& tmpError, const auto& tmpNumFds, const auto& tmpNumInts) {
+                error = tmpError;
+                if (error != Error::NONE) {
+                    return;
+                }
+
+                *outNumFds = tmpNumFds;
+                *outNumInts = tmpNumInts;
+            });
+
+    if (!ret.isOk()) {
+        error = kTransactionError;
+    }
+    ALOGE_IF(error != Error::NONE, "getTransportSize(%p) failed with %d",
+            buffer, error);
+}
+
 Error Mapper::lock(buffer_handle_t bufferHandle, uint64_t usage,
         const IMapper::Rect& accessRegion,
         int acquireFence, void** outData) const
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index c880500..254038b 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -22,6 +22,7 @@
 
 #include <grallocusage/GrallocUsageConversion.h>
 
+#include <ui/DetachedBufferHandle.h>
 #include <ui/Gralloc2.h>
 #include <ui/GraphicBufferAllocator.h>
 #include <ui/GraphicBufferMapper.h>
@@ -170,6 +171,8 @@
             inUsage, &handle, &outStride, mId,
             std::move(requestorName));
     if (err == NO_ERROR) {
+        mBufferMapper.getTransportSize(handle, &mTransportNumFds, &mTransportNumInts);
+
         width = static_cast<int>(inWidth);
         height = static_cast<int>(inHeight);
         format = inFormat;
@@ -199,7 +202,8 @@
 
     if (method == TAKE_UNREGISTERED_HANDLE || method == CLONE_HANDLE) {
         buffer_handle_t importedHandle;
-        status_t err = mBufferMapper.importBuffer(handle, &importedHandle);
+        status_t err = mBufferMapper.importBuffer(handle, width, height,
+                layerCount, format, usage, stride, &importedHandle);
         if (err != NO_ERROR) {
             initWithHandle(nullptr, WRAP_HANDLE, 0, 0, 0, 0, 0, 0);
 
@@ -212,6 +216,7 @@
         }
 
         handle = importedHandle;
+        mBufferMapper.getTransportSize(handle, &mTransportNumFds, &mTransportNumInts);
     }
 
     ANativeWindowBuffer::handle = handle;
@@ -323,11 +328,11 @@
 }
 
 size_t GraphicBuffer::getFlattenedSize() const {
-    return static_cast<size_t>(13 + (handle ? handle->numInts : 0)) * sizeof(int);
+    return static_cast<size_t>(13 + (handle ? mTransportNumInts : 0)) * sizeof(int);
 }
 
 size_t GraphicBuffer::getFdCount() const {
-    return static_cast<size_t>(handle ? handle->numFds : 0);
+    return static_cast<size_t>(handle ? mTransportNumFds : 0);
 }
 
 status_t GraphicBuffer::flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const {
@@ -353,18 +358,18 @@
     buf[12] = int(usage >> 32); // high 32-bits
 
     if (handle) {
-        buf[10] = handle->numFds;
-        buf[11] = handle->numInts;
-        memcpy(fds, handle->data, static_cast<size_t>(handle->numFds) * sizeof(int));
+        buf[10] = int32_t(mTransportNumFds);
+        buf[11] = int32_t(mTransportNumInts);
+        memcpy(fds, handle->data, static_cast<size_t>(mTransportNumFds) * sizeof(int));
         memcpy(buf + 13, handle->data + handle->numFds,
-                static_cast<size_t>(handle->numInts) * sizeof(int));
+                static_cast<size_t>(mTransportNumInts) * sizeof(int));
     }
 
     buffer = static_cast<void*>(static_cast<uint8_t*>(buffer) + sizeNeeded);
     size -= sizeNeeded;
     if (handle) {
-        fds += handle->numFds;
-        count -= static_cast<size_t>(handle->numFds);
+        fds += mTransportNumFds;
+        count -= static_cast<size_t>(mTransportNumFds);
     }
 
     return NO_ERROR;
@@ -457,7 +462,8 @@
 
     if (handle != 0) {
         buffer_handle_t importedHandle;
-        status_t err = mBufferMapper.importBuffer(handle, &importedHandle);
+        status_t err = mBufferMapper.importBuffer(handle, uint32_t(width), uint32_t(height),
+                uint32_t(layerCount), format, usage, uint32_t(stride), &importedHandle);
         if (err != NO_ERROR) {
             width = height = stride = format = usage_deprecated = 0;
             layerCount = 0;
@@ -470,6 +476,7 @@
         native_handle_close(handle);
         native_handle_delete(const_cast<native_handle_t*>(handle));
         handle = importedHandle;
+        mBufferMapper.getTransportSize(handle, &mTransportNumFds, &mTransportNumInts);
     }
 
     buffer = static_cast<void const*>(static_cast<uint8_t const*>(buffer) + sizeNeeded);
@@ -480,6 +487,24 @@
     return NO_ERROR;
 }
 
+bool GraphicBuffer::isDetachedBuffer() const {
+    return mDetachedBufferHandle && mDetachedBufferHandle->isValid();
+}
+
+status_t GraphicBuffer::setDetachedBufferHandle(std::unique_ptr<DetachedBufferHandle> channel) {
+    if (isDetachedBuffer()) {
+        ALOGW("setDetachedBuffer: there is already a BufferHub channel associated with this "
+              "GraphicBuffer. Replacing the old one.");
+    }
+
+    mDetachedBufferHandle = std::move(channel);
+    return NO_ERROR;
+}
+
+std::unique_ptr<DetachedBufferHandle> GraphicBuffer::takeDetachedBufferHandle() {
+    return std::move(mDetachedBufferHandle);
+}
+
 // ---------------------------------------------------------------------------
 
 }; // namespace android
diff --git a/libs/ui/GraphicBufferMapper.cpp b/libs/ui/GraphicBufferMapper.cpp
index d854489..2d8e582 100644
--- a/libs/ui/GraphicBufferMapper.cpp
+++ b/libs/ui/GraphicBufferMapper.cpp
@@ -52,17 +52,43 @@
 }
 
 status_t GraphicBufferMapper::importBuffer(buffer_handle_t rawHandle,
+        uint32_t width, uint32_t height, uint32_t layerCount,
+        PixelFormat format, uint64_t usage, uint32_t stride,
         buffer_handle_t* outHandle)
 {
     ATRACE_CALL();
 
+    buffer_handle_t bufferHandle;
     Gralloc2::Error error = mMapper->importBuffer(
-            hardware::hidl_handle(rawHandle), outHandle);
+            hardware::hidl_handle(rawHandle), &bufferHandle);
+    if (error != Gralloc2::Error::NONE) {
+        ALOGW("importBuffer(%p) failed: %d", rawHandle, error);
+        return static_cast<status_t>(error);
+    }
 
-    ALOGW_IF(error != Gralloc2::Error::NONE, "importBuffer(%p) failed: %d",
-            rawHandle, error);
+    Gralloc2::IMapper::BufferDescriptorInfo info = {};
+    info.width = width;
+    info.height = height;
+    info.layerCount = layerCount;
+    info.format = static_cast<Gralloc2::PixelFormat>(format);
+    info.usage = usage;
 
-    return static_cast<status_t>(error);
+    error = mMapper->validateBufferSize(bufferHandle, info, stride);
+    if (error != Gralloc2::Error::NONE) {
+        ALOGE("validateBufferSize(%p) failed: %d", rawHandle, error);
+        freeBuffer(bufferHandle);
+        return static_cast<status_t>(error);
+    }
+
+    *outHandle = bufferHandle;
+
+    return NO_ERROR;
+}
+
+void GraphicBufferMapper::getTransportSize(buffer_handle_t handle,
+            uint32_t* outTransportNumFds, uint32_t* outTransportNumInts)
+{
+    mMapper->getTransportSize(handle, outTransportNumFds, outTransportNumInts);
 }
 
 status_t GraphicBufferMapper::freeBuffer(buffer_handle_t handle)
diff --git a/libs/ui/HdrCapabilities.cpp b/libs/ui/HdrCapabilities.cpp
index 755e60c..a36911d 100644
--- a/libs/ui/HdrCapabilities.cpp
+++ b/libs/ui/HdrCapabilities.cpp
@@ -27,13 +27,12 @@
 HdrCapabilities::HdrCapabilities(HdrCapabilities&& other) = default;
 HdrCapabilities& HdrCapabilities::operator=(HdrCapabilities&& other) = default;
 
-
 size_t HdrCapabilities::getFlattenedSize() const {
     return  sizeof(mMaxLuminance) +
             sizeof(mMaxAverageLuminance) +
             sizeof(mMinLuminance) +
             sizeof(int32_t) +
-            mSupportedHdrTypes.size() * sizeof(int32_t);
+            mSupportedHdrTypes.size() * sizeof(ui::Hdr);
 }
 
 status_t HdrCapabilities::flatten(void* buffer, size_t size) const {
@@ -48,7 +47,7 @@
     reinterpret_cast<float&>(buf[2]) = mMinLuminance;
     buf[3] = static_cast<int32_t>(mSupportedHdrTypes.size());
     for (size_t i = 0, c = mSupportedHdrTypes.size(); i < c; ++i) {
-        buf[4 + i] = mSupportedHdrTypes[i];
+        buf[4 + i] = static_cast<int32_t>(mSupportedHdrTypes[i]);
     }
     return NO_ERROR;
 }
@@ -78,7 +77,7 @@
     if (itemCount) {
         mSupportedHdrTypes.resize(itemCount);
         for (size_t i = 0; i < itemCount; ++i) {
-            mSupportedHdrTypes[i] = buf[4 + i];
+            mSupportedHdrTypes[i] = static_cast<ui::Hdr>(buf[4 + i]);
         }
     }
     return NO_ERROR;
diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp
index b53c563..fe4ae6c 100644
--- a/libs/ui/Region.cpp
+++ b/libs/ui/Region.cpp
@@ -513,6 +513,12 @@
 
 bool Region::validate(const Region& reg, const char* name, bool silent)
 {
+    if (reg.mStorage.isEmpty()) {
+        ALOGE_IF(!silent, "%s: mStorage is empty, which is never valid", name);
+        // return immediately as the code below assumes mStorage is non-empty
+        return false;
+    }
+
     bool result = true;
     const_iterator cur = reg.begin();
     const_iterator const tail = reg.end();
@@ -832,6 +838,11 @@
 }
 
 Region::const_iterator Region::end() const {
+    // Workaround for b/77643177
+    // mStorage should never be empty, but somehow it is and it's causing
+    // an abort in ubsan
+    if (mStorage.isEmpty()) return mStorage.array();
+
     size_t numRects = isRect() ? 1 : mStorage.size() - 1;
     return mStorage.array() + numRects;
 }
diff --git a/libs/ui/include/ui/DebugUtils.h b/libs/ui/include/ui/DebugUtils.h
index dad9446..92b2bfb 100644
--- a/libs/ui/include/ui/DebugUtils.h
+++ b/libs/ui/include/ui/DebugUtils.h
@@ -16,7 +16,7 @@
 
 #pragma once
 
-#include <system/graphics.h>
+#include <ui/GraphicTypes.h>
 #include <ui/PixelFormat.h>
 
 #include <string>
@@ -29,6 +29,8 @@
 std::string decodeTransfer(android_dataspace dataspace);
 std::string decodeRange(android_dataspace dataspace);
 std::string dataspaceDetails(android_dataspace dataspace);
-std::string decodeColorMode(android_color_mode colormode);
+std::string decodeColorMode(android::ui::ColorMode colormode);
+std::string decodeColorTransform(android_color_transform colorTransform);
 std::string decodePixelFormat(android::PixelFormat format);
+std::string decodeRenderIntent(android::ui::RenderIntent renderIntent);
 std::string to_string(const android::Rect& rect);
diff --git a/libs/ui/include/ui/DetachedBufferHandle.h b/libs/ui/include/ui/DetachedBufferHandle.h
new file mode 100644
index 0000000..f3c328d
--- /dev/null
+++ b/libs/ui/include/ui/DetachedBufferHandle.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_DETACHED_BUFFER_HUB_HANDLE_H
+#define ANDROID_DETACHED_BUFFER_HUB_HANDLE_H
+
+#include <pdx/channel_handle.h>
+
+#include <memory>
+
+namespace android {
+
+// A wrapper that holds a pdx::LocalChannelHandle object. From the handle, a BufferHub buffer can be
+// created. Current implementation assumes that the underlying transport is using libpdx (thus
+// holding a pdx::LocalChannelHandle object), but future implementation can change it to a Binder
+// backend if ever needed.
+class DetachedBufferHandle {
+public:
+    static std::unique_ptr<DetachedBufferHandle> Create(pdx::LocalChannelHandle handle) {
+        return std::unique_ptr<DetachedBufferHandle>(new DetachedBufferHandle(std::move(handle)));
+    }
+
+    // Accessors to get or take the internal pdx::LocalChannelHandle.
+    pdx::LocalChannelHandle& handle() { return mHandle; }
+    const pdx::LocalChannelHandle& handle() const { return mHandle; }
+
+    // Returns whether the DetachedBufferHandle holds a BufferHub channel.
+    bool isValid() const { return mHandle.valid(); }
+
+private:
+    // Constructs a DetachedBufferHandle from a pdx::LocalChannelHandle.
+    explicit DetachedBufferHandle(pdx::LocalChannelHandle handle) : mHandle(std::move(handle)) {}
+
+    pdx::LocalChannelHandle mHandle;
+};
+
+} // namespace android
+
+#endif // ANDROID_DETACHED_BUFFER_HUB_HANDLE_H
diff --git a/libs/ui/include/ui/Fence.h b/libs/ui/include/ui/Fence.h
index 37811bc..ec67fa9 100644
--- a/libs/ui/include/ui/Fence.h
+++ b/libs/ui/include/ui/Fence.h
@@ -19,6 +19,7 @@
 
 #include <stdint.h>
 
+#include <android-base/unique_fd.h>
 #include <utils/Flattenable.h>
 #include <utils/RefBase.h>
 #include <utils/Timers.h>
@@ -49,12 +50,13 @@
     // Construct a new Fence object with an invalid file descriptor.  This
     // should be done when the Fence object will be set up by unflattening
     // serialized data.
-    Fence();
+    Fence() = default;
 
     // Construct a new Fence object to manage a given fence file descriptor.
     // When the new Fence object is destructed the file descriptor will be
     // closed.
     explicit Fence(int fenceFd);
+    explicit Fence(base::unique_fd fenceFd);
 
     // Not copyable or movable.
     Fence(const Fence& rhs) = delete;
@@ -136,9 +138,9 @@
 private:
     // Only allow instantiation using ref counting.
     friend class LightRefBase<Fence>;
-    ~Fence();
+    ~Fence() = default;
 
-    int mFenceFd;
+    base::unique_fd mFenceFd;
 };
 
 }; // namespace android
diff --git a/libs/ui/include/ui/Gralloc2.h b/libs/ui/include/ui/Gralloc2.h
index 8aee160..5a8dbda 100644
--- a/libs/ui/include/ui/Gralloc2.h
+++ b/libs/ui/include/ui/Gralloc2.h
@@ -20,7 +20,9 @@
 #include <string>
 
 #include <android/hardware/graphics/allocator/2.0/IAllocator.h>
+#include <android/hardware/graphics/common/1.1/types.h>
 #include <android/hardware/graphics/mapper/2.0/IMapper.h>
+#include <android/hardware/graphics/mapper/2.1/IMapper.h>
 #include <utils/StrongPointer.h>
 
 namespace android {
@@ -28,11 +30,11 @@
 namespace Gralloc2 {
 
 using hardware::graphics::allocator::V2_0::IAllocator;
-using hardware::graphics::common::V1_0::BufferUsage;
-using hardware::graphics::common::V1_0::PixelFormat;
+using hardware::graphics::common::V1_1::BufferUsage;
+using hardware::graphics::common::V1_1::PixelFormat;
+using hardware::graphics::mapper::V2_1::IMapper;
 using hardware::graphics::mapper::V2_0::BufferDescriptor;
 using hardware::graphics::mapper::V2_0::Error;
-using hardware::graphics::mapper::V2_0::IMapper;
 using hardware::graphics::mapper::V2_0::YCbCrLayout;
 
 // A wrapper to IMapper
@@ -55,6 +57,13 @@
 
     void freeBuffer(buffer_handle_t bufferHandle) const;
 
+    Error validateBufferSize(buffer_handle_t bufferHandle,
+            const IMapper::BufferDescriptorInfo& descriptorInfo,
+            uint32_t stride) const;
+
+    void getTransportSize(buffer_handle_t bufferHandle,
+            uint32_t* outNumFds, uint32_t* outNumInts) const;
+
     // The ownership of acquireFence is always transferred to the callee, even
     // on errors.
     Error lock(buffer_handle_t bufferHandle, uint64_t usage,
@@ -72,7 +81,12 @@
     int unlock(buffer_handle_t bufferHandle) const;
 
 private:
-    sp<IMapper> mMapper;
+    // Determines whether the passed info is compatible with the mapper.
+    Error validateBufferDescriptorInfo(
+            const IMapper::BufferDescriptorInfo& descriptorInfo) const;
+
+    sp<hardware::graphics::mapper::V2_0::IMapper> mMapper;
+    sp<IMapper> mMapperV2_1;
 };
 
 // A wrapper to IAllocator
diff --git a/libs/ui/include/ui/GraphicBuffer.h b/libs/ui/include/ui/GraphicBuffer.h
index 95c2d22..cc38982 100644
--- a/libs/ui/include/ui/GraphicBuffer.h
+++ b/libs/ui/include/ui/GraphicBuffer.h
@@ -34,6 +34,7 @@
 
 namespace android {
 
+class DetachedBufferHandle;
 class GraphicBufferMapper;
 
 // ===========================================================================
@@ -190,6 +191,11 @@
     status_t flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const;
     status_t unflatten(void const*& buffer, size_t& size, int const*& fds, size_t& count);
 
+    // Sets and takes DetachedBuffer. Should only be called from BufferHub.
+    bool isDetachedBuffer() const;
+    status_t setDetachedBufferHandle(std::unique_ptr<DetachedBufferHandle> detachedBuffer);
+    std::unique_ptr<DetachedBufferHandle> takeDetachedBufferHandle();
+
 private:
     ~GraphicBuffer();
 
@@ -230,12 +236,27 @@
     GraphicBufferMapper& mBufferMapper;
     ssize_t mInitCheck;
 
+    // numbers of fds/ints in native_handle_t to flatten
+    uint32_t mTransportNumFds;
+    uint32_t mTransportNumInts;
+
     uint64_t mId;
 
     // Stores the generation number of this buffer. If this number does not
     // match the BufferQueue's internal generation number (set through
     // IGBP::setGenerationNumber), attempts to attach the buffer will fail.
     uint32_t mGenerationNumber;
+
+    // Stores a BufferHub handle that can be used to re-attach this GraphicBuffer back into a
+    // BufferHub producer/consumer set. In terms of GraphicBuffer's relationship with BufferHub,
+    // there are three different modes:
+    // 1. Legacy mode: GraphicBuffer is not backed by BufferHub and mDetachedBufferHandle must be
+    //    invalid.
+    // 2. Detached mode: GraphicBuffer is backed by BufferHub, but not part of a producer/consumer
+    //    set. In this mode, mDetachedBufferHandle must be valid.
+    // 3. Attached mode: GraphicBuffer is backed by BufferHub and it's part of a producer/consumer
+    //    set. In this mode, mDetachedBufferHandle must be invalid.
+    std::unique_ptr<DetachedBufferHandle> mDetachedBufferHandle;
 };
 
 }; // namespace android
diff --git a/libs/ui/include/ui/GraphicBufferMapper.h b/libs/ui/include/ui/GraphicBufferMapper.h
index 06961b1..7cf003d 100644
--- a/libs/ui/include/ui/GraphicBufferMapper.h
+++ b/libs/ui/include/ui/GraphicBufferMapper.h
@@ -22,6 +22,7 @@
 
 #include <memory>
 
+#include <ui/PixelFormat.h>
 #include <utils/Singleton.h>
 
 
@@ -49,10 +50,15 @@
     // The imported outHandle must be freed with freeBuffer when no longer
     // needed. rawHandle is owned by the caller.
     status_t importBuffer(buffer_handle_t rawHandle,
+            uint32_t width, uint32_t height, uint32_t layerCount,
+            PixelFormat format, uint64_t usage, uint32_t stride,
             buffer_handle_t* outHandle);
 
     status_t freeBuffer(buffer_handle_t handle);
 
+    void getTransportSize(buffer_handle_t handle,
+            uint32_t* outTransportNumFds, uint32_t* outTransportNumInts);
+
     status_t lock(buffer_handle_t handle,
             uint32_t usage, const Rect& bounds, void** vaddr);
 
diff --git a/libs/ui/include/ui/GraphicTypes.h b/libs/ui/include/ui/GraphicTypes.h
new file mode 100644
index 0000000..0fa819d
--- /dev/null
+++ b/libs/ui/include/ui/GraphicTypes.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/graphics/common/1.1/types.h>
+#include <system/graphics.h>
+
+// android::ui::* in this header file will alias different types as
+// the HIDL interface is updated.
+namespace android {
+namespace ui {
+
+using android::hardware::graphics::common::V1_0::Hdr;
+using android::hardware::graphics::common::V1_1::ColorMode;
+using android::hardware::graphics::common::V1_1::Dataspace;
+using android::hardware::graphics::common::V1_1::PixelFormat;
+using android::hardware::graphics::common::V1_1::RenderIntent;
+
+}  // namespace ui
+}  // namespace android
diff --git a/libs/ui/include/ui/HdrCapabilities.h b/libs/ui/include/ui/HdrCapabilities.h
index 925aa1b..4e98c28 100644
--- a/libs/ui/include/ui/HdrCapabilities.h
+++ b/libs/ui/include/ui/HdrCapabilities.h
@@ -21,6 +21,7 @@
 
 #include <vector>
 
+#include <ui/GraphicTypes.h>
 #include <utils/Flattenable.h>
 
 namespace android {
@@ -28,7 +29,7 @@
 class HdrCapabilities : public LightFlattenable<HdrCapabilities>
 {
 public:
-    HdrCapabilities(const std::vector<int32_t /*android_hdr_t*/>& types,
+    HdrCapabilities(const std::vector<ui::Hdr>& types,
             float maxLuminance, float maxAverageLuminance, float minLuminance)
       : mSupportedHdrTypes(types),
         mMaxLuminance(maxLuminance),
@@ -47,7 +48,7 @@
 
     ~HdrCapabilities();
 
-    const std::vector<int32_t /*android_hdr_t*/>& getSupportedHdrTypes() const {
+    const std::vector<ui::Hdr>& getSupportedHdrTypes() const {
         return mSupportedHdrTypes;
     }
     float getDesiredMaxLuminance() const { return mMaxLuminance; }
@@ -61,7 +62,7 @@
     status_t unflatten(void const* buffer, size_t size);
 
 private:
-    std::vector<int32_t /*android_hdr_t*/> mSupportedHdrTypes;
+    std::vector<ui::Hdr> mSupportedHdrTypes;
     float mMaxLuminance;
     float mMaxAverageLuminance;
     float mMinLuminance;
diff --git a/libs/ui/include/ui/Rect.h b/libs/ui/include/ui/Rect.h
index c099a02..0bec0b7 100644
--- a/libs/ui/include/ui/Rect.h
+++ b/libs/ui/include/ui/Rect.h
@@ -95,15 +95,18 @@
     }
 
     // rectangle's width
+    __attribute__((no_sanitize("signed-integer-overflow")))
     inline int32_t getWidth() const {
         return right - left;
     }
 
     // rectangle's height
+    __attribute__((no_sanitize("signed-integer-overflow")))
     inline int32_t getHeight() const {
         return bottom - top;
     }
 
+    __attribute__((no_sanitize("signed-integer-overflow")))
     inline Rect getBounds() const {
         return Rect(right - left, bottom - top);
     }
diff --git a/libs/ui/include_vndk/ui/ANativeObjectBase.h b/libs/ui/include_vndk/ui/ANativeObjectBase.h
new file mode 120000
index 0000000..4dab8d8
--- /dev/null
+++ b/libs/ui/include_vndk/ui/ANativeObjectBase.h
@@ -0,0 +1 @@
+../../include/ui/ANativeObjectBase.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/BufferQueueDefs.h b/libs/ui/include_vndk/ui/BufferQueueDefs.h
new file mode 120000
index 0000000..c886ed8
--- /dev/null
+++ b/libs/ui/include_vndk/ui/BufferQueueDefs.h
@@ -0,0 +1 @@
+../../include/ui/BufferQueueDefs.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/ColorSpace.h b/libs/ui/include_vndk/ui/ColorSpace.h
new file mode 120000
index 0000000..ddf70d5
--- /dev/null
+++ b/libs/ui/include_vndk/ui/ColorSpace.h
@@ -0,0 +1 @@
+../../include/ui/ColorSpace.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/DebugUtils.h b/libs/ui/include_vndk/ui/DebugUtils.h
new file mode 120000
index 0000000..8461bb3
--- /dev/null
+++ b/libs/ui/include_vndk/ui/DebugUtils.h
@@ -0,0 +1 @@
+../../include/ui/DebugUtils.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/DisplayInfo.h b/libs/ui/include_vndk/ui/DisplayInfo.h
new file mode 120000
index 0000000..75f14cf
--- /dev/null
+++ b/libs/ui/include_vndk/ui/DisplayInfo.h
@@ -0,0 +1 @@
+../../include/ui/DisplayInfo.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/DisplayStatInfo.h b/libs/ui/include_vndk/ui/DisplayStatInfo.h
new file mode 120000
index 0000000..6689ad3
--- /dev/null
+++ b/libs/ui/include_vndk/ui/DisplayStatInfo.h
@@ -0,0 +1 @@
+../../include/ui/DisplayStatInfo.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/Fence.h b/libs/ui/include_vndk/ui/Fence.h
new file mode 120000
index 0000000..b110201
--- /dev/null
+++ b/libs/ui/include_vndk/ui/Fence.h
@@ -0,0 +1 @@
+../../include/ui/Fence.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/FenceTime.h b/libs/ui/include_vndk/ui/FenceTime.h
new file mode 120000
index 0000000..01a6ff2
--- /dev/null
+++ b/libs/ui/include_vndk/ui/FenceTime.h
@@ -0,0 +1 @@
+../../include/ui/FenceTime.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/FloatRect.h b/libs/ui/include_vndk/ui/FloatRect.h
new file mode 120000
index 0000000..a526211
--- /dev/null
+++ b/libs/ui/include_vndk/ui/FloatRect.h
@@ -0,0 +1 @@
+../../include/ui/FloatRect.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/FrameStats.h b/libs/ui/include_vndk/ui/FrameStats.h
new file mode 120000
index 0000000..e68e5c8
--- /dev/null
+++ b/libs/ui/include_vndk/ui/FrameStats.h
@@ -0,0 +1 @@
+../../include/ui/FrameStats.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/Gralloc2.h b/libs/ui/include_vndk/ui/Gralloc2.h
new file mode 120000
index 0000000..66098c4
--- /dev/null
+++ b/libs/ui/include_vndk/ui/Gralloc2.h
@@ -0,0 +1 @@
+../../include/ui/Gralloc2.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/GraphicBuffer.h b/libs/ui/include_vndk/ui/GraphicBuffer.h
new file mode 120000
index 0000000..445eae5
--- /dev/null
+++ b/libs/ui/include_vndk/ui/GraphicBuffer.h
@@ -0,0 +1 @@
+../../include/ui/GraphicBuffer.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/GraphicBufferAllocator.h b/libs/ui/include_vndk/ui/GraphicBufferAllocator.h
new file mode 120000
index 0000000..9634533
--- /dev/null
+++ b/libs/ui/include_vndk/ui/GraphicBufferAllocator.h
@@ -0,0 +1 @@
+../../include/ui/GraphicBufferAllocator.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/GraphicBufferMapper.h b/libs/ui/include_vndk/ui/GraphicBufferMapper.h
new file mode 120000
index 0000000..c3b3a7c
--- /dev/null
+++ b/libs/ui/include_vndk/ui/GraphicBufferMapper.h
@@ -0,0 +1 @@
+../../include/ui/GraphicBufferMapper.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/GraphicTypes.h b/libs/ui/include_vndk/ui/GraphicTypes.h
new file mode 120000
index 0000000..b1859e0
--- /dev/null
+++ b/libs/ui/include_vndk/ui/GraphicTypes.h
@@ -0,0 +1 @@
+../../include/ui/GraphicTypes.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/HdrCapabilities.h b/libs/ui/include_vndk/ui/HdrCapabilities.h
new file mode 120000
index 0000000..a240828
--- /dev/null
+++ b/libs/ui/include_vndk/ui/HdrCapabilities.h
@@ -0,0 +1 @@
+../../include/ui/HdrCapabilities.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/PixelFormat.h b/libs/ui/include_vndk/ui/PixelFormat.h
new file mode 120000
index 0000000..0aba056
--- /dev/null
+++ b/libs/ui/include_vndk/ui/PixelFormat.h
@@ -0,0 +1 @@
+../../include/ui/PixelFormat.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/Point.h b/libs/ui/include_vndk/ui/Point.h
new file mode 120000
index 0000000..0aeda3e
--- /dev/null
+++ b/libs/ui/include_vndk/ui/Point.h
@@ -0,0 +1 @@
+../../include/ui/Point.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/Rect.h b/libs/ui/include_vndk/ui/Rect.h
new file mode 120000
index 0000000..01ed689
--- /dev/null
+++ b/libs/ui/include_vndk/ui/Rect.h
@@ -0,0 +1 @@
+../../include/ui/Rect.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/Region.h b/libs/ui/include_vndk/ui/Region.h
new file mode 120000
index 0000000..3f829bf
--- /dev/null
+++ b/libs/ui/include_vndk/ui/Region.h
@@ -0,0 +1 @@
+../../include/ui/Region.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/UiConfig.h b/libs/ui/include_vndk/ui/UiConfig.h
new file mode 120000
index 0000000..f580ce1
--- /dev/null
+++ b/libs/ui/include_vndk/ui/UiConfig.h
@@ -0,0 +1 @@
+../../include/ui/UiConfig.h
\ No newline at end of file
diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp
index 08067fc..aef6428 100644
--- a/libs/ui/tests/Android.bp
+++ b/libs/ui/tests/Android.bp
@@ -27,3 +27,10 @@
     srcs: ["colorspace_test.cpp"],
     cflags: ["-Wall", "-Werror"],
 }
+
+cc_test {
+    name: "GraphicBuffer_test",
+    shared_libs: ["libpdx_default_transport", "libui", "libutils"],
+    srcs: ["GraphicBuffer_test.cpp"],
+    cflags: ["-Wall", "-Werror"],
+}
diff --git a/libs/ui/tests/GraphicBuffer_test.cpp b/libs/ui/tests/GraphicBuffer_test.cpp
new file mode 100644
index 0000000..eb679ac
--- /dev/null
+++ b/libs/ui/tests/GraphicBuffer_test.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2018 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 "GraphicBufferTest"
+
+#include <ui/DetachedBufferHandle.h>
+#include <ui/GraphicBuffer.h>
+
+#include <gtest/gtest.h>
+
+namespace android {
+
+namespace {
+
+constexpr uint32_t kTestWidth = 1024;
+constexpr uint32_t kTestHeight = 1;
+constexpr uint32_t kTestFormat = HAL_PIXEL_FORMAT_BLOB;
+constexpr uint32_t kTestLayerCount = 1;
+constexpr uint64_t kTestUsage = GraphicBuffer::USAGE_SW_WRITE_OFTEN;
+
+} // namespace
+
+class GraphicBufferTest : public testing::Test {};
+
+TEST_F(GraphicBufferTest, DetachedBuffer) {
+    sp<GraphicBuffer> buffer(
+            new GraphicBuffer(kTestWidth, kTestHeight, kTestFormat, kTestLayerCount, kTestUsage));
+
+    // Currently a newly allocated GraphicBuffer is in legacy mode, i.e. not associated with
+    // BufferHub. But this may change in the future.
+    EXPECT_FALSE(buffer->isDetachedBuffer());
+
+    pdx::LocalChannelHandle channel{nullptr, 1234};
+    EXPECT_TRUE(channel.valid());
+
+    std::unique_ptr<DetachedBufferHandle> handle = DetachedBufferHandle::Create(std::move(channel));
+    EXPECT_FALSE(channel.valid());
+    EXPECT_TRUE(handle->isValid());
+    EXPECT_TRUE(handle->handle().valid());
+
+    buffer->setDetachedBufferHandle(std::move(handle));
+    EXPECT_TRUE(handle == nullptr);
+    EXPECT_TRUE(buffer->isDetachedBuffer());
+
+    handle = buffer->takeDetachedBufferHandle();
+    EXPECT_TRUE(handle != nullptr);
+    EXPECT_TRUE(handle->isValid());
+    EXPECT_FALSE(buffer->isDetachedBuffer());
+}
+
+} // namespace android
diff --git a/libs/vr/libbufferhub/Android.bp b/libs/vr/libbufferhub/Android.bp
index a13160f..69b6422 100644
--- a/libs/vr/libbufferhub/Android.bp
+++ b/libs/vr/libbufferhub/Android.bp
@@ -15,6 +15,7 @@
 sourceFiles = [
     "buffer_hub_client.cpp",
     "buffer_hub_rpc.cpp",
+    "detached_buffer.cpp",
     "ion_buffer.cpp",
 ]
 
@@ -22,19 +23,16 @@
     "include",
 ]
 
-staticLibraries = [
-    "libdvrcommon",
-    "libpdx_default_transport",
-]
-
 sharedLibraries = [
     "libbase",
+    "libbinder",
     "libcutils",
     "libhardware",
     "liblog",
     "libui",
     "libutils",
-    "libnativewindow"
+    "libnativewindow",
+    "libpdx_default_transport",
 ]
 
 headerLibraries = [
@@ -52,7 +50,6 @@
         "-Werror",
     ],
     export_include_dirs: localIncludeFiles,
-    static_libs: staticLibraries,
     shared_libs: sharedLibraries,
     header_libs: headerLibraries,
     name: "libbufferhub",
@@ -62,9 +59,10 @@
 }
 
 cc_test {
-    srcs: ["bufferhub_tests.cpp"],
-    static_libs: ["libbufferhub"] + staticLibraries,
+    srcs: ["buffer_hub-test.cpp"],
+    static_libs: ["libbufferhub"],
     shared_libs: sharedLibraries,
     header_libs: headerLibraries,
-    name: "bufferhub_tests",
+    name: "buffer_hub-test",
 }
+
diff --git a/libs/vr/libbufferhub/buffer_hub-test.cpp b/libs/vr/libbufferhub/buffer_hub-test.cpp
new file mode 100644
index 0000000..e247398
--- /dev/null
+++ b/libs/vr/libbufferhub/buffer_hub-test.cpp
@@ -0,0 +1,947 @@
+#include <gtest/gtest.h>
+#include <poll.h>
+#include <private/dvr/buffer_hub_client.h>
+#include <private/dvr/bufferhub_rpc.h>
+#include <private/dvr/detached_buffer.h>
+#include <sys/epoll.h>
+#include <sys/eventfd.h>
+#include <ui/DetachedBufferHandle.h>
+
+#include <mutex>
+#include <thread>
+
+#define RETRY_EINTR(fnc_call)                 \
+  ([&]() -> decltype(fnc_call) {              \
+    decltype(fnc_call) result;                \
+    do {                                      \
+      result = (fnc_call);                    \
+    } while (result == -1 && errno == EINTR); \
+    return result;                            \
+  })()
+
+using android::GraphicBuffer;
+using android::sp;
+using android::dvr::BufferConsumer;
+using android::dvr::BufferProducer;
+using android::dvr::DetachedBuffer;
+using android::dvr::BufferHubDefs::IsBufferAcquired;
+using android::dvr::BufferHubDefs::IsBufferGained;
+using android::dvr::BufferHubDefs::IsBufferPosted;
+using android::dvr::BufferHubDefs::IsBufferReleased;
+using android::dvr::BufferHubDefs::kConsumerStateMask;
+using android::dvr::BufferHubDefs::kMetadataHeaderSize;
+using android::dvr::BufferHubDefs::kProducerStateBit;
+using android::pdx::LocalChannelHandle;
+using android::pdx::LocalHandle;
+using android::pdx::Status;
+
+const int kWidth = 640;
+const int kHeight = 480;
+const int kLayerCount = 1;
+const int kFormat = HAL_PIXEL_FORMAT_RGBA_8888;
+const int kUsage = 0;
+const size_t kUserMetadataSize = 0;
+const uint64_t kContext = 42;
+const size_t kMaxConsumerCount = 63;
+const int kPollTimeoutMs = 100;
+
+using LibBufferHubTest = ::testing::Test;
+
+TEST_F(LibBufferHubTest, TestBasicUsage) {
+  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+      kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
+  ASSERT_TRUE(p.get() != nullptr);
+  std::unique_ptr<BufferConsumer> c =
+      BufferConsumer::Import(p->CreateConsumer());
+  ASSERT_TRUE(c.get() != nullptr);
+  // Check that consumers can spawn other consumers.
+  std::unique_ptr<BufferConsumer> c2 =
+      BufferConsumer::Import(c->CreateConsumer());
+  ASSERT_TRUE(c2.get() != nullptr);
+
+  // Producer state mask is unique, i.e. 1.
+  EXPECT_EQ(p->buffer_state_bit(), kProducerStateBit);
+  // Consumer state mask cannot have producer bit on.
+  EXPECT_EQ(c->buffer_state_bit() & kProducerStateBit, 0U);
+  // Consumer state mask must be a single, i.e. power of 2.
+  EXPECT_NE(c->buffer_state_bit(), 0U);
+  EXPECT_EQ(c->buffer_state_bit() & (c->buffer_state_bit() - 1), 0U);
+  // Consumer state mask cannot have producer bit on.
+  EXPECT_EQ(c2->buffer_state_bit() & kProducerStateBit, 0U);
+  // Consumer state mask must be a single, i.e. power of 2.
+  EXPECT_NE(c2->buffer_state_bit(), 0U);
+  EXPECT_EQ(c2->buffer_state_bit() & (c2->buffer_state_bit() - 1), 0U);
+  // Each consumer should have unique bit.
+  EXPECT_EQ(c->buffer_state_bit() & c2->buffer_state_bit(), 0U);
+
+  // Initial state: producer not available, consumers not available.
+  EXPECT_EQ(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+  EXPECT_EQ(0, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
+  EXPECT_EQ(0, RETRY_EINTR(c2->Poll(kPollTimeoutMs)));
+
+  EXPECT_EQ(0, p->Post(LocalHandle(), kContext));
+
+  // New state: producer not available, consumers available.
+  EXPECT_EQ(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+  EXPECT_EQ(1, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
+  EXPECT_EQ(1, RETRY_EINTR(c2->Poll(kPollTimeoutMs)));
+
+  uint64_t context;
+  LocalHandle fence;
+  EXPECT_EQ(0, c->Acquire(&fence, &context));
+  EXPECT_EQ(kContext, context);
+  EXPECT_EQ(0, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
+  EXPECT_EQ(1, RETRY_EINTR(c2->Poll(kPollTimeoutMs)));
+
+  EXPECT_EQ(0, c2->Acquire(&fence, &context));
+  EXPECT_EQ(kContext, context);
+  EXPECT_EQ(0, RETRY_EINTR(c2->Poll(kPollTimeoutMs)));
+  EXPECT_EQ(0, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
+
+  EXPECT_EQ(0, c->Release(LocalHandle()));
+  EXPECT_EQ(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+  EXPECT_EQ(0, c2->Discard());
+
+  EXPECT_EQ(1, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+  EXPECT_EQ(0, p->Gain(&fence));
+  EXPECT_EQ(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+  EXPECT_EQ(0, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
+  EXPECT_EQ(0, RETRY_EINTR(c2->Poll(kPollTimeoutMs)));
+}
+
+TEST_F(LibBufferHubTest, TestEpoll) {
+  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+      kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
+  ASSERT_TRUE(p.get() != nullptr);
+  std::unique_ptr<BufferConsumer> c =
+      BufferConsumer::Import(p->CreateConsumer());
+  ASSERT_TRUE(c.get() != nullptr);
+
+  LocalHandle epoll_fd{epoll_create1(EPOLL_CLOEXEC)};
+  ASSERT_TRUE(epoll_fd.IsValid());
+
+  epoll_event event;
+  std::array<epoll_event, 64> events;
+
+  auto event_sources = p->GetEventSources();
+  ASSERT_LT(event_sources.size(), events.size());
+
+  for (const auto& event_source : event_sources) {
+    event = {.events = event_source.event_mask | EPOLLET,
+             .data = {.fd = p->event_fd()}};
+    ASSERT_EQ(0, epoll_ctl(epoll_fd.Get(), EPOLL_CTL_ADD, event_source.event_fd,
+                           &event));
+  }
+
+  event_sources = c->GetEventSources();
+  ASSERT_LT(event_sources.size(), events.size());
+
+  for (const auto& event_source : event_sources) {
+    event = {.events = event_source.event_mask | EPOLLET,
+             .data = {.fd = c->event_fd()}};
+    ASSERT_EQ(0, epoll_ctl(epoll_fd.Get(), EPOLL_CTL_ADD, event_source.event_fd,
+                           &event));
+  }
+
+  // No events should be signaled initially.
+  ASSERT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(), 0));
+
+  // Post the producer and check for consumer signal.
+  EXPECT_EQ(0, p->Post({}, kContext));
+  ASSERT_EQ(1, epoll_wait(epoll_fd.Get(), events.data(), events.size(),
+                          kPollTimeoutMs));
+  ASSERT_TRUE(events[0].events & EPOLLIN);
+  ASSERT_EQ(c->event_fd(), events[0].data.fd);
+
+  // Save the event bits to translate later.
+  event = events[0];
+
+  // Check for events again. Edge-triggered mode should prevent any.
+  EXPECT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(),
+                          kPollTimeoutMs));
+  EXPECT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(),
+                          kPollTimeoutMs));
+  EXPECT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(),
+                          kPollTimeoutMs));
+  EXPECT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(),
+                          kPollTimeoutMs));
+
+  // Translate the events.
+  auto event_status = c->GetEventMask(event.events);
+  ASSERT_TRUE(event_status);
+  ASSERT_TRUE(event_status.get() & EPOLLIN);
+
+  // Check for events again. Edge-triggered mode should prevent any.
+  EXPECT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(),
+                          kPollTimeoutMs));
+}
+
+TEST_F(LibBufferHubTest, TestStateMask) {
+  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+      kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
+  ASSERT_TRUE(p.get() != nullptr);
+
+  // It's ok to create up to kMaxConsumerCount consumer buffers.
+  uint64_t buffer_state_bits = p->buffer_state_bit();
+  std::array<std::unique_ptr<BufferConsumer>, kMaxConsumerCount> cs;
+  for (size_t i = 0; i < kMaxConsumerCount; i++) {
+    cs[i] = BufferConsumer::Import(p->CreateConsumer());
+    ASSERT_TRUE(cs[i].get() != nullptr);
+    // Expect all buffers have unique state mask.
+    EXPECT_EQ(buffer_state_bits & cs[i]->buffer_state_bit(), 0U);
+    buffer_state_bits |= cs[i]->buffer_state_bit();
+  }
+  EXPECT_EQ(buffer_state_bits, kProducerStateBit | kConsumerStateMask);
+
+  // The 64th creation will fail with out-of-memory error.
+  auto state = p->CreateConsumer();
+  EXPECT_EQ(state.error(), E2BIG);
+
+  // Release any consumer should allow us to re-create.
+  for (size_t i = 0; i < kMaxConsumerCount; i++) {
+    buffer_state_bits &= ~cs[i]->buffer_state_bit();
+    cs[i] = nullptr;
+    cs[i] = BufferConsumer::Import(p->CreateConsumer());
+    ASSERT_TRUE(cs[i].get() != nullptr);
+    // The released state mask will be reused.
+    EXPECT_EQ(buffer_state_bits & cs[i]->buffer_state_bit(), 0U);
+    buffer_state_bits |= cs[i]->buffer_state_bit();
+    EXPECT_EQ(buffer_state_bits, kProducerStateBit | kConsumerStateMask);
+  }
+}
+
+TEST_F(LibBufferHubTest, TestStateTransitions) {
+  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+      kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
+  ASSERT_TRUE(p.get() != nullptr);
+  std::unique_ptr<BufferConsumer> c =
+      BufferConsumer::Import(p->CreateConsumer());
+  ASSERT_TRUE(c.get() != nullptr);
+
+  uint64_t context;
+  LocalHandle fence;
+
+  // The producer buffer starts in gained state.
+
+  // Acquire, release, and gain in gained state should fail.
+  EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context));
+  EXPECT_EQ(-EBUSY, c->Release(LocalHandle()));
+  EXPECT_EQ(-EALREADY, p->Gain(&fence));
+
+  // Post in gained state should succeed.
+  EXPECT_EQ(0, p->Post(LocalHandle(), kContext));
+
+  // Post, release, and gain in posted state should fail.
+  EXPECT_EQ(-EBUSY, p->Post(LocalHandle(), kContext));
+  EXPECT_EQ(-EBUSY, c->Release(LocalHandle()));
+  EXPECT_EQ(-EBUSY, p->Gain(&fence));
+
+  // Acquire in posted state should succeed.
+  EXPECT_LE(0, c->Acquire(&fence, &context));
+
+  // Acquire, post, and gain in acquired state should fail.
+  EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context));
+  EXPECT_EQ(-EBUSY, p->Post(LocalHandle(), kContext));
+  EXPECT_EQ(-EBUSY, p->Gain(&fence));
+
+  // Release in acquired state should succeed.
+  EXPECT_EQ(0, c->Release(LocalHandle()));
+  EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+
+  // Release, acquire, and post in released state should fail.
+  EXPECT_EQ(-EBUSY, c->Release(LocalHandle()));
+  EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context));
+  EXPECT_EQ(-EBUSY, p->Post(LocalHandle(), kContext));
+
+  // Gain in released state should succeed.
+  EXPECT_EQ(0, p->Gain(&fence));
+
+  // Acquire, release, and gain in gained state should fail.
+  EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context));
+  EXPECT_EQ(-EBUSY, c->Release(LocalHandle()));
+  EXPECT_EQ(-EALREADY, p->Gain(&fence));
+}
+
+TEST_F(LibBufferHubTest, TestAsyncStateTransitions) {
+  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+      kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
+  ASSERT_TRUE(p.get() != nullptr);
+  std::unique_ptr<BufferConsumer> c =
+      BufferConsumer::Import(p->CreateConsumer());
+  ASSERT_TRUE(c.get() != nullptr);
+
+  DvrNativeBufferMetadata metadata;
+  LocalHandle invalid_fence;
+
+  // The producer buffer starts in gained state.
+
+  // Acquire, release, and gain in gained state should fail.
+  EXPECT_EQ(-EBUSY, c->AcquireAsync(&metadata, &invalid_fence));
+  EXPECT_FALSE(invalid_fence.IsValid());
+  EXPECT_EQ(-EBUSY, c->ReleaseAsync(&metadata, invalid_fence));
+  EXPECT_EQ(-EALREADY, p->GainAsync(&metadata, &invalid_fence));
+  EXPECT_FALSE(invalid_fence.IsValid());
+
+  // Post in gained state should succeed.
+  EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence));
+  EXPECT_EQ(p->buffer_state(), c->buffer_state());
+  EXPECT_TRUE(IsBufferPosted(p->buffer_state()));
+
+  // Post, release, and gain in posted state should fail.
+  EXPECT_EQ(-EBUSY, p->PostAsync(&metadata, invalid_fence));
+  EXPECT_EQ(-EBUSY, c->ReleaseAsync(&metadata, invalid_fence));
+  EXPECT_EQ(-EBUSY, p->GainAsync(&metadata, &invalid_fence));
+  EXPECT_FALSE(invalid_fence.IsValid());
+
+  // Acquire in posted state should succeed.
+  EXPECT_LT(0, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
+  EXPECT_EQ(0, c->AcquireAsync(&metadata, &invalid_fence));
+  EXPECT_FALSE(invalid_fence.IsValid());
+  EXPECT_EQ(p->buffer_state(), c->buffer_state());
+  EXPECT_TRUE(IsBufferAcquired(p->buffer_state()));
+
+  // Acquire, post, and gain in acquired state should fail.
+  EXPECT_EQ(-EBUSY, c->AcquireAsync(&metadata, &invalid_fence));
+  EXPECT_FALSE(invalid_fence.IsValid());
+  EXPECT_EQ(-EBUSY, p->PostAsync(&metadata, invalid_fence));
+  EXPECT_EQ(-EBUSY, p->GainAsync(&metadata, &invalid_fence));
+  EXPECT_FALSE(invalid_fence.IsValid());
+
+  // Release in acquired state should succeed.
+  EXPECT_EQ(0, c->ReleaseAsync(&metadata, invalid_fence));
+  EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+  EXPECT_EQ(p->buffer_state(), c->buffer_state());
+  EXPECT_TRUE(IsBufferReleased(p->buffer_state()));
+
+  // Release, acquire, and post in released state should fail.
+  EXPECT_EQ(-EBUSY, c->ReleaseAsync(&metadata, invalid_fence));
+  EXPECT_EQ(-EBUSY, c->AcquireAsync(&metadata, &invalid_fence));
+  EXPECT_FALSE(invalid_fence.IsValid());
+  EXPECT_EQ(-EBUSY, p->PostAsync(&metadata, invalid_fence));
+
+  // Gain in released state should succeed.
+  EXPECT_EQ(0, p->GainAsync(&metadata, &invalid_fence));
+  EXPECT_FALSE(invalid_fence.IsValid());
+  EXPECT_EQ(p->buffer_state(), c->buffer_state());
+  EXPECT_TRUE(IsBufferGained(p->buffer_state()));
+
+  // Acquire, release, and gain in gained state should fail.
+  EXPECT_EQ(-EBUSY, c->AcquireAsync(&metadata, &invalid_fence));
+  EXPECT_FALSE(invalid_fence.IsValid());
+  EXPECT_EQ(-EBUSY, c->ReleaseAsync(&metadata, invalid_fence));
+  EXPECT_EQ(-EALREADY, p->GainAsync(&metadata, &invalid_fence));
+  EXPECT_FALSE(invalid_fence.IsValid());
+}
+
+TEST_F(LibBufferHubTest, TestZeroConsumer) {
+  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+      kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
+  ASSERT_TRUE(p.get() != nullptr);
+
+  DvrNativeBufferMetadata metadata;
+  LocalHandle invalid_fence;
+
+  // Newly created.
+  EXPECT_TRUE(IsBufferGained(p->buffer_state()));
+  EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence));
+  EXPECT_TRUE(IsBufferPosted(p->buffer_state()));
+
+  // The buffer should stay in posted stay until a consumer picks it up.
+  EXPECT_GE(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+
+  // A new consumer should still be able to acquire the buffer immediately.
+  std::unique_ptr<BufferConsumer> c =
+      BufferConsumer::Import(p->CreateConsumer());
+  ASSERT_TRUE(c.get() != nullptr);
+  EXPECT_EQ(0, c->AcquireAsync(&metadata, &invalid_fence));
+  EXPECT_TRUE(IsBufferAcquired(c->buffer_state()));
+}
+
+TEST_F(LibBufferHubTest, TestMaxConsumers) {
+  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+      kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
+  ASSERT_TRUE(p.get() != nullptr);
+
+  std::array<std::unique_ptr<BufferConsumer>, kMaxConsumerCount> cs;
+  for (size_t i = 0; i < kMaxConsumerCount; i++) {
+    cs[i] = BufferConsumer::Import(p->CreateConsumer());
+    ASSERT_TRUE(cs[i].get() != nullptr);
+    EXPECT_TRUE(IsBufferGained(cs[i]->buffer_state()));
+  }
+
+  DvrNativeBufferMetadata metadata;
+  LocalHandle invalid_fence;
+
+  // Post the producer should trigger all consumers to be available.
+  EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence));
+  EXPECT_TRUE(IsBufferPosted(p->buffer_state()));
+  for (size_t i = 0; i < kMaxConsumerCount; i++) {
+    EXPECT_TRUE(
+        IsBufferPosted(cs[i]->buffer_state(), cs[i]->buffer_state_bit()));
+    EXPECT_LT(0, RETRY_EINTR(cs[i]->Poll(kPollTimeoutMs)));
+    EXPECT_EQ(0, cs[i]->AcquireAsync(&metadata, &invalid_fence));
+    EXPECT_TRUE(IsBufferAcquired(p->buffer_state()));
+  }
+
+  // All consumers have to release before the buffer is considered to be
+  // released.
+  for (size_t i = 0; i < kMaxConsumerCount; i++) {
+    EXPECT_FALSE(IsBufferReleased(p->buffer_state()));
+    EXPECT_EQ(0, cs[i]->ReleaseAsync(&metadata, invalid_fence));
+  }
+
+  EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+  EXPECT_TRUE(IsBufferReleased(p->buffer_state()));
+
+  // Buffer state cross all clients must be consistent.
+  for (size_t i = 0; i < kMaxConsumerCount; i++) {
+    EXPECT_EQ(p->buffer_state(), cs[i]->buffer_state());
+  }
+}
+
+TEST_F(LibBufferHubTest, TestCreateConsumerWhenBufferGained) {
+  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+      kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
+  ASSERT_TRUE(p.get() != nullptr);
+  EXPECT_TRUE(IsBufferGained(p->buffer_state()));
+
+  std::unique_ptr<BufferConsumer> c =
+      BufferConsumer::Import(p->CreateConsumer());
+  ASSERT_TRUE(c.get() != nullptr);
+  EXPECT_TRUE(IsBufferGained(c->buffer_state()));
+
+  DvrNativeBufferMetadata metadata;
+  LocalHandle invalid_fence;
+
+  // Post the gained buffer should signal already created consumer.
+  EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence));
+  EXPECT_TRUE(IsBufferPosted(p->buffer_state()));
+  EXPECT_LT(0, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
+  EXPECT_EQ(0, c->AcquireAsync(&metadata, &invalid_fence));
+  EXPECT_TRUE(IsBufferAcquired(c->buffer_state()));
+}
+
+TEST_F(LibBufferHubTest, TestCreateConsumerWhenBufferPosted) {
+  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+      kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
+  ASSERT_TRUE(p.get() != nullptr);
+  EXPECT_TRUE(IsBufferGained(p->buffer_state()));
+
+  DvrNativeBufferMetadata metadata;
+  LocalHandle invalid_fence;
+
+  // Post the gained buffer before any consumer gets created.
+  EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence));
+  EXPECT_TRUE(IsBufferPosted(p->buffer_state()));
+
+  // Newly created consumer should be automatically sigalled.
+  std::unique_ptr<BufferConsumer> c =
+      BufferConsumer::Import(p->CreateConsumer());
+  ASSERT_TRUE(c.get() != nullptr);
+  EXPECT_TRUE(IsBufferPosted(c->buffer_state()));
+  EXPECT_EQ(0, c->AcquireAsync(&metadata, &invalid_fence));
+  EXPECT_TRUE(IsBufferAcquired(c->buffer_state()));
+}
+
+TEST_F(LibBufferHubTest, TestCreateConsumerWhenBufferReleased) {
+  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+      kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
+  ASSERT_TRUE(p.get() != nullptr);
+
+  std::unique_ptr<BufferConsumer> c1 =
+      BufferConsumer::Import(p->CreateConsumer());
+  ASSERT_TRUE(c1.get() != nullptr);
+
+  DvrNativeBufferMetadata metadata;
+  LocalHandle invalid_fence;
+
+  // Post, acquire, and release the buffer..
+  EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence));
+  EXPECT_LT(0, RETRY_EINTR(c1->Poll(kPollTimeoutMs)));
+  EXPECT_EQ(0, c1->AcquireAsync(&metadata, &invalid_fence));
+  EXPECT_EQ(0, c1->ReleaseAsync(&metadata, invalid_fence));
+
+  // Note that the next PDX call is on the producer channel, which may be
+  // executed before Release impulse gets executed by bufferhubd. Thus, here we
+  // need to wait until the releasd is confirmed before creating another
+  // consumer.
+  EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+  EXPECT_TRUE(IsBufferReleased(p->buffer_state()));
+
+  // Create another consumer immediately after the release, should not make the
+  // buffer un-released.
+  std::unique_ptr<BufferConsumer> c2 =
+      BufferConsumer::Import(p->CreateConsumer());
+  ASSERT_TRUE(c2.get() != nullptr);
+
+  EXPECT_TRUE(IsBufferReleased(p->buffer_state()));
+  EXPECT_EQ(0, p->GainAsync(&metadata, &invalid_fence));
+  EXPECT_TRUE(IsBufferGained(p->buffer_state()));
+}
+
+TEST_F(LibBufferHubTest, TestWithCustomMetadata) {
+  struct Metadata {
+    int64_t field1;
+    int64_t field2;
+  };
+  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+      kWidth, kHeight, kFormat, kUsage, sizeof(Metadata));
+  ASSERT_TRUE(p.get() != nullptr);
+  std::unique_ptr<BufferConsumer> c =
+      BufferConsumer::Import(p->CreateConsumer());
+  ASSERT_TRUE(c.get() != nullptr);
+
+  Metadata m = {1, 3};
+  EXPECT_EQ(0, p->Post(LocalHandle(), m));
+  EXPECT_LE(0, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
+
+  LocalHandle fence;
+  Metadata m2 = {};
+  EXPECT_EQ(0, c->Acquire(&fence, &m2));
+  EXPECT_EQ(m.field1, m2.field1);
+  EXPECT_EQ(m.field2, m2.field2);
+
+  EXPECT_EQ(0, c->Release(LocalHandle()));
+  EXPECT_LT(0, RETRY_EINTR(p->Poll(0)));
+}
+
+TEST_F(LibBufferHubTest, TestPostWithWrongMetaSize) {
+  struct Metadata {
+    int64_t field1;
+    int64_t field2;
+  };
+  struct OverSizedMetadata {
+    int64_t field1;
+    int64_t field2;
+    int64_t field3;
+  };
+  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+      kWidth, kHeight, kFormat, kUsage, sizeof(Metadata));
+  ASSERT_TRUE(p.get() != nullptr);
+  std::unique_ptr<BufferConsumer> c =
+      BufferConsumer::Import(p->CreateConsumer());
+  ASSERT_TRUE(c.get() != nullptr);
+
+  // It is illegal to post metadata larger than originally requested during
+  // buffer allocation.
+  OverSizedMetadata evil_meta = {};
+  EXPECT_NE(0, p->Post(LocalHandle(), evil_meta));
+  EXPECT_GE(0, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
+
+  // It is ok to post metadata smaller than originally requested during
+  // buffer allocation.
+  int64_t sequence = 42;
+  EXPECT_EQ(0, p->Post(LocalHandle(), sequence));
+}
+
+TEST_F(LibBufferHubTest, TestAcquireWithWrongMetaSize) {
+  struct Metadata {
+    int64_t field1;
+    int64_t field2;
+  };
+  struct OverSizedMetadata {
+    int64_t field1;
+    int64_t field2;
+    int64_t field3;
+  };
+  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+      kWidth, kHeight, kFormat, kUsage, sizeof(Metadata));
+  ASSERT_TRUE(p.get() != nullptr);
+  std::unique_ptr<BufferConsumer> c =
+      BufferConsumer::Import(p->CreateConsumer());
+  ASSERT_TRUE(c.get() != nullptr);
+
+  Metadata m = {1, 3};
+  EXPECT_EQ(0, p->Post(LocalHandle(), m));
+
+  LocalHandle fence;
+  int64_t sequence;
+  OverSizedMetadata e;
+
+  // It is illegal to acquire metadata larger than originally requested during
+  // buffer allocation.
+  EXPECT_NE(0, c->Acquire(&fence, &e));
+
+  // It is ok to acquire metadata smaller than originally requested during
+  // buffer allocation.
+  EXPECT_EQ(0, c->Acquire(&fence, &sequence));
+  EXPECT_EQ(m.field1, sequence);
+}
+
+TEST_F(LibBufferHubTest, TestAcquireWithNoMeta) {
+  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+      kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
+  ASSERT_TRUE(p.get() != nullptr);
+  std::unique_ptr<BufferConsumer> c =
+      BufferConsumer::Import(p->CreateConsumer());
+  ASSERT_TRUE(c.get() != nullptr);
+
+  int64_t sequence = 3;
+  EXPECT_EQ(0, p->Post(LocalHandle(), sequence));
+
+  LocalHandle fence;
+  EXPECT_EQ(0, c->Acquire(&fence));
+}
+
+TEST_F(LibBufferHubTest, TestWithNoMeta) {
+  std::unique_ptr<BufferProducer> p =
+      BufferProducer::Create(kWidth, kHeight, kFormat, kUsage);
+  ASSERT_TRUE(p.get() != nullptr);
+  std::unique_ptr<BufferConsumer> c =
+      BufferConsumer::Import(p->CreateConsumer());
+  ASSERT_TRUE(c.get() != nullptr);
+
+  LocalHandle fence;
+
+  EXPECT_EQ(0, p->Post<void>(LocalHandle()));
+  EXPECT_EQ(0, c->Acquire(&fence));
+}
+
+TEST_F(LibBufferHubTest, TestFailureToPostMetaFromABufferWithoutMeta) {
+  std::unique_ptr<BufferProducer> p =
+      BufferProducer::Create(kWidth, kHeight, kFormat, kUsage);
+  ASSERT_TRUE(p.get() != nullptr);
+  std::unique_ptr<BufferConsumer> c =
+      BufferConsumer::Import(p->CreateConsumer());
+  ASSERT_TRUE(c.get() != nullptr);
+
+  int64_t sequence = 3;
+  EXPECT_NE(0, p->Post(LocalHandle(), sequence));
+}
+
+namespace {
+
+int PollFd(int fd, int timeout_ms) {
+  pollfd p = {fd, POLLIN, 0};
+  return poll(&p, 1, timeout_ms);
+}
+
+}  // namespace
+
+TEST_F(LibBufferHubTest, TestAcquireFence) {
+  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+      kWidth, kHeight, kFormat, kUsage, /*metadata_size=*/0);
+  ASSERT_TRUE(p.get() != nullptr);
+  std::unique_ptr<BufferConsumer> c =
+      BufferConsumer::Import(p->CreateConsumer());
+  ASSERT_TRUE(c.get() != nullptr);
+
+  DvrNativeBufferMetadata meta;
+  LocalHandle f1(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
+
+  // Post with unsignaled fence.
+  EXPECT_EQ(0, p->PostAsync(&meta, f1));
+
+  // Should acquire a valid fence.
+  LocalHandle f2;
+  EXPECT_LT(0, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
+  EXPECT_EQ(0, c->AcquireAsync(&meta, &f2));
+  EXPECT_TRUE(f2.IsValid());
+  // The original fence and acquired fence should have different fd number.
+  EXPECT_NE(f1.Get(), f2.Get());
+  EXPECT_GE(0, PollFd(f2.Get(), 0));
+
+  // Signal the original fence will trigger the new fence.
+  eventfd_write(f1.Get(), 1);
+  // Now the original FD has been signaled.
+  EXPECT_LT(0, PollFd(f2.Get(), kPollTimeoutMs));
+
+  // Release the consumer with an invalid fence.
+  EXPECT_EQ(0, c->ReleaseAsync(&meta, LocalHandle()));
+
+  // Should gain an invalid fence.
+  LocalHandle f3;
+  EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+  EXPECT_EQ(0, p->GainAsync(&meta, &f3));
+  EXPECT_FALSE(f3.IsValid());
+
+  // Post with a signaled fence.
+  EXPECT_EQ(0, p->PostAsync(&meta, f1));
+
+  // Should acquire a valid fence and it's already signalled.
+  LocalHandle f4;
+  EXPECT_LT(0, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
+  EXPECT_EQ(0, c->AcquireAsync(&meta, &f4));
+  EXPECT_TRUE(f4.IsValid());
+  EXPECT_LT(0, PollFd(f4.Get(), kPollTimeoutMs));
+
+  // Release with an unsignalled fence and signal it immediately after release
+  // without producer gainning.
+  LocalHandle f5(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
+  EXPECT_EQ(0, c->ReleaseAsync(&meta, f5));
+  eventfd_write(f5.Get(), 1);
+
+  // Should gain a valid fence, which is already signaled.
+  LocalHandle f6;
+  EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+  EXPECT_EQ(0, p->GainAsync(&meta, &f6));
+  EXPECT_TRUE(f6.IsValid());
+  EXPECT_LT(0, PollFd(f6.Get(), kPollTimeoutMs));
+}
+
+TEST_F(LibBufferHubTest, TestOrphanedAcquire) {
+  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+      kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
+  ASSERT_TRUE(p.get() != nullptr);
+  std::unique_ptr<BufferConsumer> c1 =
+      BufferConsumer::Import(p->CreateConsumer());
+  ASSERT_TRUE(c1.get() != nullptr);
+  const uint64_t consumer_state_bit1 = c1->buffer_state_bit();
+
+  DvrNativeBufferMetadata meta;
+  EXPECT_EQ(0, p->PostAsync(&meta, LocalHandle()));
+
+  LocalHandle fence;
+  EXPECT_LT(0, RETRY_EINTR(c1->Poll(kPollTimeoutMs)));
+  EXPECT_LE(0, c1->AcquireAsync(&meta, &fence));
+  // Destroy the consumer now will make it orphaned and the buffer is still
+  // acquired.
+  c1 = nullptr;
+  EXPECT_GE(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+
+  std::unique_ptr<BufferConsumer> c2 =
+      BufferConsumer::Import(p->CreateConsumer());
+  ASSERT_TRUE(c2.get() != nullptr);
+  const uint64_t consumer_state_bit2 = c2->buffer_state_bit();
+  EXPECT_NE(consumer_state_bit1, consumer_state_bit2);
+
+  // The new consumer is available for acquire.
+  EXPECT_LT(0, RETRY_EINTR(c2->Poll(kPollTimeoutMs)));
+  EXPECT_LE(0, c2->AcquireAsync(&meta, &fence));
+  // Releasing the consumer makes the buffer gainable.
+  EXPECT_EQ(0, c2->ReleaseAsync(&meta, LocalHandle()));
+
+  // The buffer is now available for the producer to gain.
+  EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+
+  // But if another consumer is created in released state.
+  std::unique_ptr<BufferConsumer> c3 =
+      BufferConsumer::Import(p->CreateConsumer());
+  ASSERT_TRUE(c3.get() != nullptr);
+  const uint64_t consumer_state_bit3 = c3->buffer_state_bit();
+  EXPECT_NE(consumer_state_bit2, consumer_state_bit3);
+  // The consumer buffer is not acquirable.
+  EXPECT_GE(0, RETRY_EINTR(c3->Poll(kPollTimeoutMs)));
+  EXPECT_EQ(-EBUSY, c3->AcquireAsync(&meta, &fence));
+
+  // Producer should be able to gain no matter what.
+  EXPECT_EQ(0, p->GainAsync(&meta, &fence));
+}
+
+TEST_F(LibBufferHubTest, TestDetachBufferFromProducer) {
+  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+      kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
+  std::unique_ptr<BufferConsumer> c =
+      BufferConsumer::Import(p->CreateConsumer());
+  ASSERT_TRUE(p.get() != nullptr);
+  ASSERT_TRUE(c.get() != nullptr);
+
+  DvrNativeBufferMetadata metadata;
+  LocalHandle invalid_fence;
+  int p_id = p->id();
+
+  // Detach in posted state should fail.
+  EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence));
+  EXPECT_GT(RETRY_EINTR(c->Poll(kPollTimeoutMs)), 0);
+  auto s1 = p->Detach();
+  EXPECT_FALSE(s1);
+
+  // Detach in acquired state should fail.
+  EXPECT_EQ(0, c->AcquireAsync(&metadata, &invalid_fence));
+  s1 = p->Detach();
+  EXPECT_FALSE(s1);
+
+  // Detach in released state should fail.
+  EXPECT_EQ(0, c->ReleaseAsync(&metadata, invalid_fence));
+  EXPECT_GT(RETRY_EINTR(p->Poll(kPollTimeoutMs)), 0);
+  s1 = p->Detach();
+  EXPECT_FALSE(s1);
+
+  // Detach in gained state should succeed.
+  EXPECT_EQ(0, p->GainAsync(&metadata, &invalid_fence));
+  s1 = p->Detach();
+  EXPECT_TRUE(s1);
+
+  LocalChannelHandle handle = s1.take();
+  EXPECT_TRUE(handle.valid());
+
+  // Both producer and consumer should have hangup.
+  EXPECT_GT(RETRY_EINTR(p->Poll(kPollTimeoutMs)), 0);
+  auto s2 = p->GetEventMask(POLLHUP);
+  EXPECT_TRUE(s2);
+  EXPECT_EQ(s2.get(), POLLHUP);
+
+  EXPECT_GT(RETRY_EINTR(c->Poll(kPollTimeoutMs)), 0);
+  s2 = p->GetEventMask(POLLHUP);
+  EXPECT_TRUE(s2);
+  EXPECT_EQ(s2.get(), POLLHUP);
+
+  auto s3 = p->CreateConsumer();
+  EXPECT_FALSE(s3);
+  // Note that here the expected error code is EOPNOTSUPP as the socket towards
+  // ProducerChannel has been teared down.
+  EXPECT_EQ(s3.error(), EOPNOTSUPP);
+
+  s3 = c->CreateConsumer();
+  EXPECT_FALSE(s3);
+  // Note that here the expected error code is EPIPE returned from
+  // ConsumerChannel::HandleMessage as the socket is still open but the producer
+  // is gone.
+  EXPECT_EQ(s3.error(), EPIPE);
+
+  // Detached buffer handle can be use to construct a new DetachedBuffer object.
+  auto d = DetachedBuffer::Import(std::move(handle));
+  EXPECT_FALSE(handle.valid());
+  EXPECT_TRUE(d->IsConnected());
+  EXPECT_TRUE(d->IsValid());
+
+  ASSERT_TRUE(d->buffer() != nullptr);
+  EXPECT_EQ(d->buffer()->initCheck(), 0);
+  EXPECT_EQ(d->id(), p_id);
+}
+
+TEST_F(LibBufferHubTest, TestCreateDetachedBufferFails) {
+  // Buffer Creation will fail: BLOB format requires height to be 1.
+  auto b1 = DetachedBuffer::Create(kWidth, /*height=2*/ 2, kLayerCount,
+                                   /*format=*/HAL_PIXEL_FORMAT_BLOB, kUsage,
+                                   kUserMetadataSize);
+
+  EXPECT_FALSE(b1->IsConnected());
+  EXPECT_FALSE(b1->IsValid());
+  EXPECT_TRUE(b1->buffer() == nullptr);
+
+  // Buffer Creation will fail: user metadata size too large.
+  auto b2 = DetachedBuffer::Create(
+      kWidth, kHeight, kLayerCount, kFormat, kUsage,
+      /*user_metadata_size=*/std::numeric_limits<size_t>::max());
+
+  EXPECT_FALSE(b2->IsConnected());
+  EXPECT_FALSE(b2->IsValid());
+  EXPECT_TRUE(b2->buffer() == nullptr);
+
+  // Buffer Creation will fail: user metadata size too large.
+  auto b3 = DetachedBuffer::Create(
+      kWidth, kHeight, kLayerCount, kFormat, kUsage,
+      /*user_metadata_size=*/std::numeric_limits<size_t>::max() -
+          kMetadataHeaderSize);
+
+  EXPECT_FALSE(b3->IsConnected());
+  EXPECT_FALSE(b3->IsValid());
+  EXPECT_TRUE(b3->buffer() == nullptr);
+}
+
+TEST_F(LibBufferHubTest, TestCreateDetachedBuffer) {
+  auto b1 = DetachedBuffer::Create(kWidth, kHeight, kLayerCount, kFormat,
+                                   kUsage, kUserMetadataSize);
+  int b1_id = b1->id();
+
+  EXPECT_TRUE(b1->IsConnected());
+  EXPECT_TRUE(b1->IsValid());
+  ASSERT_TRUE(b1->buffer() != nullptr);
+  EXPECT_NE(b1->id(), 0);
+  EXPECT_EQ(b1->buffer()->initCheck(), 0);
+  EXPECT_FALSE(b1->buffer()->isDetachedBuffer());
+
+  // Takes a standalone GraphicBuffer which still holds on an
+  // PDX::LocalChannelHandle towards BufferHub.
+  sp<GraphicBuffer> g1 = b1->TakeGraphicBuffer();
+  ASSERT_TRUE(g1 != nullptr);
+  EXPECT_TRUE(g1->isDetachedBuffer());
+
+  EXPECT_FALSE(b1->IsConnected());
+  EXPECT_FALSE(b1->IsValid());
+  EXPECT_TRUE(b1->buffer() == nullptr);
+
+  sp<GraphicBuffer> g2 = b1->TakeGraphicBuffer();
+  ASSERT_TRUE(g2 == nullptr);
+
+  auto h1 = g1->takeDetachedBufferHandle();
+  ASSERT_TRUE(h1 != nullptr);
+  ASSERT_TRUE(h1->isValid());
+  EXPECT_FALSE(g1->isDetachedBuffer());
+
+  auto b2 = DetachedBuffer::Import(std::move(h1->handle()));
+  ASSERT_FALSE(h1->isValid());
+  EXPECT_TRUE(b2->IsConnected());
+  EXPECT_TRUE(b2->IsValid());
+
+  ASSERT_TRUE(b2->buffer() != nullptr);
+  EXPECT_EQ(b2->buffer()->initCheck(), 0);
+
+  // The newly created DetachedBuffer should share the original buffer_id.
+  EXPECT_EQ(b2->id(), b1_id);
+  EXPECT_FALSE(b2->buffer()->isDetachedBuffer());
+}
+
+TEST_F(LibBufferHubTest, TestPromoteDetachedBuffer) {
+  auto b1 = DetachedBuffer::Create(kWidth, kHeight, kLayerCount, kFormat,
+                                   kUsage, kUserMetadataSize);
+  int b1_id = b1->id();
+  EXPECT_TRUE(b1->IsValid());
+
+  auto status_or_handle = b1->Promote();
+  EXPECT_TRUE(status_or_handle);
+
+  // The detached buffer should have hangup.
+  EXPECT_GT(RETRY_EINTR(b1->Poll(kPollTimeoutMs)), 0);
+  auto status_or_int = b1->GetEventMask(POLLHUP);
+  EXPECT_TRUE(status_or_int.ok());
+  EXPECT_EQ(status_or_int.get(), POLLHUP);
+
+  // The buffer client is still considered as connected but invalid.
+  EXPECT_TRUE(b1->IsConnected());
+  EXPECT_FALSE(b1->IsValid());
+
+  // Gets the channel handle for the producer.
+  LocalChannelHandle h1 = status_or_handle.take();
+  EXPECT_TRUE(h1.valid());
+
+  std::unique_ptr<BufferProducer> p1 = BufferProducer::Import(std::move(h1));
+  EXPECT_FALSE(h1.valid());
+  ASSERT_TRUE(p1 != nullptr);
+  int p1_id = p1->id();
+
+  // A newly promoted ProducerBuffer should inherit the same buffer id.
+  EXPECT_EQ(b1_id, p1_id);
+  EXPECT_TRUE(IsBufferGained(p1->buffer_state()));
+}
+
+TEST_F(LibBufferHubTest, TestDetachThenPromote) {
+  std::unique_ptr<BufferProducer> p1 = BufferProducer::Create(
+      kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
+  ASSERT_TRUE(p1.get() != nullptr);
+  int p1_id = p1->id();
+
+  // Detached the producer.
+  auto status_or_handle = p1->Detach();
+  EXPECT_TRUE(status_or_handle.ok());
+  LocalChannelHandle h1 = status_or_handle.take();
+  EXPECT_TRUE(h1.valid());
+
+  // Detached buffer handle can be use to construct a new DetachedBuffer object.
+  auto b1 = DetachedBuffer::Import(std::move(h1));
+  EXPECT_FALSE(h1.valid());
+  EXPECT_TRUE(b1->IsValid());
+  int b1_id = b1->id();
+  EXPECT_EQ(b1_id, p1_id);
+
+  // Promote the detached buffer.
+  status_or_handle = b1->Promote();
+  // The buffer client is still considered as connected but invalid.
+  EXPECT_TRUE(b1->IsConnected());
+  EXPECT_FALSE(b1->IsValid());
+  EXPECT_TRUE(status_or_handle.ok());
+
+  // Gets the channel handle for the producer.
+  LocalChannelHandle h2 = status_or_handle.take();
+  EXPECT_TRUE(h2.valid());
+
+  std::unique_ptr<BufferProducer> p2 = BufferProducer::Import(std::move(h2));
+  EXPECT_FALSE(h2.valid());
+  ASSERT_TRUE(p2 != nullptr);
+  int p2_id = p2->id();
+
+  // A newly promoted ProducerBuffer should inherit the same buffer id.
+  EXPECT_EQ(b1_id, p2_id);
+  EXPECT_TRUE(IsBufferGained(p2->buffer_state()));
+}
diff --git a/libs/vr/libbufferhub/buffer_hub_client.cpp b/libs/vr/libbufferhub/buffer_hub_client.cpp
index 97341b1..159f2bd 100644
--- a/libs/vr/libbufferhub/buffer_hub_client.cpp
+++ b/libs/vr/libbufferhub/buffer_hub_client.cpp
@@ -15,10 +15,30 @@
 using android::pdx::LocalChannelHandle;
 using android::pdx::LocalHandle;
 using android::pdx::Status;
+using android::pdx::default_transport::ClientChannel;
+using android::pdx::default_transport::ClientChannelFactory;
 
 namespace android {
 namespace dvr {
 
+BufferHubClient::BufferHubClient()
+    : Client(ClientChannelFactory::Create(BufferHubRPC::kClientPath)) {}
+
+BufferHubClient::BufferHubClient(LocalChannelHandle channel_handle)
+    : Client(ClientChannel::Create(std::move(channel_handle))) {}
+
+bool BufferHubClient::IsValid() const {
+  return IsConnected() && GetChannelHandle().valid();
+}
+
+LocalChannelHandle BufferHubClient::TakeChannelHandle() {
+  if (IsConnected()) {
+    return std::move(GetChannelHandle());
+  } else {
+    return {};
+  }
+}
+
 BufferHubBuffer::BufferHubBuffer(LocalChannelHandle channel_handle)
     : Client{pdx::default_transport::ClientChannel::Create(
           std::move(channel_handle))},
@@ -395,25 +415,16 @@
 }
 
 BufferProducer::BufferProducer(uint32_t width, uint32_t height, uint32_t format,
-                               uint32_t usage, size_t user_metadata_size)
-    : BufferProducer(width, height, format, usage, usage, user_metadata_size) {}
-
-BufferProducer::BufferProducer(uint32_t width, uint32_t height, uint32_t format,
-                               uint64_t producer_usage, uint64_t consumer_usage,
-                               size_t user_metadata_size)
+                               uint64_t usage, size_t user_metadata_size)
     : BASE(BufferHubRPC::kClientPath) {
   ATRACE_NAME("BufferProducer::BufferProducer");
   ALOGD_IF(TRACE,
            "BufferProducer::BufferProducer: fd=%d width=%u height=%u format=%u "
-           "producer_usage=%" PRIx64 " consumer_usage=%" PRIx64
-           " user_metadata_size=%zu",
-           event_fd(), width, height, format, producer_usage, consumer_usage,
-           user_metadata_size);
+           "usage=%" PRIx64 " user_metadata_size=%zu",
+           event_fd(), width, height, format, usage, user_metadata_size);
 
-  // (b/37881101) Deprecate producer/consumer usage
   auto status = InvokeRemoteMethod<BufferHubRPC::CreateBuffer>(
-      width, height, format, (producer_usage | consumer_usage),
-      user_metadata_size);
+      width, height, format, usage, user_metadata_size);
   if (!status) {
     ALOGE(
         "BufferProducer::BufferProducer: Failed to create producer buffer: %s",
@@ -431,70 +442,18 @@
   }
 }
 
-BufferProducer::BufferProducer(const std::string& name, int user_id,
-                               int group_id, uint32_t width, uint32_t height,
-                               uint32_t format, uint32_t usage,
-                               size_t user_metadata_size)
-    : BufferProducer(name, user_id, group_id, width, height, format, usage,
-                     usage, user_metadata_size) {}
-
-BufferProducer::BufferProducer(const std::string& name, int user_id,
-                               int group_id, uint32_t width, uint32_t height,
-                               uint32_t format, uint64_t producer_usage,
-                               uint64_t consumer_usage,
-                               size_t user_metadata_size)
+BufferProducer::BufferProducer(uint64_t usage, size_t size)
     : BASE(BufferHubRPC::kClientPath) {
   ATRACE_NAME("BufferProducer::BufferProducer");
-  ALOGD_IF(TRACE,
-           "BufferProducer::BufferProducer: fd=%d name=%s user_id=%d "
-           "group_id=%d width=%u height=%u format=%u producer_usage=%" PRIx64
-           " consumer_usage=%" PRIx64 " user_metadata_size=%zu",
-           event_fd(), name.c_str(), user_id, group_id, width, height, format,
-           producer_usage, consumer_usage, user_metadata_size);
-
-  // (b/37881101) Deprecate producer/consumer usage
-  auto status = InvokeRemoteMethod<BufferHubRPC::CreatePersistentBuffer>(
-      name, user_id, group_id, width, height, format,
-      (producer_usage | consumer_usage), user_metadata_size);
-  if (!status) {
-    ALOGE(
-        "BufferProducer::BufferProducer: Failed to create/get persistent "
-        "buffer \"%s\": %s",
-        name.c_str(), status.GetErrorMessage().c_str());
-    Close(-status.error());
-    return;
-  }
-
-  const int ret = ImportBuffer();
-  if (ret < 0) {
-    ALOGE(
-        "BufferProducer::BufferProducer: Failed to import producer buffer "
-        "\"%s\": %s",
-        name.c_str(), strerror(-ret));
-    Close(ret);
-  }
-}
-
-BufferProducer::BufferProducer(uint32_t usage, size_t size)
-    : BufferProducer(usage, usage, size) {}
-
-BufferProducer::BufferProducer(uint64_t producer_usage, uint64_t consumer_usage,
-                               size_t size)
-    : BASE(BufferHubRPC::kClientPath) {
-  ATRACE_NAME("BufferProducer::BufferProducer");
-  ALOGD_IF(TRACE,
-           "BufferProducer::BufferProducer: producer_usage=%" PRIx64
-           " consumer_usage=%" PRIx64 " size=%zu",
-           producer_usage, consumer_usage, size);
+  ALOGD_IF(TRACE, "BufferProducer::BufferProducer: usage=%" PRIx64 " size=%zu",
+           usage, size);
   const int width = static_cast<int>(size);
   const int height = 1;
   const int format = HAL_PIXEL_FORMAT_BLOB;
   const size_t user_metadata_size = 0;
 
-  // (b/37881101) Deprecate producer/consumer usage
   auto status = InvokeRemoteMethod<BufferHubRPC::CreateBuffer>(
-      width, height, format, (producer_usage | consumer_usage),
-      user_metadata_size);
+      width, height, format, usage, user_metadata_size);
   if (!status) {
     ALOGE("BufferProducer::BufferProducer: Failed to create blob: %s",
           status.GetErrorMessage().c_str());
@@ -511,73 +470,6 @@
   }
 }
 
-BufferProducer::BufferProducer(const std::string& name, int user_id,
-                               int group_id, uint32_t usage, size_t size)
-    : BufferProducer(name, user_id, group_id, usage, usage, size) {}
-
-BufferProducer::BufferProducer(const std::string& name, int user_id,
-                               int group_id, uint64_t producer_usage,
-                               uint64_t consumer_usage, size_t size)
-    : BASE(BufferHubRPC::kClientPath) {
-  ATRACE_NAME("BufferProducer::BufferProducer");
-  ALOGD_IF(TRACE,
-           "BufferProducer::BufferProducer: name=%s user_id=%d group=%d "
-           "producer_usage=%" PRIx64 " consumer_usage=%" PRIx64 " size=%zu",
-           name.c_str(), user_id, group_id, producer_usage, consumer_usage,
-           size);
-  const int width = static_cast<int>(size);
-  const int height = 1;
-  const int format = HAL_PIXEL_FORMAT_BLOB;
-  const size_t user_metadata_size = 0;
-
-  // (b/37881101) Deprecate producer/consumer usage
-  auto status = InvokeRemoteMethod<BufferHubRPC::CreatePersistentBuffer>(
-      name, user_id, group_id, width, height, format,
-      (producer_usage | consumer_usage), user_metadata_size);
-  if (!status) {
-    ALOGE(
-        "BufferProducer::BufferProducer: Failed to create persistent "
-        "buffer \"%s\": %s",
-        name.c_str(), status.GetErrorMessage().c_str());
-    Close(-status.error());
-    return;
-  }
-
-  const int ret = ImportBuffer();
-  if (ret < 0) {
-    ALOGE(
-        "BufferProducer::BufferProducer: Failed to import producer buffer "
-        "\"%s\": %s",
-        name.c_str(), strerror(-ret));
-    Close(ret);
-  }
-}
-
-BufferProducer::BufferProducer(const std::string& name)
-    : BASE(BufferHubRPC::kClientPath) {
-  ATRACE_NAME("BufferProducer::BufferProducer");
-  ALOGD_IF(TRACE, "BufferProducer::BufferProducer: name=%s", name.c_str());
-
-  auto status = InvokeRemoteMethod<BufferHubRPC::GetPersistentBuffer>(name);
-  if (!status) {
-    ALOGE(
-        "BufferProducer::BufferProducer: Failed to get producer buffer by name "
-        "\"%s\": %s",
-        name.c_str(), status.GetErrorMessage().c_str());
-    Close(-status.error());
-    return;
-  }
-
-  const int ret = ImportBuffer();
-  if (ret < 0) {
-    ALOGE(
-        "BufferProducer::BufferProducer: Failed to import producer buffer "
-        "\"%s\": %s",
-        name.c_str(), strerror(-ret));
-    Close(ret);
-  }
-}
-
 BufferProducer::BufferProducer(LocalChannelHandle channel)
     : BASE(std::move(channel)) {
   const int ret = ImportBuffer();
@@ -736,18 +628,22 @@
                        : LocalChannelHandle{nullptr, -status.error()});
 }
 
-int BufferProducer::MakePersistent(const std::string& name, int user_id,
-                                   int group_id) {
-  ATRACE_NAME("BufferProducer::MakePersistent");
-  return ReturnStatusOrError(
-      InvokeRemoteMethod<BufferHubRPC::ProducerMakePersistent>(name, user_id,
-                                                               group_id));
-}
+Status<LocalChannelHandle> BufferProducer::Detach() {
+  uint64_t buffer_state = buffer_state_->load();
+  if (!BufferHubDefs::IsBufferGained(buffer_state)) {
+    // Can only detach a BufferProducer when it's in gained state.
+    ALOGW("BufferProducer::Detach: The buffer (id=%d, state=0x%" PRIx64
+          ") is not in gained state.",
+          id(), buffer_state);
+    return {};
+  }
 
-int BufferProducer::RemovePersistence() {
-  ATRACE_NAME("BufferProducer::RemovePersistence");
-  return ReturnStatusOrError(
-      InvokeRemoteMethod<BufferHubRPC::ProducerRemovePersistence>());
+  Status<LocalChannelHandle> status =
+      InvokeRemoteMethod<BufferHubRPC::ProducerBufferDetach>();
+  ALOGE_IF(!status,
+           "BufferProducer::Detach: Failed to detach buffer (id=%d): %s.", id(),
+           status.GetErrorMessage().c_str());
+  return status;
 }
 
 }  // namespace dvr
diff --git a/libs/vr/libbufferhub/bufferhub_tests.cpp b/libs/vr/libbufferhub/bufferhub_tests.cpp
deleted file mode 100644
index d0d3a73..0000000
--- a/libs/vr/libbufferhub/bufferhub_tests.cpp
+++ /dev/null
@@ -1,558 +0,0 @@
-#include <gtest/gtest.h>
-#include <poll.h>
-#include <private/dvr/buffer_hub_client.h>
-#include <private/dvr/bufferhub_rpc.h>
-#include <sys/epoll.h>
-#include <sys/eventfd.h>
-
-#include <mutex>
-#include <thread>
-
-#define RETRY_EINTR(fnc_call)                 \
-  ([&]() -> decltype(fnc_call) {              \
-    decltype(fnc_call) result;                \
-    do {                                      \
-      result = (fnc_call);                    \
-    } while (result == -1 && errno == EINTR); \
-    return result;                            \
-  })()
-
-using android::dvr::BufferConsumer;
-using android::dvr::BufferHubDefs::kConsumerStateMask;
-using android::dvr::BufferHubDefs::kProducerStateBit;
-using android::dvr::BufferProducer;
-using android::pdx::LocalHandle;
-
-const int kWidth = 640;
-const int kHeight = 480;
-const int kFormat = HAL_PIXEL_FORMAT_RGBA_8888;
-const int kUsage = 0;
-const uint64_t kContext = 42;
-
-using LibBufferHubTest = ::testing::Test;
-
-TEST_F(LibBufferHubTest, TestBasicUsage) {
-  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
-      kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
-  ASSERT_TRUE(p.get() != nullptr);
-  std::unique_ptr<BufferConsumer> c =
-      BufferConsumer::Import(p->CreateConsumer());
-  ASSERT_TRUE(c.get() != nullptr);
-  // Check that consumers can spawn other consumers.
-  std::unique_ptr<BufferConsumer> c2 =
-      BufferConsumer::Import(c->CreateConsumer());
-  ASSERT_TRUE(c2.get() != nullptr);
-
-  // Producer state mask is unique, i.e. 1.
-  EXPECT_EQ(p->buffer_state_bit(), kProducerStateBit);
-  // Consumer state mask cannot have producer bit on.
-  EXPECT_EQ(c->buffer_state_bit() & kProducerStateBit, 0ULL);
-  // Consumer state mask must be a single, i.e. power of 2.
-  EXPECT_NE(c->buffer_state_bit(), 0ULL);
-  EXPECT_EQ(c->buffer_state_bit() & (c->buffer_state_bit() - 1), 0ULL);
-  // Consumer state mask cannot have producer bit on.
-  EXPECT_EQ(c2->buffer_state_bit() & kProducerStateBit, 0ULL);
-  // Consumer state mask must be a single, i.e. power of 2.
-  EXPECT_NE(c2->buffer_state_bit(), 0ULL);
-  EXPECT_EQ(c2->buffer_state_bit() & (c2->buffer_state_bit() - 1), 0ULL);
-  // Each consumer should have unique bit.
-  EXPECT_EQ(c->buffer_state_bit() & c2->buffer_state_bit(), 0ULL);
-
-  // Initial state: producer not available, consumers not available.
-  EXPECT_EQ(0, RETRY_EINTR(p->Poll(100)));
-  EXPECT_EQ(0, RETRY_EINTR(c->Poll(100)));
-  EXPECT_EQ(0, RETRY_EINTR(c2->Poll(100)));
-
-  EXPECT_EQ(0, p->Post(LocalHandle(), kContext));
-
-  // New state: producer not available, consumers available.
-  EXPECT_EQ(0, RETRY_EINTR(p->Poll(100)));
-  EXPECT_EQ(1, RETRY_EINTR(c->Poll(100)));
-  EXPECT_EQ(1, RETRY_EINTR(c2->Poll(100)));
-
-  uint64_t context;
-  LocalHandle fence;
-  EXPECT_EQ(0, c->Acquire(&fence, &context));
-  EXPECT_EQ(kContext, context);
-  EXPECT_EQ(0, RETRY_EINTR(c->Poll(100)));
-  EXPECT_EQ(1, RETRY_EINTR(c2->Poll(100)));
-
-  EXPECT_EQ(0, c2->Acquire(&fence, &context));
-  EXPECT_EQ(kContext, context);
-  EXPECT_EQ(0, RETRY_EINTR(c2->Poll(100)));
-  EXPECT_EQ(0, RETRY_EINTR(c->Poll(100)));
-
-  EXPECT_EQ(0, c->Release(LocalHandle()));
-  EXPECT_EQ(0, RETRY_EINTR(p->Poll(100)));
-  EXPECT_EQ(0, c2->Discard());
-
-  EXPECT_EQ(1, RETRY_EINTR(p->Poll(100)));
-  EXPECT_EQ(0, p->Gain(&fence));
-  EXPECT_EQ(0, RETRY_EINTR(p->Poll(100)));
-  EXPECT_EQ(0, RETRY_EINTR(c->Poll(100)));
-  EXPECT_EQ(0, RETRY_EINTR(c2->Poll(100)));
-}
-
-TEST_F(LibBufferHubTest, TestEpoll) {
-  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
-      kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
-  ASSERT_TRUE(p.get() != nullptr);
-  std::unique_ptr<BufferConsumer> c =
-      BufferConsumer::Import(p->CreateConsumer());
-  ASSERT_TRUE(c.get() != nullptr);
-
-  LocalHandle epoll_fd{epoll_create1(EPOLL_CLOEXEC)};
-  ASSERT_TRUE(epoll_fd.IsValid());
-
-  epoll_event event;
-  std::array<epoll_event, 64> events;
-
-  auto event_sources = p->GetEventSources();
-  ASSERT_LT(event_sources.size(), events.size());
-
-  for (const auto& event_source : event_sources) {
-    event = {.events = event_source.event_mask | EPOLLET,
-             .data = {.fd = p->event_fd()}};
-    ASSERT_EQ(0, epoll_ctl(epoll_fd.Get(), EPOLL_CTL_ADD, event_source.event_fd,
-                           &event));
-  }
-
-  event_sources = c->GetEventSources();
-  ASSERT_LT(event_sources.size(), events.size());
-
-  for (const auto& event_source : event_sources) {
-    event = {.events = event_source.event_mask | EPOLLET,
-             .data = {.fd = c->event_fd()}};
-    ASSERT_EQ(0, epoll_ctl(epoll_fd.Get(), EPOLL_CTL_ADD, event_source.event_fd,
-                           &event));
-  }
-
-  // No events should be signaled initially.
-  ASSERT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(), 0));
-
-  // Post the producer and check for consumer signal.
-  EXPECT_EQ(0, p->Post({}, kContext));
-  ASSERT_EQ(1, epoll_wait(epoll_fd.Get(), events.data(), events.size(), 100));
-  ASSERT_TRUE(events[0].events & EPOLLIN);
-  ASSERT_EQ(c->event_fd(), events[0].data.fd);
-
-  // Save the event bits to translate later.
-  event = events[0];
-
-  // Check for events again. Edge-triggered mode should prevent any.
-  EXPECT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(), 100));
-  EXPECT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(), 100));
-  EXPECT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(), 100));
-  EXPECT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(), 100));
-
-  // Translate the events.
-  auto event_status = c->GetEventMask(event.events);
-  ASSERT_TRUE(event_status);
-  ASSERT_TRUE(event_status.get() & EPOLLIN);
-
-  // Check for events again. Edge-triggered mode should prevent any.
-  EXPECT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(), 100));
-}
-
-TEST_F(LibBufferHubTest, TestStateMask) {
-  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
-      kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
-  ASSERT_TRUE(p.get() != nullptr);
-
-  // It's ok to create up to 63 consumer buffers.
-  uint64_t buffer_state_bits = p->buffer_state_bit();
-  std::array<std::unique_ptr<BufferConsumer>, 63> cs;
-  for (size_t i = 0; i < 63; i++) {
-    cs[i] = BufferConsumer::Import(p->CreateConsumer());
-    ASSERT_TRUE(cs[i].get() != nullptr);
-    // Expect all buffers have unique state mask.
-    EXPECT_EQ(buffer_state_bits & cs[i]->buffer_state_bit(), 0ULL);
-    buffer_state_bits |= cs[i]->buffer_state_bit();
-  }
-  EXPECT_EQ(buffer_state_bits, kProducerStateBit | kConsumerStateMask);
-
-  // The 64th creation will fail with out-of-memory error.
-  auto state = p->CreateConsumer();
-  EXPECT_EQ(state.error(), E2BIG);
-
-  // Release any consumer should allow us to re-create.
-  for (size_t i = 0; i < 63; i++) {
-    buffer_state_bits &= ~cs[i]->buffer_state_bit();
-    cs[i] = nullptr;
-    cs[i] = BufferConsumer::Import(p->CreateConsumer());
-    ASSERT_TRUE(cs[i].get() != nullptr);
-    // The released state mask will be reused.
-    EXPECT_EQ(buffer_state_bits & cs[i]->buffer_state_bit(), 0ULL);
-    buffer_state_bits |= cs[i]->buffer_state_bit();
-    EXPECT_EQ(buffer_state_bits, kProducerStateBit | kConsumerStateMask);
-  }
-}
-
-TEST_F(LibBufferHubTest, TestStateTransitions) {
-  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
-      kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
-  ASSERT_TRUE(p.get() != nullptr);
-  std::unique_ptr<BufferConsumer> c =
-      BufferConsumer::Import(p->CreateConsumer());
-  ASSERT_TRUE(c.get() != nullptr);
-
-  uint64_t context;
-  LocalHandle fence;
-
-  // The producer buffer starts in gained state.
-
-  // Acquire, release, and gain in gained state should fail.
-  EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context));
-  EXPECT_EQ(-EBUSY, c->Release(LocalHandle()));
-  EXPECT_EQ(-EALREADY, p->Gain(&fence));
-
-  // Post in gained state should succeed.
-  EXPECT_EQ(0, p->Post(LocalHandle(), kContext));
-
-  // Post, release, and gain in posted state should fail.
-  EXPECT_EQ(-EBUSY, p->Post(LocalHandle(), kContext));
-  EXPECT_EQ(-EBUSY, c->Release(LocalHandle()));
-  EXPECT_EQ(-EBUSY, p->Gain(&fence));
-
-  // Acquire in posted state should succeed.
-  EXPECT_LE(0, c->Acquire(&fence, &context));
-
-  // Acquire, post, and gain in acquired state should fail.
-  EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context));
-  EXPECT_EQ(-EBUSY, p->Post(LocalHandle(), kContext));
-  EXPECT_EQ(-EBUSY, p->Gain(&fence));
-
-  // Release in acquired state should succeed.
-  EXPECT_EQ(0, c->Release(LocalHandle()));
-  EXPECT_LT(0, RETRY_EINTR(p->Poll(10)));
-
-  // Release, acquire, and post in released state should fail.
-  EXPECT_EQ(-EBUSY, c->Release(LocalHandle()));
-  EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context));
-  EXPECT_EQ(-EBUSY, p->Post(LocalHandle(), kContext));
-
-  // Gain in released state should succeed.
-  EXPECT_EQ(0, p->Gain(&fence));
-
-  // Acquire, release, and gain in gained state should fail.
-  EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context));
-  EXPECT_EQ(-EBUSY, c->Release(LocalHandle()));
-  EXPECT_EQ(-EALREADY, p->Gain(&fence));
-}
-
-TEST_F(LibBufferHubTest, TestWithCustomMetadata) {
-  struct Metadata {
-    int64_t field1;
-    int64_t field2;
-  };
-  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
-      kWidth, kHeight, kFormat, kUsage, sizeof(Metadata));
-  ASSERT_TRUE(p.get() != nullptr);
-  std::unique_ptr<BufferConsumer> c =
-      BufferConsumer::Import(p->CreateConsumer());
-  ASSERT_TRUE(c.get() != nullptr);
-
-  Metadata m = {1, 3};
-  EXPECT_EQ(0, p->Post(LocalHandle(), m));
-  EXPECT_LE(0, RETRY_EINTR(c->Poll(10)));
-
-  LocalHandle fence;
-  Metadata m2 = {};
-  EXPECT_EQ(0, c->Acquire(&fence, &m2));
-  EXPECT_EQ(m.field1, m2.field1);
-  EXPECT_EQ(m.field2, m2.field2);
-
-  EXPECT_EQ(0, c->Release(LocalHandle()));
-  EXPECT_LT(0, RETRY_EINTR(p->Poll(0)));
-}
-
-TEST_F(LibBufferHubTest, TestPostWithWrongMetaSize) {
-  struct Metadata {
-    int64_t field1;
-    int64_t field2;
-  };
-  struct OverSizedMetadata {
-    int64_t field1;
-    int64_t field2;
-    int64_t field3;
-  };
-  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
-      kWidth, kHeight, kFormat, kUsage, sizeof(Metadata));
-  ASSERT_TRUE(p.get() != nullptr);
-  std::unique_ptr<BufferConsumer> c =
-      BufferConsumer::Import(p->CreateConsumer());
-  ASSERT_TRUE(c.get() != nullptr);
-
-  // It is illegal to post metadata larger than originally requested during
-  // buffer allocation.
-  OverSizedMetadata evil_meta = {};
-  EXPECT_NE(0, p->Post(LocalHandle(), evil_meta));
-  EXPECT_GE(0, RETRY_EINTR(c->Poll(10)));
-
-  // It is ok to post metadata smaller than originally requested during
-  // buffer allocation.
-  int64_t sequence = 42;
-  EXPECT_EQ(0, p->Post(LocalHandle(), sequence));
-}
-
-TEST_F(LibBufferHubTest, TestAcquireWithWrongMetaSize) {
-  struct Metadata {
-    int64_t field1;
-    int64_t field2;
-  };
-  struct OverSizedMetadata {
-    int64_t field1;
-    int64_t field2;
-    int64_t field3;
-  };
-  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
-      kWidth, kHeight, kFormat, kUsage, sizeof(Metadata));
-  ASSERT_TRUE(p.get() != nullptr);
-  std::unique_ptr<BufferConsumer> c =
-      BufferConsumer::Import(p->CreateConsumer());
-  ASSERT_TRUE(c.get() != nullptr);
-
-  Metadata m = {1, 3};
-  EXPECT_EQ(0, p->Post(LocalHandle(), m));
-
-  LocalHandle fence;
-  int64_t sequence;
-  OverSizedMetadata e;
-
-  // It is illegal to acquire metadata larger than originally requested during
-  // buffer allocation.
-  EXPECT_NE(0, c->Acquire(&fence, &e));
-
-  // It is ok to acquire metadata smaller than originally requested during
-  // buffer allocation.
-  EXPECT_EQ(0, c->Acquire(&fence, &sequence));
-  EXPECT_EQ(m.field1, sequence);
-}
-
-TEST_F(LibBufferHubTest, TestAcquireWithNoMeta) {
-  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
-      kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
-  ASSERT_TRUE(p.get() != nullptr);
-  std::unique_ptr<BufferConsumer> c =
-      BufferConsumer::Import(p->CreateConsumer());
-  ASSERT_TRUE(c.get() != nullptr);
-
-  int64_t sequence = 3;
-  EXPECT_EQ(0, p->Post(LocalHandle(), sequence));
-
-  LocalHandle fence;
-  EXPECT_EQ(0, c->Acquire(&fence));
-}
-
-TEST_F(LibBufferHubTest, TestWithNoMeta) {
-  std::unique_ptr<BufferProducer> p =
-      BufferProducer::Create(kWidth, kHeight, kFormat, kUsage);
-  ASSERT_TRUE(p.get() != nullptr);
-  std::unique_ptr<BufferConsumer> c =
-      BufferConsumer::Import(p->CreateConsumer());
-  ASSERT_TRUE(c.get() != nullptr);
-
-  LocalHandle fence;
-
-  EXPECT_EQ(0, p->Post<void>(LocalHandle()));
-  EXPECT_EQ(0, c->Acquire(&fence));
-}
-
-TEST_F(LibBufferHubTest, TestFailureToPostMetaFromABufferWithoutMeta) {
-  std::unique_ptr<BufferProducer> p =
-      BufferProducer::Create(kWidth, kHeight, kFormat, kUsage);
-  ASSERT_TRUE(p.get() != nullptr);
-  std::unique_ptr<BufferConsumer> c =
-      BufferConsumer::Import(p->CreateConsumer());
-  ASSERT_TRUE(c.get() != nullptr);
-
-  int64_t sequence = 3;
-  EXPECT_NE(0, p->Post(LocalHandle(), sequence));
-}
-
-TEST_F(LibBufferHubTest, TestPersistentBufferPersistence) {
-  auto p = BufferProducer::Create("TestPersistentBuffer", -1, -1, kWidth,
-                                  kHeight, kFormat, kUsage);
-  ASSERT_NE(nullptr, p);
-
-  // Record the original buffer id for later comparison.
-  const int buffer_id = p->id();
-
-  auto c = BufferConsumer::Import(p->CreateConsumer());
-  ASSERT_NE(nullptr, c);
-
-  EXPECT_EQ(0, p->Post<void>(LocalHandle()));
-
-  // Close the connection to the producer. This should not affect the consumer.
-  p = nullptr;
-
-  LocalHandle fence;
-  EXPECT_EQ(0, c->Acquire(&fence));
-  EXPECT_EQ(0, c->Release(LocalHandle()));
-
-  // Attempt to reconnect to the persistent buffer.
-  p = BufferProducer::Create("TestPersistentBuffer");
-  ASSERT_NE(nullptr, p);
-  EXPECT_EQ(buffer_id, p->id());
-  EXPECT_EQ(0, p->Gain(&fence));
-}
-
-TEST_F(LibBufferHubTest, TestPersistentBufferMismatchParams) {
-  auto p = BufferProducer::Create("TestPersistentBuffer", -1, -1, kWidth,
-                                  kHeight, kFormat, kUsage);
-  ASSERT_NE(nullptr, p);
-
-  // Close the connection to the producer.
-  p = nullptr;
-
-  // Mismatch the params.
-  p = BufferProducer::Create("TestPersistentBuffer", -1, -1, kWidth * 2,
-                             kHeight, kFormat, kUsage);
-  ASSERT_EQ(nullptr, p);
-}
-
-TEST_F(LibBufferHubTest, TestRemovePersistentBuffer) {
-  auto p = BufferProducer::Create("TestPersistentBuffer", -1, -1, kWidth,
-                                  kHeight, kFormat, kUsage);
-  ASSERT_NE(nullptr, p);
-
-  LocalHandle fence;
-  auto c = BufferConsumer::Import(p->CreateConsumer());
-  ASSERT_NE(nullptr, c);
-  EXPECT_EQ(0, p->Post<void>(LocalHandle()));
-  EXPECT_EQ(0, c->Acquire(&fence));
-  EXPECT_EQ(0, c->Release(LocalHandle()));
-  EXPECT_LT(0, RETRY_EINTR(p->Poll(10)));
-
-  // Test that removing persistence and closing the producer orphans the
-  // consumer.
-  EXPECT_EQ(0, p->Gain(&fence));
-  EXPECT_EQ(0, p->Post<void>(LocalHandle()));
-  EXPECT_EQ(0, p->RemovePersistence());
-  p = nullptr;
-
-  // Orphaned consumer can acquire the posted buffer one more time in
-  // asynchronous manner. But synchronous call will fail.
-  DvrNativeBufferMetadata meta;
-  EXPECT_EQ(0, c->AcquireAsync(&meta, &fence));
-  EXPECT_EQ(-EPIPE, c->Release(LocalHandle()));
-}
-
-namespace {
-
-int PollFd(int fd, int timeout_ms) {
-  pollfd p = {fd, POLLIN, 0};
-  return poll(&p, 1, timeout_ms);
-}
-
-}  // namespace
-
-TEST_F(LibBufferHubTest, TestAcquireFence) {
-  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
-      kWidth, kHeight, kFormat, kUsage, /*metadata_size=*/0);
-  ASSERT_TRUE(p.get() != nullptr);
-  std::unique_ptr<BufferConsumer> c =
-      BufferConsumer::Import(p->CreateConsumer());
-  ASSERT_TRUE(c.get() != nullptr);
-
-  DvrNativeBufferMetadata meta;
-  LocalHandle f1(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
-
-  // Post with unsignaled fence.
-  EXPECT_EQ(0, p->PostAsync(&meta, f1));
-
-  // Should acquire a valid fence.
-  LocalHandle f2;
-  EXPECT_LT(0, RETRY_EINTR(c->Poll(10)));
-  EXPECT_EQ(0, c->AcquireAsync(&meta, &f2));
-  EXPECT_TRUE(f2.IsValid());
-  // The original fence and acquired fence should have different fd number.
-  EXPECT_NE(f1.Get(), f2.Get());
-  EXPECT_GE(0, PollFd(f2.Get(), 0));
-
-  // Signal the original fence will trigger the new fence.
-  eventfd_write(f1.Get(), 1);
-  // Now the original FD has been signaled.
-  EXPECT_LT(0, PollFd(f2.Get(), 10));
-
-  // Release the consumer with an invalid fence.
-  EXPECT_EQ(0, c->ReleaseAsync(&meta, LocalHandle()));
-
-  // Should gain an invalid fence.
-  LocalHandle f3;
-  EXPECT_LT(0, RETRY_EINTR(p->Poll(10)));
-  EXPECT_EQ(0, p->GainAsync(&meta, &f3));
-  EXPECT_FALSE(f3.IsValid());
-
-  // Post with a signaled fence.
-  EXPECT_EQ(0, p->PostAsync(&meta, f1));
-
-  // Should acquire a valid fence and it's already signalled.
-  LocalHandle f4;
-  EXPECT_LT(0, RETRY_EINTR(c->Poll(10)));
-  EXPECT_EQ(0, c->AcquireAsync(&meta, &f4));
-  EXPECT_TRUE(f4.IsValid());
-  EXPECT_LT(0, PollFd(f4.Get(), 10));
-
-  // Release with an unsignalled fence and signal it immediately after release
-  // without producer gainning.
-  LocalHandle f5(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
-  EXPECT_EQ(0, c->ReleaseAsync(&meta, f5));
-  eventfd_write(f5.Get(), 1);
-
-  // Should gain a valid fence, which is already signaled.
-  LocalHandle f6;
-  EXPECT_LT(0, RETRY_EINTR(p->Poll(10)));
-  EXPECT_EQ(0, p->GainAsync(&meta, &f6));
-  EXPECT_TRUE(f6.IsValid());
-  EXPECT_LT(0, PollFd(f6.Get(), 10));
-}
-
-TEST_F(LibBufferHubTest, TestOrphanedAcquire) {
-  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
-      kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
-  ASSERT_TRUE(p.get() != nullptr);
-  std::unique_ptr<BufferConsumer> c1 =
-      BufferConsumer::Import(p->CreateConsumer());
-  ASSERT_TRUE(c1.get() != nullptr);
-  const uint64_t consumer_state_bit1 = c1->buffer_state_bit();
-
-  DvrNativeBufferMetadata meta;
-  EXPECT_EQ(0, p->PostAsync(&meta, LocalHandle()));
-
-  LocalHandle fence;
-  EXPECT_LT(0, RETRY_EINTR(c1->Poll(10)));
-  EXPECT_LE(0, c1->AcquireAsync(&meta, &fence));
-  // Destroy the consumer now will make it orphaned and the buffer is still
-  // acquired.
-  c1 = nullptr;
-  EXPECT_GE(0, RETRY_EINTR(p->Poll(10)));
-
-  std::unique_ptr<BufferConsumer> c2 =
-      BufferConsumer::Import(p->CreateConsumer());
-  ASSERT_TRUE(c2.get() != nullptr);
-  const uint64_t consumer_state_bit2 = c2->buffer_state_bit();
-  EXPECT_NE(consumer_state_bit1, consumer_state_bit2);
-
-  // The new consumer is available for acquire.
-  EXPECT_LT(0, RETRY_EINTR(c2->Poll(10)));
-  EXPECT_LE(0, c2->AcquireAsync(&meta, &fence));
-  // Releasing the consumer makes the buffer gainable.
-  EXPECT_EQ(0, c2->ReleaseAsync(&meta, LocalHandle()));
-
-  // The buffer is now available for the producer to gain.
-  EXPECT_LT(0, RETRY_EINTR(p->Poll(10)));
-
-  // But if another consumer is created in released state.
-  std::unique_ptr<BufferConsumer> c3 =
-      BufferConsumer::Import(p->CreateConsumer());
-  ASSERT_TRUE(c3.get() != nullptr);
-  const uint64_t consumer_state_bit3 = c3->buffer_state_bit();
-  EXPECT_NE(consumer_state_bit2, consumer_state_bit3);
-  // The consumer buffer is not acquirable.
-  EXPECT_GE(0, RETRY_EINTR(c3->Poll(10)));
-  EXPECT_EQ(-EBUSY, c3->AcquireAsync(&meta, &fence));
-
-  // Producer should be able to gain no matter what.
-  EXPECT_EQ(0, p->GainAsync(&meta, &fence));
-}
diff --git a/libs/vr/libbufferhub/detached_buffer.cpp b/libs/vr/libbufferhub/detached_buffer.cpp
new file mode 100644
index 0000000..6fae16d
--- /dev/null
+++ b/libs/vr/libbufferhub/detached_buffer.cpp
@@ -0,0 +1,125 @@
+#include <private/dvr/detached_buffer.h>
+
+#include <pdx/file_handle.h>
+#include <ui/DetachedBufferHandle.h>
+
+#include <poll.h>
+
+using android::pdx::LocalChannelHandle;
+using android::pdx::LocalHandle;
+using android::pdx::Status;
+
+namespace android {
+namespace dvr {
+
+DetachedBuffer::DetachedBuffer(uint32_t width, uint32_t height,
+                               uint32_t layer_count, uint32_t format,
+                               uint64_t usage, size_t user_metadata_size) {
+  ATRACE_NAME("DetachedBuffer::DetachedBuffer");
+  ALOGD_IF(TRACE,
+           "DetachedBuffer::DetachedBuffer: width=%u height=%u layer_count=%u, "
+           "format=%u usage=%" PRIx64 " user_metadata_size=%zu",
+           width, height, layer_count, format, usage, user_metadata_size);
+
+  auto status = client_.InvokeRemoteMethod<DetachedBufferRPC::Create>(
+      width, height, layer_count, format, usage, user_metadata_size);
+  if (!status) {
+    ALOGE(
+        "DetachedBuffer::DetachedBuffer: Failed to create detached buffer: %s",
+        status.GetErrorMessage().c_str());
+    client_.Close(-status.error());
+  }
+
+  const int ret = ImportGraphicBuffer();
+  if (ret < 0) {
+    ALOGE("DetachedBuffer::DetachedBuffer: Failed to import buffer: %s",
+          strerror(-ret));
+    client_.Close(ret);
+  }
+}
+
+DetachedBuffer::DetachedBuffer(LocalChannelHandle channel_handle)
+    : client_(std::move(channel_handle)) {
+  const int ret = ImportGraphicBuffer();
+  if (ret < 0) {
+    ALOGE("DetachedBuffer::DetachedBuffer: Failed to import buffer: %s",
+          strerror(-ret));
+    client_.Close(ret);
+  }
+}
+
+int DetachedBuffer::ImportGraphicBuffer() {
+  ATRACE_NAME("DetachedBuffer::DetachedBuffer");
+
+  auto status = client_.InvokeRemoteMethod<DetachedBufferRPC::Import>();
+  if (!status) {
+    ALOGE("DetachedBuffer::DetachedBuffer: Failed to import GraphicBuffer: %s",
+          status.GetErrorMessage().c_str());
+    return -status.error();
+  }
+
+  BufferDescription<LocalHandle> buffer_desc = status.take();
+  if (buffer_desc.id() < 0) {
+    ALOGE("DetachedBuffer::DetachedBuffer: Received an invalid id!");
+    return -EIO;
+  }
+
+  // Stash the buffer id to replace the value in id_.
+  const int buffer_id = buffer_desc.id();
+
+  // Import the buffer.
+  IonBuffer ion_buffer;
+  ALOGD_IF(TRACE, "DetachedBuffer::DetachedBuffer: id=%d.", buffer_id);
+
+  if (const int ret = buffer_desc.ImportBuffer(&ion_buffer)) {
+    ALOGE("Failed to import GraphicBuffer, error=%d", ret);
+    return ret;
+  }
+
+  // If all imports succeed, replace the previous buffer and id.
+  id_ = buffer_id;
+  buffer_ = std::move(ion_buffer);
+  return 0;
+}
+
+int DetachedBuffer::Poll(int timeout_ms) {
+  ATRACE_NAME("DetachedBuffer::Poll");
+  pollfd p = {client_.event_fd(), POLLIN, 0};
+  return poll(&p, 1, timeout_ms);
+}
+
+Status<LocalChannelHandle> DetachedBuffer::Promote() {
+  ATRACE_NAME("DetachedBuffer::Promote");
+  ALOGD_IF(TRACE, "DetachedBuffer::Promote: id=%d.", id_);
+
+  auto status_or_handle =
+      client_.InvokeRemoteMethod<DetachedBufferRPC::Promote>();
+  if (status_or_handle.ok()) {
+    // Invalidate the buffer.
+    buffer_ = {};
+  } else {
+    ALOGE("DetachedBuffer::Promote: Failed to promote buffer (id=%d): %s.", id_,
+          status_or_handle.GetErrorMessage().c_str());
+  }
+  return status_or_handle;
+}
+
+sp<GraphicBuffer> DetachedBuffer::TakeGraphicBuffer() {
+  if (!client_.IsValid() || !buffer_.buffer()) {
+    ALOGE("DetachedBuffer::TakeGraphicBuffer: Invalid buffer.");
+    return nullptr;
+  }
+
+  // Technically this should never happen.
+  LOG_FATAL_IF(
+      buffer_.buffer()->isDetachedBuffer(),
+      "DetachedBuffer::TakeGraphicBuffer: GraphicBuffer is already detached.");
+
+  sp<GraphicBuffer> buffer = std::move(buffer_.buffer());
+  buffer->setDetachedBufferHandle(
+      DetachedBufferHandle::Create(client_.TakeChannelHandle()));
+  return buffer;
+}
+
+}  // namespace dvr
+}  // namespace android
diff --git a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h
index 1186f93..0ea77c8 100644
--- a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h
+++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h
@@ -16,6 +16,21 @@
 namespace android {
 namespace dvr {
 
+class BufferHubClient : public pdx::Client {
+ public:
+  BufferHubClient();
+  explicit BufferHubClient(pdx::LocalChannelHandle channel_handle);
+
+  bool IsValid() const;
+  pdx::LocalChannelHandle TakeChannelHandle();
+
+  using pdx::Client::Close;
+  using pdx::Client::GetChannel;
+  using pdx::Client::InvokeRemoteMethod;
+  using pdx::Client::IsConnected;
+  using pdx::Client::event_fd;
+};
+
 class BufferHubBuffer : public pdx::Client {
  public:
   using LocalHandle = pdx::LocalHandle;
@@ -94,6 +109,9 @@
 
   int id() const { return id_; }
 
+  // Returns the buffer buffer state.
+  uint64_t buffer_state() { return buffer_state_->load(); };
+
   // A state mask which is unique to a buffer hub client among all its siblings
   // sharing the same concrete graphic buffer.
   uint64_t buffer_state_bit() const { return buffer_state_bit_; }
@@ -108,10 +126,6 @@
   uint32_t usage() const { return buffer_.usage(); }
   uint32_t layer_count() const { return buffer_.layer_count(); }
 
-  // TODO(b/37881101) Clean up producer/consumer usage.
-  uint64_t producer_usage() const { return buffer_.usage(); }
-  uint64_t consumer_usage() const { return buffer_.usage(); }
-
   uint64_t GetQueueIndex() const { return metadata_header_->queue_index; }
   void SetQueueIndex(uint64_t index) { metadata_header_->queue_index = index; }
 
@@ -218,18 +232,13 @@
   // succeeded, or a negative errno code if local error check fails.
   int GainAsync(DvrNativeBufferMetadata* out_meta, LocalHandle* out_fence);
 
-  // Attaches the producer to |name| so that it becomes a persistent buffer that
-  // may be retrieved by name at a later time. This may be used in cases where a
-  // shared memory buffer should persist across the life of the producer process
-  // (i.e. the buffer may be held by clients across a service restart). The
-  // buffer may be associated with a user and/or group id to restrict access to
-  // the buffer. If user_id or group_id is -1 then checks for the respective id
-  // are disabled. If user_id or group_id is 0 then the respective id of the
-  // calling process is used instead.
-  int MakePersistent(const std::string& name, int user_id, int group_id);
-
-  // Removes the persistence of the producer.
-  int RemovePersistence();
+  // Detaches a ProducerBuffer from an existing producer/consumer set. Can only
+  // be called when a producer buffer has exclusive access to the buffer (i.e.
+  // in the gain'ed state). On the successful return of the IPC call, a new
+  // LocalChannelHandle representing a detached buffer will be returned and all
+  // existing producer and consumer channels will be closed. Further IPCs
+  // towards those channels will return error.
+  Status<LocalChannelHandle> Detach();
 
  private:
   friend BASE;
@@ -240,44 +249,10 @@
 
   // Constructs a buffer with the given geometry and parameters.
   BufferProducer(uint32_t width, uint32_t height, uint32_t format,
-                 uint32_t usage, size_t metadata_size = 0);
-  BufferProducer(uint32_t width, uint32_t height, uint32_t format,
-                 uint64_t producer_usage, uint64_t consumer_usage,
-                 size_t metadata_size);
-
-  // Constructs a persistent buffer with the given geometry and parameters and
-  // binds it to |name| in one shot. If a persistent buffer with the same name
-  // and settings already exists and matches the given geometry and parameters,
-  // that buffer is connected to this client instead of creating a new buffer.
-  // If the name matches but the geometry or settings do not match then
-  // construction fails and BufferProducer::Create() returns nullptr.
-  //
-  // Access to the persistent buffer may be restricted by |user_id| and/or
-  // |group_id|; these settings are established only when the buffer is first
-  // created and cannot be changed. A user or group id of -1 disables checks for
-  // that respective id. A user or group id of 0 is substituted with the
-  // effective user or group id of the calling process.
-  BufferProducer(const std::string& name, int user_id, int group_id,
-                 uint32_t width, uint32_t height, uint32_t format,
-                 uint32_t usage, size_t metadata_size = 0);
-  BufferProducer(const std::string& name, int user_id, int group_id,
-                 uint32_t width, uint32_t height, uint32_t format,
-                 uint64_t producer_usage, uint64_t consumer_usage,
-                 size_t user_metadata_size);
+                 uint64_t usage, size_t metadata_size = 0);
 
   // Constructs a blob (flat) buffer with the given usage flags.
-  BufferProducer(uint32_t usage, size_t size);
-  BufferProducer(uint64_t producer_usage, uint64_t consumer_usage, size_t size);
-
-  // Constructs a persistent blob (flat) buffer and binds it to |name|.
-  BufferProducer(const std::string& name, int user_id, int group_id,
-                 uint32_t usage, size_t size);
-  BufferProducer(const std::string& name, int user_id, int group_id,
-                 uint64_t producer_usage, uint64_t consumer_usage, size_t size);
-
-  // Constructs a channel to persistent buffer by name only. The buffer must
-  // have been previously created or made persistent.
-  explicit BufferProducer(const std::string& name);
+  BufferProducer(uint64_t usage, size_t size);
 
   // Imports the given file handle to a producer channel, taking ownership.
   explicit BufferProducer(LocalChannelHandle channel);
diff --git a/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h b/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
index f9fd42d..f4918c4 100644
--- a/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
+++ b/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
@@ -2,8 +2,8 @@
 #define ANDROID_DVR_BUFFERHUB_RPC_H_
 
 #include <cutils/native_handle.h>
-#include <gui/BufferQueueDefs.h>
 #include <sys/types.h>
+#include <ui/BufferQueueDefs.h>
 
 #include <dvr/dvr_api.h>
 #include <pdx/channel_handle.h>
@@ -366,23 +366,25 @@
   // Op codes.
   enum {
     kOpCreateBuffer = 0,
-    kOpCreatePersistentBuffer,
-    kOpGetPersistentBuffer,
     kOpGetBuffer,
     kOpNewConsumer,
-    kOpProducerMakePersistent,
-    kOpProducerRemovePersistence,
     kOpProducerPost,
     kOpProducerGain,
     kOpConsumerAcquire,
     kOpConsumerRelease,
     kOpConsumerSetIgnore,
+    kOpProducerBufferDetach,
+    kOpConsumerBufferDetach,
+    kOpDetachedBufferCreate,
+    kOpDetachedBufferPromote,
     kOpCreateProducerQueue,
     kOpCreateConsumerQueue,
     kOpGetQueueInfo,
     kOpProducerQueueAllocateBuffers,
     kOpProducerQueueRemoveBuffer,
     kOpConsumerQueueImportBuffers,
+    // TODO(b/77153033): Separate all those RPC operations into subclasses.
+    kOpDetachedBufferBase = 1000,
   };
 
   // Aliases.
@@ -394,19 +396,9 @@
   PDX_REMOTE_METHOD(CreateBuffer, kOpCreateBuffer,
                     void(uint32_t width, uint32_t height, uint32_t format,
                          uint64_t usage, size_t user_metadata_size));
-  PDX_REMOTE_METHOD(CreatePersistentBuffer, kOpCreatePersistentBuffer,
-                    void(const std::string& name, int user_id, int group_id,
-                         uint32_t width, uint32_t height, uint32_t format,
-                         uint64_t usage, size_t user_metadata_size));
-  PDX_REMOTE_METHOD(GetPersistentBuffer, kOpGetPersistentBuffer,
-                    void(const std::string& name));
   PDX_REMOTE_METHOD(GetBuffer, kOpGetBuffer,
                     BufferDescription<LocalHandle>(Void));
   PDX_REMOTE_METHOD(NewConsumer, kOpNewConsumer, LocalChannelHandle(Void));
-  PDX_REMOTE_METHOD(ProducerMakePersistent, kOpProducerMakePersistent,
-                    void(const std::string& name, int user_id, int group_id));
-  PDX_REMOTE_METHOD(ProducerRemovePersistence, kOpProducerRemovePersistence,
-                    void(Void));
   PDX_REMOTE_METHOD(ProducerPost, kOpProducerPost,
                     void(LocalFence acquire_fence));
   PDX_REMOTE_METHOD(ProducerGain, kOpProducerGain, LocalFence(Void));
@@ -414,6 +406,17 @@
   PDX_REMOTE_METHOD(ConsumerRelease, kOpConsumerRelease,
                     void(LocalFence release_fence));
   PDX_REMOTE_METHOD(ConsumerSetIgnore, kOpConsumerSetIgnore, void(bool ignore));
+  PDX_REMOTE_METHOD(ProducerBufferDetach, kOpProducerBufferDetach,
+                    LocalChannelHandle(Void));
+
+  // Detaches a ConsumerBuffer from an existing producer/consumer set. Can only
+  // be called when the consumer is the only consumer and it has exclusive
+  // access to the buffer (i.e. in the acquired'ed state). On the successful
+  // return of the IPC call, a new DetachedBufferChannel handle will be returned
+  // and all existing producer and consumer channels will be closed. Further
+  // IPCs towards those channels will return error.
+  PDX_REMOTE_METHOD(ConsumerBufferDetach, kOpConsumerBufferDetach,
+                    LocalChannelHandle(Void));
 
   // Buffer Queue Methods.
   PDX_REMOTE_METHOD(CreateProducerQueue, kOpCreateProducerQueue,
@@ -433,6 +436,25 @@
                     std::vector<std::pair<LocalChannelHandle, size_t>>(Void));
 };
 
+struct DetachedBufferRPC final : public BufferHubRPC {
+ private:
+  enum {
+    kOpCreate = kOpDetachedBufferBase,
+    kOpImport,
+    kOpPromote,
+  };
+
+ public:
+  PDX_REMOTE_METHOD(Create, kOpCreate,
+                    void(uint32_t width, uint32_t height, uint32_t layer_count,
+                         uint32_t format, uint64_t usage,
+                         size_t user_metadata_size));
+  PDX_REMOTE_METHOD(Import, kOpImport, BufferDescription<LocalHandle>(Void));
+  PDX_REMOTE_METHOD(Promote, kOpPromote, LocalChannelHandle(Void));
+
+  PDX_REMOTE_API(API, Create, Promote);
+};
+
 }  // namespace dvr
 }  // namespace android
 
diff --git a/libs/vr/libbufferhub/include/private/dvr/detached_buffer.h b/libs/vr/libbufferhub/include/private/dvr/detached_buffer.h
new file mode 100644
index 0000000..6d0b502
--- /dev/null
+++ b/libs/vr/libbufferhub/include/private/dvr/detached_buffer.h
@@ -0,0 +1,82 @@
+#ifndef ANDROID_DVR_DETACHED_BUFFER_H_
+#define ANDROID_DVR_DETACHED_BUFFER_H_
+
+#include <private/dvr/buffer_hub_client.h>
+
+namespace android {
+namespace dvr {
+
+class DetachedBuffer {
+ public:
+  // Allocates a standalone DetachedBuffer not associated with any producer
+  // consumer set.
+  static std::unique_ptr<DetachedBuffer> Create(uint32_t width, uint32_t height,
+                                                uint32_t layer_count,
+                                                uint32_t format, uint64_t usage,
+                                                size_t user_metadata_size) {
+    return std::unique_ptr<DetachedBuffer>(new DetachedBuffer(
+        width, height, layer_count, format, usage, user_metadata_size));
+  }
+
+  // Imports the given channel handle to a DetachedBuffer, taking ownership.
+  static std::unique_ptr<DetachedBuffer> Import(
+      pdx::LocalChannelHandle channel_handle) {
+    return std::unique_ptr<DetachedBuffer>(
+        new DetachedBuffer(std::move(channel_handle)));
+  }
+
+  DetachedBuffer(const DetachedBuffer&) = delete;
+  void operator=(const DetachedBuffer&) = delete;
+
+  const sp<GraphicBuffer>& buffer() const { return buffer_.buffer(); }
+
+  int id() const { return id_; }
+
+  // Returns true if the buffer holds an open PDX channels towards bufferhubd.
+  bool IsConnected() const { return client_.IsValid(); }
+
+  // Returns true if the buffer holds an valid gralloc buffer handle that's
+  // availble for the client to read from and/or write into.
+  bool IsValid() const { return buffer_.IsValid(); }
+
+  // Returns the event mask for all the events that are pending on this buffer
+  // (see sys/poll.h for all possible bits).
+  pdx::Status<int> GetEventMask(int events) {
+    if (auto* channel = client_.GetChannel()) {
+      return channel->GetEventMask(events);
+    } else {
+      return pdx::ErrorStatus(EINVAL);
+    }
+  }
+
+  // Polls the fd for |timeout_ms| milliseconds (-1 for infinity).
+  int Poll(int timeout_ms);
+
+  // Promotes a DetachedBuffer to become a ProducerBuffer. Once promoted the
+  // DetachedBuffer channel will be closed automatically on successful IPC
+  // return. Further IPCs towards this channel will return error.
+  pdx::Status<pdx::LocalChannelHandle> Promote();
+
+  // Takes the underlying graphic buffer out of this DetachedBuffer. This call
+  // immediately invalidates this DetachedBuffer object and transfers the
+  // underlying pdx::LocalChannelHandle into the GraphicBuffer.
+  sp<GraphicBuffer> TakeGraphicBuffer();
+
+ private:
+  DetachedBuffer(uint32_t width, uint32_t height, uint32_t layer_count,
+                 uint32_t format, uint64_t usage, size_t user_metadata_size);
+
+  DetachedBuffer(pdx::LocalChannelHandle channel_handle);
+
+  int ImportGraphicBuffer();
+
+  // Global id for the buffer that is consistent across processes.
+  int id_;
+  IonBuffer buffer_;
+  BufferHubClient client_;
+};
+
+}  // namespace dvr
+}  // namespace android
+
+#endif  // ANDROID_DVR_DETACHED_BUFFER_H_
diff --git a/libs/vr/libbufferhub/include/private/dvr/ion_buffer.h b/libs/vr/libbufferhub/include/private/dvr/ion_buffer.h
index 0d337f7..f6bc547 100644
--- a/libs/vr/libbufferhub/include/private/dvr/ion_buffer.h
+++ b/libs/vr/libbufferhub/include/private/dvr/ion_buffer.h
@@ -23,6 +23,9 @@
   IonBuffer(IonBuffer&& other);
   IonBuffer& operator=(IonBuffer&& other);
 
+  // Returns check this IonBuffer holds a valid Gralloc buffer.
+  bool IsValid() const { return buffer_ && buffer_->initCheck() == NO_ERROR; }
+
   // Frees the underlying native handle and leaves the instance initialized to
   // empty.
   void FreeHandle();
@@ -66,6 +69,7 @@
               struct android_ycbcr* yuv);
   int Unlock();
 
+  sp<GraphicBuffer>& buffer() { return buffer_; }
   const sp<GraphicBuffer>& buffer() const { return buffer_; }
   buffer_handle_t handle() const {
     return buffer_.get() ? buffer_->handle : nullptr;
diff --git a/libs/vr/libbufferhub/include/private/dvr/native_buffer.h b/libs/vr/libbufferhub/include/private/dvr/native_buffer.h
deleted file mode 100644
index 140ffc5..0000000
--- a/libs/vr/libbufferhub/include/private/dvr/native_buffer.h
+++ /dev/null
@@ -1,179 +0,0 @@
-#ifndef ANDROID_DVR_NATIVE_BUFFER_H_
-#define ANDROID_DVR_NATIVE_BUFFER_H_
-
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-#include <log/log.h>
-#include <ui/ANativeObjectBase.h>
-#include <utils/RefBase.h>
-#include <nativebase/nativebase.h>
-
-#include <private/dvr/buffer_hub_client.h>
-
-namespace android {
-namespace dvr {
-
-// ANativeWindowBuffer is the abstraction Android HALs and frameworks use to
-// pass around hardware graphics buffers. The following classes implement this
-// abstraction with different DVR backing buffers, all of which provide
-// different semantics on top of ion/gralloc buffers.
-
-// An implementation of ANativeWindowBuffer backed by an IonBuffer.
-class NativeBuffer
-    : public android::ANativeObjectBase<ANativeWindowBuffer, NativeBuffer,
-                                        android::LightRefBase<NativeBuffer>> {
- public:
-  static constexpr int kEmptyFence = -1;
-
-  explicit NativeBuffer(const std::shared_ptr<IonBuffer>& buffer)
-      : BASE(), buffer_(buffer), fence_(kEmptyFence) {
-    ANativeWindowBuffer::width = buffer->width();
-    ANativeWindowBuffer::height = buffer->height();
-    ANativeWindowBuffer::stride = buffer->stride();
-    ANativeWindowBuffer::format = buffer->format();
-    ANativeWindowBuffer::usage = buffer->usage();
-    handle = buffer_->handle();
-  }
-
-  virtual ~NativeBuffer() {}
-
-  std::shared_ptr<IonBuffer> buffer() { return buffer_; }
-  int fence() const { return fence_.Get(); }
-
-  void SetFence(int fence) { fence_.Reset(fence); }
-
- private:
-  friend class android::LightRefBase<NativeBuffer>;
-
-  std::shared_ptr<IonBuffer> buffer_;
-  pdx::LocalHandle fence_;
-
-  NativeBuffer(const NativeBuffer&) = delete;
-  void operator=(NativeBuffer&) = delete;
-};
-
-class NativeBufferProducer : public android::ANativeObjectBase<
-                                 ANativeWindowBuffer, NativeBufferProducer,
-                                 android::LightRefBase<NativeBufferProducer>> {
- public:
-  static constexpr int kEmptyFence = -1;
-
-  NativeBufferProducer(const std::shared_ptr<BufferProducer>& buffer,
-                       EGLDisplay display, uint32_t surface_buffer_index)
-      : BASE(),
-        buffer_(buffer),
-        surface_buffer_index_(surface_buffer_index),
-        display_(display) {
-    ANativeWindowBuffer::width = buffer_->width();
-    ANativeWindowBuffer::height = buffer_->height();
-    ANativeWindowBuffer::stride = buffer_->stride();
-    ANativeWindowBuffer::format = buffer_->format();
-    ANativeWindowBuffer::usage = buffer_->usage();
-    ANativeWindowBuffer::handle = buffer_->native_handle();
-    if (display_) {
-      image_khr_ =
-          eglCreateImageKHR(display_, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
-                            static_cast<ANativeWindowBuffer*>(this), nullptr);
-    } else {
-      image_khr_ = EGL_NO_IMAGE_KHR;
-    }
-  }
-
-  explicit NativeBufferProducer(const std::shared_ptr<BufferProducer>& buffer)
-      : NativeBufferProducer(buffer, nullptr, 0) {}
-
-  virtual ~NativeBufferProducer() {
-    if (image_khr_ != EGL_NO_IMAGE_KHR)
-      eglDestroyImageKHR(display_, image_khr_);
-  }
-
-  EGLImageKHR image_khr() const { return image_khr_; }
-  std::shared_ptr<BufferProducer> buffer() const { return buffer_; }
-  int release_fence() const { return release_fence_.Get(); }
-  uint32_t surface_buffer_index() const { return surface_buffer_index_; }
-
-  // Return the release fence, passing ownership to the caller.
-  pdx::LocalHandle ClaimReleaseFence() { return std::move(release_fence_); }
-
-  // Post the buffer consumer, closing the acquire and release fences.
-  int Post(int acquire_fence, uint64_t sequence) {
-    release_fence_.Close();
-    return buffer_->Post(pdx::LocalHandle(acquire_fence), sequence);
-  }
-
-  // Gain the buffer producer, closing the previous release fence if valid.
-  int Gain() { return buffer_->Gain(&release_fence_); }
-
-  // Asynchronously gain the buffer, closing the previous release fence.
-  int GainAsync() {
-    release_fence_.Close();
-    return buffer_->GainAsync();
-  }
-
- private:
-  friend class android::LightRefBase<NativeBufferProducer>;
-
-  std::shared_ptr<BufferProducer> buffer_;
-  pdx::LocalHandle release_fence_;
-  EGLImageKHR image_khr_;
-  uint32_t surface_buffer_index_;
-  EGLDisplay display_;
-
-  NativeBufferProducer(const NativeBufferProducer&) = delete;
-  void operator=(NativeBufferProducer&) = delete;
-};
-
-// NativeBufferConsumer is an implementation of ANativeWindowBuffer backed by a
-// BufferConsumer.
-class NativeBufferConsumer : public android::ANativeObjectBase<
-                                 ANativeWindowBuffer, NativeBufferConsumer,
-                                 android::LightRefBase<NativeBufferConsumer>> {
- public:
-  static constexpr int kEmptyFence = -1;
-
-  explicit NativeBufferConsumer(const std::shared_ptr<BufferConsumer>& buffer)
-      : BASE(), buffer_(buffer), acquire_fence_(kEmptyFence), sequence_(0) {
-    ANativeWindowBuffer::width = buffer_->width();
-    ANativeWindowBuffer::height = buffer_->height();
-    ANativeWindowBuffer::stride = buffer_->stride();
-    ANativeWindowBuffer::format = buffer_->format();
-    ANativeWindowBuffer::usage = buffer_->usage();
-    handle = buffer_->native_handle();
-  }
-
-  virtual ~NativeBufferConsumer() {}
-
-  std::shared_ptr<BufferConsumer> buffer() const { return buffer_; }
-  int acquire_fence() const { return acquire_fence_.Get(); }
-  uint64_t sequence() const { return sequence_; }
-
-  // Return the acquire fence, passing ownership to the caller.
-  pdx::LocalHandle ClaimAcquireFence() { return std::move(acquire_fence_); }
-
-  // Acquire the underlying buffer consumer, closing the previous acquire fence
-  // if valid.
-  int Acquire() { return buffer_->Acquire(&acquire_fence_, &sequence_); }
-
-  // Release the buffer consumer, closing the acquire and release fences if
-  // valid.
-  int Release(int release_fence) {
-    acquire_fence_.Close();
-    sequence_ = 0;
-    return buffer_->Release(pdx::LocalHandle(release_fence));
-  }
-
- private:
-  friend class android::LightRefBase<NativeBufferConsumer>;
-
-  std::shared_ptr<BufferConsumer> buffer_;
-  pdx::LocalHandle acquire_fence_;
-  uint64_t sequence_;
-
-  NativeBufferConsumer(const NativeBufferConsumer&) = delete;
-  void operator=(NativeBufferConsumer&) = delete;
-};
-
-}  // namespace dvr
-}  // namespace android
-
-#endif  // ANDROID_DVR_NATIVE_BUFFER_H_
diff --git a/libs/vr/libbufferhubqueue/Android.bp b/libs/vr/libbufferhubqueue/Android.bp
index b279875..9f72c05 100644
--- a/libs/vr/libbufferhubqueue/Android.bp
+++ b/libs/vr/libbufferhubqueue/Android.bp
@@ -14,7 +14,7 @@
 
 sourceFiles = [
     "buffer_hub_queue_client.cpp",
-    "buffer_hub_queue_producer.cpp",
+    "buffer_hub_queue_parcelable.cpp",
 ]
 
 includeFiles = [
@@ -23,8 +23,6 @@
 
 staticLibraries = [
     "libbufferhub",
-    "libdvrcommon",
-    "libpdx_default_transport",
 ]
 
 sharedLibraries = [
@@ -35,7 +33,7 @@
     "liblog",
     "libui",
     "libutils",
-    "libgui",
+    "libpdx_default_transport",
 ]
 
 headerLibraries = [
@@ -43,7 +41,7 @@
     "libnativebase_headers",
 ]
 
-cc_library {
+cc_library_shared {
     name: "libbufferhubqueue",
     cflags: [
         "-DLOG_TAG=\"libbufferhubqueue\"",
@@ -63,4 +61,4 @@
     header_libs: headerLibraries,
 }
 
-subdirs = ["tests"]
+subdirs = ["benchmarks", "tests"]
diff --git a/libs/vr/libbufferhubqueue/benchmarks/Android.bp b/libs/vr/libbufferhubqueue/benchmarks/Android.bp
new file mode 100644
index 0000000..5089b87
--- /dev/null
+++ b/libs/vr/libbufferhubqueue/benchmarks/Android.bp
@@ -0,0 +1,26 @@
+
+cc_benchmark {
+    srcs: ["buffer_transport_benchmark.cpp"],
+    shared_libs: [
+        "libbase",
+        "libbinder",
+        "libcutils",
+        "libdvr",
+        "libgui",
+        "liblog",
+        "libhardware",
+        "libui",
+        "libutils",
+        "libnativewindow",
+        "libbufferhubqueue",
+        "libpdx_default_transport",
+    ],
+    cflags: [
+        "-DLOG_TAG=\"buffer_transport_benchmark\"",
+        "-DTRACE=0",
+        "-O2",
+        "-Wall",
+        "-Werror",
+    ],
+    name: "buffer_transport_benchmark",
+}
diff --git a/libs/vr/libbufferhubqueue/benchmarks/buffer_transport_benchmark.cpp b/libs/vr/libbufferhubqueue/benchmarks/buffer_transport_benchmark.cpp
new file mode 100644
index 0000000..4ca8671
--- /dev/null
+++ b/libs/vr/libbufferhubqueue/benchmarks/buffer_transport_benchmark.cpp
@@ -0,0 +1,589 @@
+#include <android-base/logging.h>
+#include <android/native_window.h>
+#include <benchmark/benchmark.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <dvr/dvr_api.h>
+#include <gui/BufferItem.h>
+#include <gui/BufferItemConsumer.h>
+#include <gui/Surface.h>
+#include <private/dvr/epoll_file_descriptor.h>
+#include <utils/Trace.h>
+
+#include <chrono>
+#include <functional>
+#include <iostream>
+#include <thread>
+#include <vector>
+
+#include <dlfcn.h>
+#include <poll.h>
+#include <sys/epoll.h>
+#include <sys/wait.h>
+
+// Use ALWAYS at the tag level. Control is performed manually during command
+// line processing.
+#ifdef ATRACE_TAG
+#undef ATRACE_TAG
+#endif
+#define ATRACE_TAG ATRACE_TAG_ALWAYS
+
+using namespace android;
+using ::benchmark::State;
+
+static const String16 kBinderService = String16("bufferTransport");
+static const uint32_t kBufferWidth = 100;
+static const uint32_t kBufferHeight = 1;
+static const uint32_t kBufferFormat = HAL_PIXEL_FORMAT_BLOB;
+static const uint64_t kBufferUsage =
+    GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN;
+static const uint32_t kBufferLayer = 1;
+static const int kMaxAcquiredImages = 1;
+static const int kQueueDepth = 2;  // We are double buffering for this test.
+static const size_t kMaxQueueCounts = 128;
+static const int kInvalidFence = -1;
+
+enum BufferTransportServiceCode {
+  CREATE_BUFFER_QUEUE = IBinder::FIRST_CALL_TRANSACTION,
+};
+
+// A binder services that minics a compositor that consumes buffers. It provides
+// one Binder interface to create a new Surface for buffer producer to write
+// into; while itself will carry out no-op buffer consuming by acquiring then
+// releasing the buffer immediately.
+class BufferTransportService : public BBinder {
+ public:
+  BufferTransportService() = default;
+  ~BufferTransportService() = default;
+
+  virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+                              uint32_t flags = 0) {
+    (void)flags;
+    (void)data;
+    switch (code) {
+      case CREATE_BUFFER_QUEUE: {
+        auto new_queue = std::make_shared<BufferQueueHolder>(this);
+        reply->writeStrongBinder(
+            IGraphicBufferProducer::asBinder(new_queue->producer));
+        buffer_queues_.push_back(new_queue);
+        return NO_ERROR;
+      }
+      default:
+        return UNKNOWN_TRANSACTION;
+    };
+  }
+
+ private:
+  struct FrameListener : public ConsumerBase::FrameAvailableListener {
+   public:
+    FrameListener(BufferTransportService* /*service*/,
+                  sp<BufferItemConsumer> buffer_item_consumer)
+        : buffer_item_consumer_(buffer_item_consumer) {}
+
+    void onFrameAvailable(const BufferItem& /*item*/) override {
+      BufferItem buffer;
+      status_t ret = 0;
+      {
+        ATRACE_NAME("AcquireBuffer");
+        ret = buffer_item_consumer_->acquireBuffer(&buffer, /*presentWhen=*/0,
+                                                   /*waitForFence=*/false);
+      }
+
+      if (ret != NO_ERROR) {
+        LOG(ERROR) << "Failed to acquire next buffer.";
+        return;
+      }
+
+      {
+        ATRACE_NAME("ReleaseBuffer");
+        ret = buffer_item_consumer_->releaseBuffer(buffer);
+      }
+
+      if (ret != NO_ERROR) {
+        LOG(ERROR) << "Failed to release buffer.";
+        return;
+      }
+    }
+
+   private:
+    sp<BufferItemConsumer> buffer_item_consumer_;
+  };
+
+  struct BufferQueueHolder {
+    explicit BufferQueueHolder(BufferTransportService* service) {
+      BufferQueue::createBufferQueue(&producer, &consumer);
+
+      sp<BufferItemConsumer> buffer_item_consumer =
+          new BufferItemConsumer(consumer, kBufferUsage, kMaxAcquiredImages,
+                                 /*controlledByApp=*/true);
+      buffer_item_consumer->setName(String8("BinderBufferTransport"));
+      frame_listener_ = new FrameListener(service, buffer_item_consumer);
+      buffer_item_consumer->setFrameAvailableListener(frame_listener_);
+    }
+
+    sp<IGraphicBufferProducer> producer;
+    sp<IGraphicBufferConsumer> consumer;
+
+   private:
+    sp<FrameListener> frame_listener_;
+  };
+
+  std::vector<std::shared_ptr<BufferQueueHolder>> buffer_queues_;
+};
+
+// A virtual interfaces that abstracts the common BufferQueue operations, so
+// that the test suite can use the same test case to drive different types of
+// transport backends.
+class BufferTransport {
+ public:
+  virtual ~BufferTransport() {}
+
+  virtual int Start() = 0;
+  virtual sp<Surface> CreateSurface() = 0;
+};
+
+// Binder-based buffer transport backend.
+//
+// On Start() a new process will be swapned to run a Binder server that
+// actually consumes the buffer.
+// On CreateSurface() a new Binder BufferQueue will be created, which the
+// service holds the concrete binder node of the IGraphicBufferProducer while
+// sending the binder proxy to the client. In another word, the producer side
+// operations are carried out process while the consumer side operations are
+// carried out within the BufferTransportService's own process.
+class BinderBufferTransport : public BufferTransport {
+ public:
+  BinderBufferTransport() {}
+
+  int Start() override {
+    sp<IServiceManager> sm = defaultServiceManager();
+    service_ = sm->getService(kBinderService);
+    if (service_ == nullptr) {
+      LOG(ERROR) << "Failed to get the benchmark service.";
+      return -EIO;
+    }
+
+    LOG(INFO) << "Binder server is ready for client.";
+    return 0;
+  }
+
+  sp<Surface> CreateSurface() override {
+    Parcel data;
+    Parcel reply;
+    int error = service_->transact(CREATE_BUFFER_QUEUE, data, &reply);
+    if (error != NO_ERROR) {
+      LOG(ERROR) << "Failed to get buffer queue over binder.";
+      return nullptr;
+    }
+
+    sp<IBinder> binder;
+    error = reply.readNullableStrongBinder(&binder);
+    if (error != NO_ERROR) {
+      LOG(ERROR) << "Failed to get IGraphicBufferProducer over binder.";
+      return nullptr;
+    }
+
+    auto producer = interface_cast<IGraphicBufferProducer>(binder);
+    if (producer == nullptr) {
+      LOG(ERROR) << "Failed to get IGraphicBufferProducer over binder.";
+      return nullptr;
+    }
+
+    sp<Surface> surface = new Surface(producer, /*controlledByApp=*/true);
+
+    // Set buffer dimension.
+    ANativeWindow* window = static_cast<ANativeWindow*>(surface.get());
+    ANativeWindow_setBuffersGeometry(window, kBufferWidth, kBufferHeight,
+                                     kBufferFormat);
+
+    return surface;
+  }
+
+ private:
+  sp<IBinder> service_;
+};
+
+class DvrApi {
+ public:
+  DvrApi() {
+    handle_ = dlopen("libdvr.so", RTLD_NOW | RTLD_LOCAL);
+    CHECK(handle_);
+
+    auto dvr_get_api =
+        reinterpret_cast<decltype(&dvrGetApi)>(dlsym(handle_, "dvrGetApi"));
+    int ret = dvr_get_api(&api_, sizeof(api_), /*version=*/1);
+
+    CHECK(ret == 0);
+  }
+
+  ~DvrApi() { dlclose(handle_); }
+
+  const DvrApi_v1& Api() { return api_; }
+
+ private:
+  void* handle_ = nullptr;
+  DvrApi_v1 api_;
+};
+
+// BufferHub/PDX-based buffer transport.
+//
+// On Start() a new thread will be swapned to run an epoll polling thread which
+// minics the behavior of a compositor. Similar to Binder-based backend, the
+// buffer available handler is also a no-op: Buffer gets acquired and released
+// immediately.
+// On CreateSurface() a pair of dvr::ProducerQueue and dvr::ConsumerQueue will
+// be created. The epoll thread holds on the consumer queue and dequeues buffer
+// from it; while the producer queue will be wrapped in a Surface and returned
+// to test suite.
+class BufferHubTransport : public BufferTransport {
+ public:
+  virtual ~BufferHubTransport() {
+    stopped_.store(true);
+    if (reader_thread_.joinable()) {
+      reader_thread_.join();
+    }
+  }
+
+  int Start() override {
+    int ret = epoll_fd_.Create();
+    if (ret < 0) {
+      LOG(ERROR) << "Failed to create epoll fd: %s", strerror(-ret);
+      return -1;
+    }
+
+    // Create the reader thread.
+    reader_thread_ = std::thread([this]() {
+      int ret = dvr_.Api().PerformanceSetSchedulerPolicy(0, "graphics");
+      if (ret < 0) {
+        LOG(ERROR) << "Failed to set scheduler policy, ret=" << ret;
+        return;
+      }
+
+      stopped_.store(false);
+      LOG(INFO) << "Reader Thread Running...";
+
+      while (!stopped_.load()) {
+        std::array<epoll_event, kMaxQueueCounts> events;
+
+        // Don't sleep forever so that we will have a chance to wake up.
+        const int ret = epoll_fd_.Wait(events.data(), events.size(),
+                                       /*timeout=*/100);
+        if (ret < 0) {
+          LOG(ERROR) << "Error polling consumer queues.";
+          continue;
+        }
+        if (ret == 0) {
+          continue;
+        }
+
+        const int num_events = ret;
+        for (int i = 0; i < num_events; i++) {
+          uint32_t index = events[i].data.u32;
+          dvr_.Api().ReadBufferQueueHandleEvents(
+              buffer_queues_[index]->GetReadQueue());
+        }
+      }
+
+      LOG(INFO) << "Reader Thread Exiting...";
+    });
+
+    return 0;
+  }
+
+  sp<Surface> CreateSurface() override {
+    auto new_queue = std::make_shared<BufferQueueHolder>();
+    if (!new_queue->IsReady()) {
+      LOG(ERROR) << "Failed to create BufferHub-based BufferQueue.";
+      return nullptr;
+    }
+
+    // Set buffer dimension.
+    ANativeWindow_setBuffersGeometry(new_queue->GetSurface(), kBufferWidth,
+                                     kBufferHeight, kBufferFormat);
+
+    // Use the next position as buffer_queue index.
+    uint32_t index = buffer_queues_.size();
+    epoll_event event = {.events = EPOLLIN | EPOLLET, .data = {.u32 = index}};
+    int queue_fd =
+        dvr_.Api().ReadBufferQueueGetEventFd(new_queue->GetReadQueue());
+    const int ret = epoll_fd_.Control(EPOLL_CTL_ADD, queue_fd, &event);
+    if (ret < 0) {
+      LOG(ERROR) << "Failed to track consumer queue: " << strerror(-ret)
+                 << ", consumer queue fd: " << queue_fd;
+      return nullptr;
+    }
+
+    buffer_queues_.push_back(new_queue);
+    ANativeWindow_acquire(new_queue->GetSurface());
+    return static_cast<Surface*>(new_queue->GetSurface());
+  }
+
+ private:
+  struct BufferQueueHolder {
+    BufferQueueHolder() {
+      int ret = 0;
+      ret = dvr_.Api().WriteBufferQueueCreate(
+          kBufferWidth, kBufferHeight, kBufferFormat, kBufferLayer,
+          kBufferUsage, 0, sizeof(DvrNativeBufferMetadata), &write_queue_);
+      if (ret < 0) {
+        LOG(ERROR) << "Failed to create write buffer queue, ret=" << ret;
+        return;
+      }
+
+      ret = dvr_.Api().WriteBufferQueueCreateReadQueue(write_queue_,
+                                                       &read_queue_);
+      if (ret < 0) {
+        LOG(ERROR) << "Failed to create read buffer queue, ret=" << ret;
+        return;
+      }
+
+      ret = dvr_.Api().ReadBufferQueueSetBufferAvailableCallback(
+          read_queue_, BufferAvailableCallback, this);
+      if (ret < 0) {
+        LOG(ERROR) << "Failed to create buffer available callback, ret=" << ret;
+        return;
+      }
+
+      ret =
+          dvr_.Api().WriteBufferQueueGetANativeWindow(write_queue_, &surface_);
+      if (ret < 0) {
+        LOG(ERROR) << "Failed to create surface, ret=" << ret;
+        return;
+      }
+    }
+
+    static void BufferAvailableCallback(void* context) {
+      BufferQueueHolder* thiz = static_cast<BufferQueueHolder*>(context);
+      thiz->HandleBufferAvailable();
+    }
+
+    DvrReadBufferQueue* GetReadQueue() { return read_queue_; }
+
+    ANativeWindow* GetSurface() { return surface_; }
+
+    bool IsReady() {
+      return write_queue_ != nullptr && read_queue_ != nullptr &&
+             surface_ != nullptr;
+    }
+
+    void HandleBufferAvailable() {
+      int ret = 0;
+      DvrNativeBufferMetadata meta;
+      DvrReadBuffer* buffer = nullptr;
+      DvrNativeBufferMetadata metadata;
+      int acquire_fence = kInvalidFence;
+
+      {
+        ATRACE_NAME("AcquireBuffer");
+        ret = dvr_.Api().ReadBufferQueueAcquireBuffer(
+            read_queue_, 0, &buffer, &metadata, &acquire_fence);
+      }
+      if (ret < 0) {
+        LOG(ERROR) << "Failed to acquire consumer buffer, error: " << ret;
+        return;
+      }
+
+      if (buffer != nullptr) {
+        ATRACE_NAME("ReleaseBuffer");
+        ret = dvr_.Api().ReadBufferQueueReleaseBuffer(read_queue_, buffer,
+                                                      &meta, kInvalidFence);
+      }
+      if (ret < 0) {
+        LOG(ERROR) << "Failed to release consumer buffer, error: " << ret;
+      }
+    }
+
+   private:
+    DvrWriteBufferQueue* write_queue_ = nullptr;
+    DvrReadBufferQueue* read_queue_ = nullptr;
+    ANativeWindow* surface_ = nullptr;
+  };
+
+  static DvrApi dvr_;
+  std::atomic<bool> stopped_;
+  std::thread reader_thread_;
+
+  dvr::EpollFileDescriptor epoll_fd_;
+  std::vector<std::shared_ptr<BufferQueueHolder>> buffer_queues_;
+};
+
+DvrApi BufferHubTransport::dvr_ = {};
+
+enum TransportType {
+  kBinderBufferTransport,
+  kBufferHubTransport,
+};
+
+// Main test suite, which supports two transport backend: 1) BinderBufferQueue,
+// 2) BufferHubQueue. The test case drives the producer end of both transport
+// backend by queuing buffers into the buffer queue by using ANativeWindow API.
+class BufferTransportBenchmark : public ::benchmark::Fixture {
+ public:
+  void SetUp(State& state) override {
+    if (state.thread_index == 0) {
+      const int transport = state.range(0);
+      switch (transport) {
+        case kBinderBufferTransport:
+          transport_.reset(new BinderBufferTransport);
+          break;
+        case kBufferHubTransport:
+          transport_.reset(new BufferHubTransport);
+          break;
+        default:
+          CHECK(false) << "Unknown test case.";
+          break;
+      }
+
+      CHECK(transport_);
+      const int ret = transport_->Start();
+      CHECK_EQ(ret, 0);
+
+      LOG(INFO) << "Transport backend running, transport=" << transport << ".";
+
+      // Create surfaces for each thread.
+      surfaces_.resize(state.threads);
+      for (int i = 0; i < state.threads; i++) {
+        // Common setup every thread needs.
+        surfaces_[i] = transport_->CreateSurface();
+        CHECK(surfaces_[i]);
+
+        LOG(INFO) << "Surface initialized on thread " << i << ".";
+      }
+    }
+  }
+
+  void TearDown(State& state) override {
+    if (state.thread_index == 0) {
+      surfaces_.clear();
+      transport_.reset();
+      LOG(INFO) << "Tear down benchmark.";
+    }
+  }
+
+ protected:
+  std::unique_ptr<BufferTransport> transport_;
+  std::vector<sp<Surface>> surfaces_;
+};
+
+BENCHMARK_DEFINE_F(BufferTransportBenchmark, Producers)(State& state) {
+  ANativeWindow* window = nullptr;
+  ANativeWindow_Buffer buffer;
+  int32_t error = 0;
+  double total_gain_buffer_us = 0;
+  double total_post_buffer_us = 0;
+  int iterations = 0;
+
+  while (state.KeepRunning()) {
+    if (window == nullptr) {
+      CHECK(surfaces_[state.thread_index]);
+      window = static_cast<ANativeWindow*>(surfaces_[state.thread_index].get());
+
+      // Lock buffers a couple time from the queue, so that we have the buffer
+      // allocated.
+      for (int i = 0; i < kQueueDepth; i++) {
+        error = ANativeWindow_lock(window, &buffer,
+                                   /*inOutDirtyBounds=*/nullptr);
+        CHECK_EQ(error, 0);
+        error = ANativeWindow_unlockAndPost(window);
+        CHECK_EQ(error, 0);
+      }
+    }
+
+    {
+      ATRACE_NAME("GainBuffer");
+      auto t1 = std::chrono::high_resolution_clock::now();
+      error = ANativeWindow_lock(window, &buffer,
+                                 /*inOutDirtyBounds=*/nullptr);
+      auto t2 = std::chrono::high_resolution_clock::now();
+      std::chrono::duration<double, std::micro> delta_us = t2 - t1;
+      total_gain_buffer_us += delta_us.count();
+    }
+    CHECK_EQ(error, 0);
+
+    {
+      ATRACE_NAME("PostBuffer");
+      auto t1 = std::chrono::high_resolution_clock::now();
+      error = ANativeWindow_unlockAndPost(window);
+      auto t2 = std::chrono::high_resolution_clock::now();
+      std::chrono::duration<double, std::micro> delta_us = t2 - t1;
+      total_post_buffer_us += delta_us.count();
+    }
+    CHECK_EQ(error, 0);
+
+    iterations++;
+  }
+
+  state.counters["gain_buffer_us"] = ::benchmark::Counter(
+      total_gain_buffer_us / iterations, ::benchmark::Counter::kAvgThreads);
+  state.counters["post_buffer_us"] = ::benchmark::Counter(
+      total_post_buffer_us / iterations, ::benchmark::Counter::kAvgThreads);
+  state.counters["producer_us"] = ::benchmark::Counter(
+      (total_gain_buffer_us + total_post_buffer_us) / iterations,
+      ::benchmark::Counter::kAvgThreads);
+}
+
+BENCHMARK_REGISTER_F(BufferTransportBenchmark, Producers)
+    ->Unit(::benchmark::kMicrosecond)
+    ->Ranges({{kBinderBufferTransport, kBufferHubTransport}})
+    ->ThreadRange(1, 32);
+
+static void runBinderServer() {
+  ProcessState::self()->setThreadPoolMaxThreadCount(0);
+  ProcessState::self()->startThreadPool();
+
+  sp<IServiceManager> sm = defaultServiceManager();
+  sp<BufferTransportService> service = new BufferTransportService;
+  sm->addService(kBinderService, service, false);
+
+  LOG(INFO) << "Binder server running...";
+
+  while (true) {
+    int stat, retval;
+    retval = wait(&stat);
+    if (retval == -1 && errno == ECHILD) {
+      break;
+    }
+  }
+
+  LOG(INFO) << "Service Exiting...";
+}
+
+// To run binder-based benchmark, use:
+// adb shell buffer_transport_benchmark \
+//   --benchmark_filter="BufferTransportBenchmark/ContinuousLoad/0/"
+//
+// To run bufferhub-based benchmark, use:
+// adb shell buffer_transport_benchmark \
+//   --benchmark_filter="BufferTransportBenchmark/ContinuousLoad/1/"
+int main(int argc, char** argv) {
+  bool tracing_enabled = false;
+
+  // Parse arguments in addition to "--benchmark_filter" paramters.
+  for (int i = 1; i < argc; i++) {
+    if (std::string(argv[i]) == "--help") {
+      std::cout << "Usage: binderThroughputTest [OPTIONS]" << std::endl;
+      std::cout << "\t--trace: Enable systrace logging." << std::endl;
+      return 0;
+    }
+    if (std::string(argv[i]) == "--trace") {
+      tracing_enabled = true;
+      continue;
+    }
+  }
+
+  // Setup ATRACE/systrace based on command line.
+  atrace_setup();
+  atrace_set_tracing_enabled(tracing_enabled);
+
+  pid_t pid = fork();
+  if (pid == 0) {
+    // Child, i.e. the client side.
+    ProcessState::self()->startThreadPool();
+
+    ::benchmark::Initialize(&argc, argv);
+    ::benchmark::RunSpecifiedBenchmarks();
+  } else {
+    LOG(INFO) << "Benchmark process pid: " << pid;
+    runBinderServer();
+  }
+}
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
index 8bea0cd..8feb1cd 100644
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
+++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
@@ -31,20 +31,6 @@
 
 namespace {
 
-// Polls an fd for the given events.
-Status<int> PollEvents(int fd, short events) {
-  const int kTimeoutMs = 0;
-  pollfd pfd{fd, events, 0};
-  const int count = RETRY_EINTR(poll(&pfd, 1, kTimeoutMs));
-  if (count < 0) {
-    return ErrorStatus(errno);
-  } else if (count == 0) {
-    return ErrorStatus(ETIMEDOUT);
-  } else {
-    return {pfd.revents};
-  }
-}
-
 std::pair<int32_t, int32_t> Unstuff(uint64_t value) {
   return {static_cast<int32_t>(value >> 32),
           static_cast<int32_t>(value & ((1ull << 32) - 1))};
@@ -137,6 +123,28 @@
   return status;
 }
 
+pdx::Status<ConsumerQueueParcelable>
+BufferHubQueue::CreateConsumerQueueParcelable(bool silent) {
+  auto status = CreateConsumerQueueHandle(silent);
+  if (!status)
+    return status.error_status();
+
+  // A temporary consumer queue client to pull its channel parcelable.
+  auto consumer_queue =
+      std::unique_ptr<ConsumerQueue>(new ConsumerQueue(status.take()));
+  ConsumerQueueParcelable queue_parcelable(
+      consumer_queue->GetChannel()->TakeChannelParcelable());
+
+  if (!queue_parcelable.IsValid()) {
+    ALOGE(
+        "BufferHubQueue::CreateConsumerQueueParcelable: Failed to create "
+        "consumer queue parcelable.");
+    return ErrorStatus(EINVAL);
+  }
+
+  return {std::move(queue_parcelable)};
+}
+
 bool BufferHubQueue::WaitForBuffers(int timeout) {
   ATRACE_NAME("BufferHubQueue::WaitForBuffers");
   std::array<epoll_event, kMaxEvents> events;
@@ -555,6 +563,31 @@
   return {std::move(buffer)};
 }
 
+pdx::Status<ProducerQueueParcelable> ProducerQueue::TakeAsParcelable() {
+  if (capacity() != 0) {
+    ALOGE(
+        "ProducerQueue::TakeAsParcelable: producer queue can only be taken out"
+        " as a parcelable when empty. Current queue capacity: %zu",
+        capacity());
+    return ErrorStatus(EINVAL);
+  }
+
+  std::unique_ptr<pdx::ClientChannel> channel = TakeChannel();
+  ProducerQueueParcelable queue_parcelable(channel->TakeChannelParcelable());
+
+  // Here the queue parcelable is returned and holds the underlying system
+  // resources backing the queue; while the original client channel of this
+  // producer queue is destroyed in place so that this client can no longer
+  // provide producer operations.
+  return {std::move(queue_parcelable)};
+}
+
+/*static */
+std::unique_ptr<ConsumerQueue> ConsumerQueue::Import(
+    LocalChannelHandle handle) {
+  return std::unique_ptr<ConsumerQueue>(new ConsumerQueue(std::move(handle)));
+}
+
 ConsumerQueue::ConsumerQueue(LocalChannelHandle handle)
     : BufferHubQueue(std::move(handle)) {
   auto status = ImportQueue();
@@ -629,27 +662,7 @@
     const std::shared_ptr<BufferConsumer>& buffer, size_t slot) {
   ALOGD_IF(TRACE, "ConsumerQueue::AddBuffer: queue_id=%d buffer_id=%d slot=%zu",
            id(), buffer->id(), slot);
-  auto status = BufferHubQueue::AddBuffer(buffer, slot);
-  if (!status)
-    return status;
-
-  // Check to see if the buffer is already signaled. This is necessary to catch
-  // cases where buffers are already available; epoll edge triggered mode does
-  // not fire until an edge transition when adding new buffers to the epoll
-  // set. Note that we only poll the fd events because HandleBufferEvent() takes
-  // care of checking the translated buffer events.
-  auto poll_status = PollEvents(buffer->event_fd(), POLLIN);
-  if (!poll_status && poll_status.error() != ETIMEDOUT) {
-    ALOGE("ConsumerQueue::AddBuffer: Failed to poll consumer buffer: %s",
-          poll_status.GetErrorMessage().c_str());
-    return poll_status.error_status();
-  }
-
-  // Update accounting if the buffer is available.
-  if (poll_status)
-    return HandleBufferEvent(slot, buffer->event_fd(), poll_status.get());
-  else
-    return {};
+  return BufferHubQueue::AddBuffer(buffer, slot);
 }
 
 Status<std::shared_ptr<BufferConsumer>> ConsumerQueue::Dequeue(
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_parcelable.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_parcelable.cpp
new file mode 100644
index 0000000..2cd7c45
--- /dev/null
+++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_parcelable.cpp
@@ -0,0 +1,82 @@
+#include "include/private/dvr/buffer_hub_queue_parcelable.h"
+
+#include <binder/Parcel.h>
+#include <pdx/default_transport/channel_parcelable.h>
+
+namespace android {
+namespace dvr {
+
+template <BufferHubQueueParcelableMagic Magic>
+bool BufferHubQueueParcelable<Magic>::IsValid() const {
+  return !!channel_parcelable_ && channel_parcelable_->IsValid();
+}
+
+template <BufferHubQueueParcelableMagic Magic>
+pdx::LocalChannelHandle BufferHubQueueParcelable<Magic>::TakeChannelHandle() {
+  if (!IsValid()) {
+    ALOGE(
+        "BufferHubQueueParcelable::TakeChannelHandle: Invalid channel parcel.");
+    return {};  // Returns an empty channel handle.
+  }
+
+  // Take channel handle out of the parcelable and reset the parcelable.
+  pdx::LocalChannelHandle handle = channel_parcelable_->TakeChannelHandle();
+  // Now channel_parcelable_ should already be invalid, but reset it to release
+  // the invalid parcelable object from unique_ptr.
+  channel_parcelable_ = nullptr;
+  return handle;
+}
+
+template <BufferHubQueueParcelableMagic Magic>
+status_t BufferHubQueueParcelable<Magic>::writeToParcel(Parcel* parcel) const {
+  if (!IsValid()) {
+    ALOGE("BufferHubQueueParcelable::writeToParcel: Invalid channel.");
+    return -EINVAL;
+  }
+
+  status_t res = parcel->writeUint32(Magic);
+  if (res != NO_ERROR) {
+    ALOGE("BufferHubQueueParcelable::writeToParcel: Cannot write magic.");
+    return res;
+  }
+
+  return channel_parcelable_->writeToParcel(parcel);
+}
+
+template <BufferHubQueueParcelableMagic Magic>
+status_t BufferHubQueueParcelable<Magic>::readFromParcel(const Parcel* parcel) {
+  if (IsValid()) {
+    ALOGE(
+        "BufferHubQueueParcelable::readFromParcel: This parcelable object has "
+        "been initialized already.");
+    return -EINVAL;
+  }
+
+  uint32_t out_magic = 0;
+  status_t res = NO_ERROR;
+
+  res = parcel->readUint32(&out_magic);
+  if (res != NO_ERROR)
+    return res;
+
+  if (out_magic != Magic) {
+    ALOGE(
+        "BufferHubQueueParcelable::readFromParcel: Unexpected magic: 0x%x, "
+        "epxected: 0x%x",
+        out_magic, Magic);
+    return -EINVAL;
+  }
+
+  // (Re)Alocate channel parcelable object.
+  channel_parcelable_ =
+      std::make_unique<pdx::default_transport::ChannelParcelable>();
+  return channel_parcelable_->readFromParcel(parcel);
+}
+
+template class BufferHubQueueParcelable<
+    BufferHubQueueParcelableMagic::Producer>;
+template class BufferHubQueueParcelable<
+    BufferHubQueueParcelableMagic::Consumer>;
+
+}  // namespace dvr
+}  // namespace android
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp
deleted file mode 100644
index 221bc4f..0000000
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp
+++ /dev/null
@@ -1,686 +0,0 @@
-#include "include/private/dvr/buffer_hub_queue_producer.h"
-
-#include <dvr/dvr_api.h>
-#include <inttypes.h>
-#include <log/log.h>
-#include <system/window.h>
-
-namespace android {
-namespace dvr {
-
-/* static */
-sp<BufferHubQueueProducer> BufferHubQueueProducer::Create() {
-  sp<BufferHubQueueProducer> producer = new BufferHubQueueProducer;
-  auto config = ProducerQueueConfigBuilder()
-                    .SetMetadata<DvrNativeBufferMetadata>()
-                    .Build();
-  producer->queue_ = ProducerQueue::Create(config, UsagePolicy{});
-  return producer;
-}
-
-/* static */
-sp<BufferHubQueueProducer> BufferHubQueueProducer::Create(
-    const std::shared_ptr<ProducerQueue>& queue) {
-  if (queue->metadata_size() != sizeof(DvrNativeBufferMetadata)) {
-    ALOGE(
-        "BufferHubQueueProducer::Create producer's metadata size is different "
-        "than the size of DvrNativeBufferMetadata");
-    return nullptr;
-  }
-
-  sp<BufferHubQueueProducer> producer = new BufferHubQueueProducer;
-  producer->queue_ = queue;
-  return producer;
-}
-
-status_t BufferHubQueueProducer::requestBuffer(int slot,
-                                               sp<GraphicBuffer>* buf) {
-  ALOGD_IF(TRACE, "requestBuffer: slot=%d", slot);
-
-  std::unique_lock<std::mutex> lock(mutex_);
-
-  if (connected_api_ == kNoConnectedApi) {
-    ALOGE("requestBuffer: BufferHubQueueProducer has no connected producer");
-    return NO_INIT;
-  }
-
-  if (slot < 0 || slot >= max_buffer_count_) {
-    ALOGE("requestBuffer: slot index %d out of range [0, %d)", slot,
-          max_buffer_count_);
-    return BAD_VALUE;
-  } else if (!buffers_[slot].mBufferState.isDequeued()) {
-    ALOGE("requestBuffer: slot %d is not owned by the producer (state = %s)",
-          slot, buffers_[slot].mBufferState.string());
-    return BAD_VALUE;
-  } else if (buffers_[slot].mGraphicBuffer != nullptr) {
-    ALOGE("requestBuffer: slot %d is not empty.", slot);
-    return BAD_VALUE;
-  } else if (buffers_[slot].mBufferProducer == nullptr) {
-    ALOGE("requestBuffer: slot %d is not dequeued.", slot);
-    return BAD_VALUE;
-  }
-
-  const auto& buffer_producer = buffers_[slot].mBufferProducer;
-  sp<GraphicBuffer> graphic_buffer = buffer_producer->buffer()->buffer();
-
-  buffers_[slot].mGraphicBuffer = graphic_buffer;
-  buffers_[slot].mRequestBufferCalled = true;
-
-  *buf = graphic_buffer;
-  return NO_ERROR;
-}
-
-status_t BufferHubQueueProducer::setMaxDequeuedBufferCount(
-    int max_dequeued_buffers) {
-  ALOGD_IF(TRACE, "setMaxDequeuedBufferCount: max_dequeued_buffers=%d",
-           max_dequeued_buffers);
-
-  std::unique_lock<std::mutex> lock(mutex_);
-
-  if (max_dequeued_buffers <= 0 ||
-      max_dequeued_buffers >
-          static_cast<int>(BufferHubQueue::kMaxQueueCapacity -
-                           kDefaultUndequeuedBuffers)) {
-    ALOGE("setMaxDequeuedBufferCount: %d out of range (0, %zu]",
-          max_dequeued_buffers, BufferHubQueue::kMaxQueueCapacity);
-    return BAD_VALUE;
-  }
-
-  // The new dequeued_buffers count should not be violated by the number
-  // of currently dequeued buffers.
-  int dequeued_count = 0;
-  for (const auto& buf : buffers_) {
-    if (buf.mBufferState.isDequeued()) {
-      dequeued_count++;
-    }
-  }
-  if (dequeued_count > max_dequeued_buffers) {
-    ALOGE(
-        "setMaxDequeuedBufferCount: the requested dequeued_buffers"
-        "count (%d) exceeds the current dequeued buffer count (%d)",
-        max_dequeued_buffers, dequeued_count);
-    return BAD_VALUE;
-  }
-
-  max_dequeued_buffer_count_ = max_dequeued_buffers;
-  return NO_ERROR;
-}
-
-status_t BufferHubQueueProducer::setAsyncMode(bool async) {
-  if (async) {
-    // TODO(b/36724099) BufferHubQueue's consumer end always acquires the buffer
-    // automatically and behaves differently from IGraphicBufferConsumer. Thus,
-    // android::BufferQueue's async mode (a.k.a. allocating an additional buffer
-    // to prevent dequeueBuffer from being blocking) technically does not apply
-    // here.
-    //
-    // In Daydream, non-blocking producer side dequeue is guaranteed by careful
-    // buffer consumer implementations. In another word, BufferHubQueue based
-    // dequeueBuffer should never block whether setAsyncMode(true) is set or
-    // not.
-    //
-    // See: IGraphicBufferProducer::setAsyncMode and
-    // BufferQueueProducer::setAsyncMode for more about original implementation.
-    ALOGW(
-        "BufferHubQueueProducer::setAsyncMode: BufferHubQueue should always be "
-        "asynchronous. This call makes no effact.");
-    return NO_ERROR;
-  }
-  return NO_ERROR;
-}
-
-status_t BufferHubQueueProducer::dequeueBuffer(
-    int* out_slot, sp<Fence>* out_fence, uint32_t width, uint32_t height,
-    PixelFormat format, uint64_t usage, uint64_t* /*outBufferAge*/,
-    FrameEventHistoryDelta* /* out_timestamps */) {
-  ALOGD_IF(TRACE, "dequeueBuffer: w=%u, h=%u, format=%d, usage=%" PRIu64, width,
-           height, format, usage);
-
-  status_t ret;
-  std::unique_lock<std::mutex> lock(mutex_);
-
-  if (connected_api_ == kNoConnectedApi) {
-    ALOGE("dequeueBuffer: BufferQueue has no connected producer");
-    return NO_INIT;
-  }
-
-  const uint32_t kLayerCount = 1;
-  if (static_cast<int32_t>(queue_->capacity()) <
-      max_dequeued_buffer_count_ + kDefaultUndequeuedBuffers) {
-    // Lazy allocation. When the capacity of |queue_| has not reached
-    // |max_dequeued_buffer_count_|, allocate new buffer.
-    // TODO(jwcai) To save memory, the really reasonable thing to do is to go
-    // over existing slots and find first existing one to dequeue.
-    ret = AllocateBuffer(width, height, kLayerCount, format, usage);
-    if (ret < 0)
-      return ret;
-  }
-
-  size_t slot;
-  std::shared_ptr<BufferProducer> buffer_producer;
-
-  for (size_t retry = 0; retry < BufferHubQueue::kMaxQueueCapacity; retry++) {
-    LocalHandle fence;
-    auto buffer_status = queue_->Dequeue(dequeue_timeout_ms_, &slot, &fence);
-    if (!buffer_status)
-      return NO_MEMORY;
-
-    buffer_producer = buffer_status.take();
-    if (!buffer_producer)
-      return NO_MEMORY;
-
-    if (width == buffer_producer->width() &&
-        height == buffer_producer->height() &&
-        static_cast<uint32_t>(format) == buffer_producer->format()) {
-      // The producer queue returns a buffer producer matches the request.
-      break;
-    }
-
-    // Needs reallocation.
-    // TODO(jwcai) Consider use VLOG instead if we find this log is not useful.
-    ALOGI(
-        "dequeueBuffer: requested buffer (w=%u, h=%u, format=%u) is different "
-        "from the buffer returned at slot: %zu (w=%u, h=%u, format=%u). Need "
-        "re-allocattion.",
-        width, height, format, slot, buffer_producer->width(),
-        buffer_producer->height(), buffer_producer->format());
-    // Mark the slot as reallocating, so that later we can set
-    // BUFFER_NEEDS_REALLOCATION when the buffer actually get dequeued.
-    buffers_[slot].mIsReallocating = true;
-
-    // Remove the old buffer once the allocation before allocating its
-    // replacement.
-    RemoveBuffer(slot);
-
-    // Allocate a new producer buffer with new buffer configs. Note that if
-    // there are already multiple buffers in the queue, the next one returned
-    // from |queue_->Dequeue| may not be the new buffer we just reallocated.
-    // Retry up to BufferHubQueue::kMaxQueueCapacity times.
-    ret = AllocateBuffer(width, height, kLayerCount, format, usage);
-    if (ret < 0)
-      return ret;
-  }
-
-  // With the BufferHub backed solution. Buffer slot returned from
-  // |queue_->Dequeue| is guaranteed to avaiable for producer's use.
-  // It's either in free state (if the buffer has never been used before) or
-  // in queued state (if the buffer has been dequeued and queued back to
-  // BufferHubQueue).
-  LOG_ALWAYS_FATAL_IF(
-      (!buffers_[slot].mBufferState.isFree() &&
-       !buffers_[slot].mBufferState.isQueued()),
-      "dequeueBuffer: slot %zu is not free or queued, actual state: %s.", slot,
-      buffers_[slot].mBufferState.string());
-
-  buffers_[slot].mBufferState.freeQueued();
-  buffers_[slot].mBufferState.dequeue();
-  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.
-  *out_fence = Fence::NO_FENCE;
-  *out_slot = slot;
-  ret = NO_ERROR;
-
-  if (buffers_[slot].mIsReallocating) {
-    ret |= BUFFER_NEEDS_REALLOCATION;
-    buffers_[slot].mIsReallocating = false;
-  }
-
-  return ret;
-}
-
-status_t BufferHubQueueProducer::detachBuffer(int /* slot */) {
-  ALOGE("BufferHubQueueProducer::detachBuffer not implemented.");
-  return INVALID_OPERATION;
-}
-
-status_t BufferHubQueueProducer::detachNextBuffer(
-    sp<GraphicBuffer>* /* out_buffer */, sp<Fence>* /* out_fence */) {
-  ALOGE("BufferHubQueueProducer::detachNextBuffer not implemented.");
-  return INVALID_OPERATION;
-}
-
-status_t BufferHubQueueProducer::attachBuffer(
-    int* /* out_slot */, const sp<GraphicBuffer>& /* buffer */) {
-  // With this BufferHub backed implementation, we assume (for now) all buffers
-  // are allocated and owned by the BufferHub. Thus the attempt of transfering
-  // ownership of a buffer to the buffer queue is intentionally unsupported.
-  LOG_ALWAYS_FATAL("BufferHubQueueProducer::attachBuffer not supported.");
-  return INVALID_OPERATION;
-}
-
-status_t BufferHubQueueProducer::queueBuffer(int slot,
-                                             const QueueBufferInput& input,
-                                             QueueBufferOutput* output) {
-  ALOGD_IF(TRACE, "queueBuffer: slot %d", slot);
-
-  if (output == nullptr) {
-    return BAD_VALUE;
-  }
-
-  int64_t timestamp;
-  bool is_auto_timestamp;
-  android_dataspace dataspace;
-  Rect crop(Rect::EMPTY_RECT);
-  int scaling_mode;
-  uint32_t transform;
-  sp<Fence> fence;
-
-  input.deflate(&timestamp, &is_auto_timestamp, &dataspace, &crop,
-                &scaling_mode, &transform, &fence);
-
-  // Check input scaling mode is valid.
-  switch (scaling_mode) {
-    case NATIVE_WINDOW_SCALING_MODE_FREEZE:
-    case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW:
-    case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP:
-    case NATIVE_WINDOW_SCALING_MODE_NO_SCALE_CROP:
-      break;
-    default:
-      ALOGE("queueBuffer: unknown scaling mode %d", scaling_mode);
-      return BAD_VALUE;
-  }
-
-  // Check input fence is valid.
-  if (fence == nullptr) {
-    ALOGE("queueBuffer: fence is NULL");
-    return BAD_VALUE;
-  }
-
-  status_t ret;
-  std::unique_lock<std::mutex> lock(mutex_);
-
-  if (connected_api_ == kNoConnectedApi) {
-    ALOGE("queueBuffer: BufferQueue has no connected producer");
-    return NO_INIT;
-  }
-
-  if (slot < 0 || slot >= max_buffer_count_) {
-    ALOGE("queueBuffer: slot index %d out of range [0, %d)", slot,
-          max_buffer_count_);
-    return BAD_VALUE;
-  } else if (!buffers_[slot].mBufferState.isDequeued()) {
-    ALOGE("queueBuffer: slot %d is not owned by the producer (state = %s)",
-          slot, buffers_[slot].mBufferState.string());
-    return BAD_VALUE;
-  } else if ((!buffers_[slot].mRequestBufferCalled ||
-              buffers_[slot].mGraphicBuffer == nullptr)) {
-    ALOGE(
-        "queueBuffer: slot %d is not requested (mRequestBufferCalled=%d, "
-        "mGraphicBuffer=%p)",
-        slot, buffers_[slot].mRequestBufferCalled,
-        buffers_[slot].mGraphicBuffer.get());
-    return BAD_VALUE;
-  }
-
-  // Post the buffer producer with timestamp in the metadata.
-  const auto& buffer_producer = buffers_[slot].mBufferProducer;
-
-  // Check input crop is not out of boundary of current buffer.
-  Rect buffer_rect(buffer_producer->width(), buffer_producer->height());
-  Rect cropped_rect(Rect::EMPTY_RECT);
-  crop.intersect(buffer_rect, &cropped_rect);
-  if (cropped_rect != crop) {
-    ALOGE("queueBuffer: slot %d has out-of-boundary crop.", slot);
-    return BAD_VALUE;
-  }
-
-  LocalHandle fence_fd(fence->isValid() ? fence->dup() : -1);
-
-  DvrNativeBufferMetadata meta_data;
-  meta_data.timestamp = timestamp;
-  meta_data.is_auto_timestamp = static_cast<int32_t>(is_auto_timestamp);
-  meta_data.dataspace = static_cast<int32_t>(dataspace);
-  meta_data.crop_left = crop.left;
-  meta_data.crop_top = crop.top;
-  meta_data.crop_right = crop.right;
-  meta_data.crop_bottom = crop.bottom;
-  meta_data.scaling_mode = static_cast<int32_t>(scaling_mode);
-  meta_data.transform = static_cast<int32_t>(transform);
-
-  buffer_producer->PostAsync(&meta_data, fence_fd);
-  buffers_[slot].mBufferState.queue();
-
-  output->width = buffer_producer->width();
-  output->height = buffer_producer->height();
-  output->transformHint = 0;  // default value, we don't use it yet.
-
-  // |numPendingBuffers| counts of the number of buffers that has been enqueued
-  // by the producer but not yet acquired by the consumer. Due to the nature
-  // of BufferHubQueue design, this is hard to trace from the producer's client
-  // side, but it's safe to assume it's zero.
-  output->numPendingBuffers = 0;
-
-  // Note that we are not setting nextFrameNumber here as it seems to be only
-  // used by surface flinger. See more at b/22802885, ag/791760.
-  output->nextFrameNumber = 0;
-
-  return NO_ERROR;
-}
-
-status_t BufferHubQueueProducer::cancelBuffer(int slot,
-                                              const sp<Fence>& fence) {
-  ALOGD_IF(TRACE, __FUNCTION__);
-
-  std::unique_lock<std::mutex> lock(mutex_);
-
-  if (connected_api_ == kNoConnectedApi) {
-    ALOGE("cancelBuffer: BufferQueue has no connected producer");
-    return NO_INIT;
-  }
-
-  if (slot < 0 || slot >= max_buffer_count_) {
-    ALOGE("cancelBuffer: slot index %d out of range [0, %d)", slot,
-          max_buffer_count_);
-    return BAD_VALUE;
-  } else if (!buffers_[slot].mBufferState.isDequeued()) {
-    ALOGE("cancelBuffer: slot %d is not owned by the producer (state = %s)",
-          slot, buffers_[slot].mBufferState.string());
-    return BAD_VALUE;
-  } else if (fence == nullptr) {
-    ALOGE("cancelBuffer: fence is NULL");
-    return BAD_VALUE;
-  }
-
-  auto buffer_producer = buffers_[slot].mBufferProducer;
-  queue_->Enqueue(buffer_producer, slot, 0ULL);
-  buffers_[slot].mBufferState.cancel();
-  buffers_[slot].mFence = fence;
-  ALOGD_IF(TRACE, "cancelBuffer: slot %d", slot);
-
-  return NO_ERROR;
-}
-
-status_t BufferHubQueueProducer::query(int what, int* out_value) {
-  ALOGD_IF(TRACE, __FUNCTION__);
-
-  std::unique_lock<std::mutex> lock(mutex_);
-
-  if (out_value == nullptr) {
-    ALOGE("query: out_value was NULL");
-    return BAD_VALUE;
-  }
-
-  int value = 0;
-  switch (what) {
-    case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
-      // TODO(b/36187402) This should be the maximum number of buffers that this
-      // producer queue's consumer can acquire. Set to be at least one. Need to
-      // find a way to set from the consumer side.
-      value = kDefaultUndequeuedBuffers;
-      break;
-    case NATIVE_WINDOW_BUFFER_AGE:
-      value = 0;
-      break;
-    case NATIVE_WINDOW_WIDTH:
-      value = queue_->default_width();
-      break;
-    case NATIVE_WINDOW_HEIGHT:
-      value = queue_->default_height();
-      break;
-    case NATIVE_WINDOW_FORMAT:
-      value = queue_->default_format();
-      break;
-    case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND:
-      // BufferHubQueue is always operating in async mode, thus semantically
-      // consumer can never be running behind. See BufferQueueCore.cpp core
-      // for more information about the original meaning of this flag.
-      value = 0;
-      break;
-    case NATIVE_WINDOW_CONSUMER_USAGE_BITS:
-      // TODO(jwcai) This is currently not implement as we don't need
-      // IGraphicBufferConsumer parity.
-      value = 0;
-      break;
-    case NATIVE_WINDOW_DEFAULT_DATASPACE:
-      // TODO(jwcai) Return the default value android::BufferQueue is using as
-      // there is no way dvr::ConsumerQueue can set it.
-      value = 0;  // HAL_DATASPACE_UNKNOWN
-      break;
-    case NATIVE_WINDOW_STICKY_TRANSFORM:
-      // TODO(jwcai) Return the default value android::BufferQueue is using as
-      // there is no way dvr::ConsumerQueue can set it.
-      value = 0;
-      break;
-    case NATIVE_WINDOW_CONSUMER_IS_PROTECTED:
-      // In Daydream's implementation, the consumer end (i.e. VR Compostior)
-      // knows how to handle protected buffers.
-      value = 1;
-      break;
-    default:
-      return BAD_VALUE;
-  }
-
-  ALOGD_IF(TRACE, "query: key=%d, v=%d", what, value);
-  *out_value = value;
-  return NO_ERROR;
-}
-
-status_t BufferHubQueueProducer::connect(
-    const sp<IProducerListener>& /* listener */, int api,
-    bool /* producer_controlled_by_app */, QueueBufferOutput* output) {
-  // Consumer interaction are actually handled by buffer hub, and we need
-  // to maintain consumer operations here. We only need to perform basic input
-  // parameter checks here.
-  ALOGD_IF(TRACE, __FUNCTION__);
-
-  if (output == nullptr) {
-    return BAD_VALUE;
-  }
-
-  std::unique_lock<std::mutex> lock(mutex_);
-
-  if (connected_api_ != kNoConnectedApi) {
-    return BAD_VALUE;
-  }
-
-  switch (api) {
-    case NATIVE_WINDOW_API_EGL:
-    case NATIVE_WINDOW_API_CPU:
-    case NATIVE_WINDOW_API_MEDIA:
-    case NATIVE_WINDOW_API_CAMERA:
-      connected_api_ = api;
-
-      output->width = queue_->default_width();
-      output->height = queue_->default_height();
-
-      // default values, we don't use them yet.
-      output->transformHint = 0;
-      output->numPendingBuffers = 0;
-      output->nextFrameNumber = 0;
-      output->bufferReplaced = false;
-
-      break;
-    default:
-      ALOGE("BufferHubQueueProducer::connect: unknow API %d", api);
-      return BAD_VALUE;
-  }
-
-  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.  We only need to perform basic input
-  // parameter checks here.
-  ALOGD_IF(TRACE, __FUNCTION__);
-
-  std::unique_lock<std::mutex> lock(mutex_);
-
-  if (kNoConnectedApi == connected_api_) {
-    return NO_INIT;
-  } else if (api != connected_api_) {
-    return BAD_VALUE;
-  }
-
-  FreeAllBuffers();
-  connected_api_ = kNoConnectedApi;
-  return NO_ERROR;
-}
-
-status_t BufferHubQueueProducer::setSidebandStream(
-    const sp<NativeHandle>& stream) {
-  if (stream != nullptr) {
-    // TODO(jwcai) Investigate how is is used, maybe use BufferHubBuffer's
-    // metadata.
-    ALOGE("SidebandStream is not currently supported.");
-    return INVALID_OPERATION;
-  }
-  return NO_ERROR;
-}
-
-void BufferHubQueueProducer::allocateBuffers(uint32_t /* width */,
-                                             uint32_t /* height */,
-                                             PixelFormat /* format */,
-                                             uint64_t /* usage */) {
-  // TODO(jwcai) |allocateBuffers| aims to preallocate up to the maximum number
-  // of buffers permitted by the current BufferQueue configuration (aka
-  // |max_buffer_count_|).
-  ALOGE("BufferHubQueueProducer::allocateBuffers not implemented.");
-}
-
-status_t BufferHubQueueProducer::allowAllocation(bool /* allow */) {
-  ALOGE("BufferHubQueueProducer::allowAllocation not implemented.");
-  return INVALID_OPERATION;
-}
-
-status_t BufferHubQueueProducer::setGenerationNumber(
-    uint32_t generation_number) {
-  ALOGD_IF(TRACE, __FUNCTION__);
-
-  std::unique_lock<std::mutex> lock(mutex_);
-  generation_number_ = generation_number;
-  return NO_ERROR;
-}
-
-String8 BufferHubQueueProducer::getConsumerName() const {
-  // BufferHub based implementation could have one to many producer/consumer
-  // relationship, thus |getConsumerName| from the producer side does not
-  // make any sense.
-  ALOGE("BufferHubQueueProducer::getConsumerName not supported.");
-  return String8("BufferHubQueue::DummyConsumer");
-}
-
-status_t BufferHubQueueProducer::setSharedBufferMode(bool shared_buffer_mode) {
-  if (shared_buffer_mode) {
-    ALOGE(
-        "BufferHubQueueProducer::setSharedBufferMode(true) is not supported.");
-    // TODO(b/36373181) Front buffer mode for buffer hub queue as ANativeWindow.
-    return INVALID_OPERATION;
-  }
-  // Setting to default should just work as a no-op.
-  return NO_ERROR;
-}
-
-status_t BufferHubQueueProducer::setAutoRefresh(bool auto_refresh) {
-  if (auto_refresh) {
-    ALOGE("BufferHubQueueProducer::setAutoRefresh(true) is not supported.");
-    return INVALID_OPERATION;
-  }
-  // Setting to default should just work as a no-op.
-  return NO_ERROR;
-}
-
-status_t BufferHubQueueProducer::setDequeueTimeout(nsecs_t timeout) {
-  ALOGD_IF(TRACE, __FUNCTION__);
-
-  std::unique_lock<std::mutex> lock(mutex_);
-  dequeue_timeout_ms_ = static_cast<int>(timeout / (1000 * 1000));
-  return NO_ERROR;
-}
-
-status_t BufferHubQueueProducer::getLastQueuedBuffer(
-    sp<GraphicBuffer>* /* out_buffer */, sp<Fence>* /* out_fence */,
-    float /*out_transform_matrix*/[16]) {
-  ALOGE("BufferHubQueueProducer::getLastQueuedBuffer not implemented.");
-  return INVALID_OPERATION;
-}
-
-void BufferHubQueueProducer::getFrameTimestamps(
-    FrameEventHistoryDelta* /*outDelta*/) {
-  ALOGE("BufferHubQueueProducer::getFrameTimestamps not implemented.");
-}
-
-status_t BufferHubQueueProducer::getUniqueId(uint64_t* out_id) const {
-  ALOGD_IF(TRACE, __FUNCTION__);
-
-  *out_id = unique_id_;
-  return NO_ERROR;
-}
-
-status_t BufferHubQueueProducer::getConsumerUsage(uint64_t* out_usage) const {
-  ALOGD_IF(TRACE, __FUNCTION__);
-
-  // same value as returned by querying NATIVE_WINDOW_CONSUMER_USAGE_BITS
-  *out_usage = 0;
-  return NO_ERROR;
-}
-
-status_t BufferHubQueueProducer::AllocateBuffer(uint32_t width, uint32_t height,
-                                                uint32_t layer_count,
-                                                PixelFormat format,
-                                                uint64_t usage) {
-  auto status =
-      queue_->AllocateBuffer(width, height, layer_count, format, usage);
-  if (!status) {
-    ALOGE(
-        "BufferHubQueueProducer::AllocateBuffer: Failed to allocate buffer: %s",
-        status.GetErrorMessage().c_str());
-    return NO_MEMORY;
-  }
-
-  size_t slot = status.get();
-  auto buffer_producer = queue_->GetBuffer(slot);
-
-  LOG_ALWAYS_FATAL_IF(buffer_producer == nullptr,
-                      "Failed to get buffer producer at slot: %zu", slot);
-
-  buffers_[slot].mBufferProducer = buffer_producer;
-
-  return NO_ERROR;
-}
-
-status_t BufferHubQueueProducer::RemoveBuffer(size_t slot) {
-  auto status = queue_->RemoveBuffer(slot);
-  if (!status) {
-    ALOGE("BufferHubQueueProducer::RemoveBuffer: Failed to remove buffer: %s",
-          status.GetErrorMessage().c_str());
-    return INVALID_OPERATION;
-  }
-
-  // Reset in memory objects related the the buffer.
-  buffers_[slot].mBufferProducer = nullptr;
-  buffers_[slot].mGraphicBuffer = nullptr;
-  buffers_[slot].mBufferState.detachProducer();
-  return NO_ERROR;
-}
-
-status_t BufferHubQueueProducer::FreeAllBuffers() {
-  for (size_t slot = 0; slot < BufferHubQueue::kMaxQueueCapacity; slot++) {
-    // Reset in memory objects related the the buffer.
-    buffers_[slot].mGraphicBuffer = nullptr;
-    buffers_[slot].mBufferState.reset();
-    buffers_[slot].mRequestBufferCalled = false;
-    buffers_[slot].mBufferProducer = nullptr;
-    buffers_[slot].mFence = Fence::NO_FENCE;
-  }
-
-  auto status = queue_->FreeAllBuffers();
-  if (!status) {
-    ALOGE(
-        "BufferHubQueueProducer::FreeAllBuffers: Failed to free all buffers on "
-        "the queue: %s",
-        status.GetErrorMessage().c_str());
-  }
-
-  if (queue_->capacity() != 0 || queue_->count() != 0) {
-    LOG_ALWAYS_FATAL(
-        "BufferHubQueueProducer::FreeAllBuffers: Not all buffers are freed.");
-  }
-
-  return NO_ERROR;
-}
-
-}  // namespace dvr
-}  // namespace android
diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
index 6962d6c..60e1c4b 100644
--- a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
+++ b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
@@ -1,14 +1,26 @@
 #ifndef ANDROID_DVR_BUFFER_HUB_QUEUE_CLIENT_H_
 #define ANDROID_DVR_BUFFER_HUB_QUEUE_CLIENT_H_
 
-#include <gui/BufferQueueDefs.h>
+#include <ui/BufferQueueDefs.h>
 
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Weverything"
+#endif
+
+// The following headers are included without checking every warning.
+// TODO(b/72172820): Remove the workaround once we have enforced -Weverything
+// in these headers and their dependencies.
 #include <pdx/client.h>
 #include <pdx/status.h>
 #include <private/dvr/buffer_hub_client.h>
+#include <private/dvr/buffer_hub_queue_parcelable.h>
 #include <private/dvr/bufferhub_rpc.h>
 #include <private/dvr/epoll_file_descriptor.h>
-#include <private/dvr/ring_buffer.h>
+
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
 
 #include <memory>
 #include <queue>
@@ -45,15 +57,20 @@
   uint32_t default_width() const { return default_width_; }
 
   // Returns the default buffer height of this buffer queue.
-  uint32_t default_height() const { return default_height_; }
+  uint32_t default_height() const { return static_cast<uint32_t>(default_height_); }
 
   // Returns the default buffer format of this buffer queue.
-  uint32_t default_format() const { return default_format_; }
+  uint32_t default_format() const { return static_cast<uint32_t>(default_format_); }
 
   // Creates a new consumer in handle form for immediate transport over RPC.
   pdx::Status<pdx::LocalChannelHandle> CreateConsumerQueueHandle(
       bool silent = false);
 
+  // Creates a new consumer in parcelable form for immediate transport over
+  // Binder.
+  pdx::Status<ConsumerQueueParcelable> CreateConsumerQueueParcelable(
+      bool silent = false);
+
   // Returns the number of buffers avaiable for dequeue.
   size_t count() const { return available_buffers_.size(); }
 
@@ -68,7 +85,8 @@
     return available_buffers_.size() >= kMaxQueueCapacity;
   }
 
-  explicit operator bool() const { return epoll_fd_.IsValid(); }
+  // Returns whether the buffer queue is connected to bufferhubd.
+  bool is_connected() const { return !!GetChannel(); }
 
   int GetBufferId(size_t slot) const {
     return (slot < buffers_.size() && buffers_[slot]) ? buffers_[slot]->id()
@@ -150,20 +168,20 @@
                                       int poll_events);
   pdx::Status<void> HandleQueueEvent(int poll_events);
 
-  // Entry in the ring buffer of available buffers that stores related
+  // Entry in the priority queue of available buffers that stores related
   // per-buffer data.
   struct Entry {
     Entry() : slot(0) {}
-    Entry(const std::shared_ptr<BufferHubBuffer>& buffer, size_t slot,
-          uint64_t index)
-        : buffer(buffer), slot(slot), index(index) {}
-    Entry(const std::shared_ptr<BufferHubBuffer>& buffer,
-          std::unique_ptr<uint8_t[]> metadata, pdx::LocalHandle fence,
-          size_t slot)
-        : buffer(buffer),
-          metadata(std::move(metadata)),
-          fence(std::move(fence)),
-          slot(slot) {}
+    Entry(const std::shared_ptr<BufferHubBuffer>& in_buffer, size_t in_slot,
+          uint64_t in_index)
+        : buffer(in_buffer), slot(in_slot), index(in_index) {}
+    Entry(const std::shared_ptr<BufferHubBuffer>& in_buffer,
+          std::unique_ptr<uint8_t[]> in_metadata, pdx::LocalHandle in_fence,
+          size_t in_slot)
+        : buffer(in_buffer),
+          metadata(std::move(in_metadata)),
+          fence(std::move(in_fence)),
+          slot(in_slot) {}
     Entry(Entry&&) = default;
     Entry& operator=(Entry&&) = default;
 
@@ -221,13 +239,13 @@
   bool is_async_{false};
 
   // Default buffer width that is set during ProducerQueue's creation.
-  size_t default_width_{1};
+  uint32_t default_width_{1};
 
   // Default buffer height that is set during ProducerQueue's creation.
-  size_t default_height_{1};
+  uint32_t default_height_{1};
 
   // Default buffer format that is set during ProducerQueue's creation.
-  int32_t default_format_{1};  // PIXEL_FORMAT_RGBA_8888
+  uint32_t default_format_{1};  // PIXEL_FORMAT_RGBA_8888
 
   // Tracks the buffers belonging to this queue. Buffers are stored according to
   // "slot" in this vector. Each slot is a logical id of the buffer within this
@@ -235,7 +253,6 @@
   std::array<std::shared_ptr<BufferHubBuffer>, kMaxQueueCapacity> buffers_;
 
   // Buffers and related data that are available for dequeue.
-  // RingBuffer<Entry> available_buffers_{kMaxQueueCapacity};
   std::priority_queue<Entry, std::vector<Entry>, EntryComparator>
       available_buffers_;
 
@@ -337,6 +354,11 @@
     return BufferHubQueue::Enqueue({buffer, slot, index});
   }
 
+  // Takes out the current producer queue as a binder parcelable object. Note
+  // that the queue must be empty to be exportable. After successful export, the
+  // producer queue client should no longer be used.
+  pdx::Status<ProducerQueueParcelable> TakeAsParcelable();
+
  private:
   friend BASE;
 
@@ -363,10 +385,7 @@
   // used to avoid participation in the buffer lifecycle by a consumer queue
   // that is only used to spawn other consumer queues, such as in an
   // intermediate service.
-  static std::unique_ptr<ConsumerQueue> Import(pdx::LocalChannelHandle handle) {
-    return std::unique_ptr<ConsumerQueue>(
-        new ConsumerQueue(std::move(handle)));
-  }
+  static std::unique_ptr<ConsumerQueue> Import(pdx::LocalChannelHandle handle);
 
   // Import newly created buffers from the service side.
   // Returns number of buffers successfully imported or an error.
diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_parcelable.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_parcelable.h
new file mode 100644
index 0000000..4dea9b2
--- /dev/null
+++ b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_parcelable.h
@@ -0,0 +1,74 @@
+#ifndef ANDROID_DVR_BUFFER_HUB_QUEUE_PARCELABLE_H_
+#define ANDROID_DVR_BUFFER_HUB_QUEUE_PARCELABLE_H_
+
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Weverything"
+#endif
+
+// The following headers are included without checking every warning.
+// TODO(b/72172820): Remove the workaround once we have enforced -Weverything
+// in these headers and their dependencies.
+#include <pdx/channel_parcelable.h>
+
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
+
+namespace android {
+namespace dvr {
+
+enum BufferHubQueueParcelableMagic : uint32_t {
+  Producer = 0x62687170,  // 'bhqp'
+  Consumer = 0x62687163,  // 'bhqc'
+};
+
+template <BufferHubQueueParcelableMagic Magic>
+class BufferHubQueueParcelable : public Parcelable {
+ public:
+  BufferHubQueueParcelable() = default;
+
+  BufferHubQueueParcelable(BufferHubQueueParcelable&& other) = default;
+  BufferHubQueueParcelable& operator=(BufferHubQueueParcelable&& other) {
+    channel_parcelable_ = std::move(other.channel_parcelable_);
+    return *this;
+  }
+
+  // Constructs an parcelable contains the channel parcelable.
+  BufferHubQueueParcelable(
+      std::unique_ptr<pdx::ChannelParcelable> channel_parcelable)
+      : channel_parcelable_(std::move(channel_parcelable)) {}
+
+  BufferHubQueueParcelable(const BufferHubQueueParcelable&) = delete;
+  void operator=(const BufferHubQueueParcelable&) = delete;
+
+  bool IsValid() const;
+
+  // Returns a channel handle constructed from this parcelable object and takes
+  // the ownership of all resources from the parcelable object.
+  pdx::LocalChannelHandle TakeChannelHandle();
+
+  // Serializes the queue parcelable into the given parcel. Note that no system
+  // resources are getting duplicated, nor did the parcel takes ownership of the
+  // queue parcelable. Thus, the parcelable object must remain valid for the
+  // lifetime of the parcel.
+  status_t writeToParcel(Parcel* parcel) const override;
+
+  // Deserialize the queue parcelable from the given parcel. Note that system
+  // resources are duplicated from the parcel into the queue parcelable. Returns
+  // error if the targeting parcelable object is already valid.
+  status_t readFromParcel(const Parcel* parcel) override;
+
+ private:
+  std::unique_ptr<pdx::ChannelParcelable> channel_parcelable_;
+};
+
+using ProducerQueueParcelable =
+    BufferHubQueueParcelable<BufferHubQueueParcelableMagic::Producer>;
+using ConsumerQueueParcelable =
+    BufferHubQueueParcelable<BufferHubQueueParcelableMagic::Consumer>;
+
+}  // namespace dvr
+}  // namespace android
+
+#endif  // ANDROID_DVR_BUFFER_HUB_QUEUE_PARCELABLE_H_
diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_producer.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_producer.h
deleted file mode 100644
index 7ed55fb..0000000
--- a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_producer.h
+++ /dev/null
@@ -1,191 +0,0 @@
-#ifndef ANDROID_DVR_BUFFER_HUB_QUEUE_PRODUCER_H_
-#define ANDROID_DVR_BUFFER_HUB_QUEUE_PRODUCER_H_
-
-#include <gui/IGraphicBufferProducer.h>
-#include <private/dvr/buffer_hub_queue_client.h>
-
-namespace android {
-namespace dvr {
-
-class BufferHubQueueProducer : public BnGraphicBufferProducer {
- public:
-  static constexpr int kNoConnectedApi = -1;
-
-  // TODO(b/36187402) The actual implementation of BufferHubQueue's consumer
-  // side logic doesn't limit the number of buffer it can acquire
-  // simultaneously. We need a way for consumer logic to configure and enforce
-  // that.
-  static constexpr int kDefaultUndequeuedBuffers = 1;
-
-  // Create a BufferHubQueueProducer instance by creating a new producer queue.
-  static sp<BufferHubQueueProducer> Create();
-
-  // Create a BufferHubQueueProducer instance by importing an existing prodcuer
-  // queue.
-  static sp<BufferHubQueueProducer> Create(
-      const std::shared_ptr<ProducerQueue>& producer);
-
-  // See |IGraphicBufferProducer::requestBuffer|
-  status_t requestBuffer(int slot, sp<GraphicBuffer>* buf) override;
-
-  // For the BufferHub based implementation. All buffers in the queue are
-  // allowed to be dequeued from the consumer side. It call always returns
-  // 0 for |NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS| query. Thus setting
-  // |max_dequeued_buffers| here can be considered the same as setting queue
-  // capacity.
-  //
-  // See |IGraphicBufferProducer::setMaxDequeuedBufferCount| for more info
-  status_t setMaxDequeuedBufferCount(int max_dequeued_buffers) override;
-
-  // See |IGraphicBufferProducer::setAsyncMode|
-  status_t setAsyncMode(bool async) override;
-
-  // See |IGraphicBufferProducer::dequeueBuffer|
-  status_t dequeueBuffer(int* out_slot, sp<Fence>* out_fence, uint32_t width,
-                         uint32_t height, PixelFormat format, uint64_t usage,
-                         uint64_t* outBufferAge,
-                         FrameEventHistoryDelta* outTimestamps) override;
-
-  // See |IGraphicBufferProducer::detachBuffer|
-  status_t detachBuffer(int slot) override;
-
-  // See |IGraphicBufferProducer::detachNextBuffer|
-  status_t detachNextBuffer(sp<GraphicBuffer>* out_buffer,
-                            sp<Fence>* out_fence) override;
-
-  // See |IGraphicBufferProducer::attachBuffer|
-  status_t attachBuffer(int* out_slot,
-                        const sp<GraphicBuffer>& buffer) override;
-
-  // See |IGraphicBufferProducer::queueBuffer|
-  status_t queueBuffer(int slot, const QueueBufferInput& input,
-                       QueueBufferOutput* output) override;
-
-  // See |IGraphicBufferProducer::cancelBuffer|
-  status_t cancelBuffer(int slot, const sp<Fence>& fence) override;
-
-  // See |IGraphicBufferProducer::query|
-  status_t query(int what, int* out_value) override;
-
-  // See |IGraphicBufferProducer::connect|
-  status_t connect(const sp<IProducerListener>& listener, int api,
-                   bool producer_controlled_by_app,
-                   QueueBufferOutput* output) override;
-
-  // See |IGraphicBufferProducer::disconnect|
-  status_t disconnect(int api,
-                      DisconnectMode mode = DisconnectMode::Api) override;
-
-  // See |IGraphicBufferProducer::setSidebandStream|
-  status_t setSidebandStream(const sp<NativeHandle>& stream) override;
-
-  // See |IGraphicBufferProducer::allocateBuffers|
-  void allocateBuffers(uint32_t width, uint32_t height, PixelFormat format,
-                       uint64_t usage) override;
-
-  // See |IGraphicBufferProducer::allowAllocation|
-  status_t allowAllocation(bool allow) override;
-
-  // See |IGraphicBufferProducer::setGenerationNumber|
-  status_t setGenerationNumber(uint32_t generation_number) override;
-
-  // See |IGraphicBufferProducer::getConsumerName|
-  String8 getConsumerName() const override;
-
-  // See |IGraphicBufferProducer::setSharedBufferMode|
-  status_t setSharedBufferMode(bool shared_buffer_mode) override;
-
-  // See |IGraphicBufferProducer::setAutoRefresh|
-  status_t setAutoRefresh(bool auto_refresh) override;
-
-  // See |IGraphicBufferProducer::setDequeueTimeout|
-  status_t setDequeueTimeout(nsecs_t timeout) override;
-
-  // See |IGraphicBufferProducer::getLastQueuedBuffer|
-  status_t getLastQueuedBuffer(sp<GraphicBuffer>* out_buffer,
-                               sp<Fence>* out_fence,
-                               float out_transform_matrix[16]) override;
-
-  // See |IGraphicBufferProducer::getFrameTimestamps|
-  void getFrameTimestamps(FrameEventHistoryDelta* /*outDelta*/) override;
-
-  // See |IGraphicBufferProducer::getUniqueId|
-  status_t getUniqueId(uint64_t* out_id) const override;
-
-  // See |IGraphicBufferProducer::getConsumerUsage|
-  status_t getConsumerUsage(uint64_t* out_usage) const override;
-
- private:
-  using LocalHandle = pdx::LocalHandle;
-
-  // Private constructor to force use of |Create|.
-  BufferHubQueueProducer() {}
-
-  static uint64_t genUniqueId() {
-    static std::atomic<uint32_t> counter{0};
-    static uint64_t id = static_cast<uint64_t>(getpid()) << 32;
-    return id | counter++;
-  }
-
-  // Allocate new buffer through BufferHub and add it into |queue_| for
-  // bookkeeping.
-  status_t AllocateBuffer(uint32_t width, uint32_t height, uint32_t layer_count,
-                          PixelFormat format, uint64_t usage);
-
-  // Remove a buffer via BufferHubRPC.
-  status_t RemoveBuffer(size_t slot);
-
-  // Free all buffers which are owned by the prodcuer. Note that if graphic
-  // buffers are acquired by the consumer, we can't .
-  status_t FreeAllBuffers();
-
-  // Concreate implementation backed by BufferHubBuffer.
-  std::shared_ptr<ProducerQueue> queue_;
-
-  // Mutex for thread safety.
-  std::mutex mutex_;
-
-  // Connect client API, should be one of the NATIVE_WINDOW_API_* flags.
-  int connected_api_{kNoConnectedApi};
-
-  // |max_buffer_count_| sets the capacity of the underlying buffer queue.
-  int32_t max_buffer_count_{BufferHubQueue::kMaxQueueCapacity};
-
-  // |max_dequeued_buffer_count_| set the maximum number of buffers that can
-  // be dequeued at the same momment.
-  int32_t max_dequeued_buffer_count_{1};
-
-  // Sets how long dequeueBuffer or attachBuffer will block if a buffer or
-  // slot is not yet available. The timeout is stored in milliseconds.
-  int dequeue_timeout_ms_{BufferHubQueue::kNoTimeOut};
-
-  // |generation_number_| stores the current generation number of the attached
-  // producer. Any attempt to attach a buffer with a different generation
-  // number will fail.
-  // TOOD(b/38137191) Currently not used as we don't support
-  // IGraphicBufferProducer::detachBuffer.
-  uint32_t generation_number_{0};
-
-  // |buffers_| stores the buffers that have been dequeued from
-  // |dvr::BufferHubQueue|, It is initialized to invalid buffers, and gets
-  // filled in with the result of |Dequeue|.
-  // TODO(jwcai) The buffer allocated to a slot will also be replaced if the
-  // requested buffer usage or geometry differs from that of the buffer
-  // allocated to a slot.
-  struct BufferHubSlot : public BufferSlot {
-    BufferHubSlot() : mBufferProducer(nullptr), mIsReallocating(false) {}
-    // BufferSlot comes from android framework, using m prefix to comply with
-    // the name convention with the reset of data fields from BufferSlot.
-    std::shared_ptr<BufferProducer> mBufferProducer;
-    bool mIsReallocating;
-  };
-  BufferHubSlot buffers_[BufferHubQueue::kMaxQueueCapacity];
-
-  // A uniqueId used by IGraphicBufferProducer interface.
-  const uint64_t unique_id_{genUniqueId()};
-};
-
-}  // namespace dvr
-}  // namespace android
-
-#endif  // ANDROID_DVR_BUFFER_HUB_QUEUE_PRODUCER_H_
diff --git a/libs/vr/libdvrcommon/include/private/dvr/epoll_file_descriptor.h b/libs/vr/libbufferhubqueue/include/private/dvr/epoll_file_descriptor.h
similarity index 84%
rename from libs/vr/libdvrcommon/include/private/dvr/epoll_file_descriptor.h
rename to libs/vr/libbufferhubqueue/include/private/dvr/epoll_file_descriptor.h
index 099a409..6e303a5 100644
--- a/libs/vr/libdvrcommon/include/private/dvr/epoll_file_descriptor.h
+++ b/libs/vr/libbufferhubqueue/include/private/dvr/epoll_file_descriptor.h
@@ -1,5 +1,5 @@
-#ifndef LIBS_VR_LIBDVRCOMMON_INCLUDE_PRIVATE_DVR_EPOLL_FILE_DESCRIPTOR_H_
-#define LIBS_VR_LIBDVRCOMMON_INCLUDE_PRIVATE_DVR_EPOLL_FILE_DESCRIPTOR_H_
+#ifndef ANDROID_DVR_EPOLL_FILE_DESCRIPTOR_H_
+#define ANDROID_DVR_EPOLL_FILE_DESCRIPTOR_H_
 
 #include <android-base/unique_fd.h>
 #include <log/log.h>
@@ -61,4 +61,4 @@
 }  // namespace dvr
 }  // namespace android
 
-#endif  // LIBS_VR_LIBDVRCOMMON_INCLUDE_PRIVATE_DVR_EPOLL_FILE_DESCRIPTOR_H_
+#endif  // ANDROID_DVR_EPOLL_FILE_DESCRIPTOR_H_
diff --git a/libs/vr/libbufferhubqueue/tests/Android.bp b/libs/vr/libbufferhubqueue/tests/Android.bp
index 29e4ffe..a337921 100644
--- a/libs/vr/libbufferhubqueue/tests/Android.bp
+++ b/libs/vr/libbufferhubqueue/tests/Android.bp
@@ -6,20 +6,21 @@
 shared_libraries = [
     "libbase",
     "libbinder",
+    "libbufferhubqueue",
     "libcutils",
     "libgui",
     "liblog",
     "libhardware",
     "libui",
     "libutils",
+    "libnativewindow",
+    "libpdx_default_transport",
 ]
 
 static_libraries = [
-    "libbufferhubqueue",
-    "libbufferhub",
     "libchrome",
     "libdvrcommon",
-    "libpdx_default_transport",
+    "libperformance",
 ]
 
 cc_test {
diff --git a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
index 8a72531..47a2734 100644
--- a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
+++ b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
@@ -1,4 +1,5 @@
 #include <base/logging.h>
+#include <binder/Parcel.h>
 #include <private/dvr/buffer_hub_client.h>
 #include <private/dvr/buffer_hub_queue_client.h>
 
@@ -14,6 +15,7 @@
 namespace android {
 namespace dvr {
 
+using pdx::LocalChannelHandle;
 using pdx::LocalHandle;
 
 namespace {
@@ -23,6 +25,8 @@
 constexpr uint32_t kBufferLayerCount = 1;
 constexpr uint32_t kBufferFormat = HAL_PIXEL_FORMAT_BLOB;
 constexpr uint64_t kBufferUsage = GRALLOC_USAGE_SW_READ_RARELY;
+constexpr int kTimeoutMs = 100;
+constexpr int kNoTimeout = 0;
 
 class BufferHubQueueTest : public ::testing::Test {
  public:
@@ -82,41 +86,49 @@
 };
 
 TEST_F(BufferHubQueueTest, TestDequeue) {
-  const size_t nb_dequeue_times = 16;
+  const int64_t nb_dequeue_times = 16;
 
-  ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<size_t>().Build(),
-                           UsagePolicy{}));
+  ASSERT_TRUE(CreateQueues(config_builder_.Build(), UsagePolicy{}));
 
   // Allocate only one buffer.
   AllocateBuffer();
 
   // But dequeue multiple times.
-  for (size_t i = 0; i < nb_dequeue_times; i++) {
+  for (int64_t i = 0; i < nb_dequeue_times; i++) {
     size_t slot;
     LocalHandle fence;
-    auto p1_status = producer_queue_->Dequeue(100, &slot, &fence);
-    ASSERT_TRUE(p1_status.ok());
+    DvrNativeBufferMetadata mi, mo;
+
+    // Producer gains a buffer.
+    auto p1_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
+    EXPECT_TRUE(p1_status.ok());
     auto p1 = p1_status.take();
-    ASSERT_NE(nullptr, p1);
-    size_t mi = i;
-    ASSERT_EQ(p1->Post(LocalHandle(), &mi, sizeof(mi)), 0);
-    size_t mo;
-    auto c1_status = consumer_queue_->Dequeue(100, &slot, &mo, &fence);
-    ASSERT_TRUE(c1_status.ok());
+    ASSERT_NE(p1, nullptr);
+
+    // Producer posts the buffer.
+    mi.index = i;
+    EXPECT_EQ(p1->PostAsync(&mi, LocalHandle()), 0);
+
+    // Consumer acquires a buffer.
+    auto c1_status = consumer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
+    EXPECT_TRUE(c1_status.ok());
     auto c1 = c1_status.take();
-    ASSERT_NE(nullptr, c1);
-    ASSERT_EQ(mi, mo);
-    c1->Release(LocalHandle());
+    ASSERT_NE(c1, nullptr);
+    EXPECT_EQ(mi.index, i);
+    EXPECT_EQ(mo.index, i);
+
+    // Consumer releases the buffer.
+    EXPECT_EQ(c1->ReleaseAsync(&mi, LocalHandle()), 0);
   }
 }
 
 TEST_F(BufferHubQueueTest, TestProducerConsumer) {
   const size_t kBufferCount = 16;
   size_t slot;
-  uint64_t seq;
+  DvrNativeBufferMetadata mi, mo;
+  LocalHandle fence;
 
-  ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<uint64_t>().Build(),
-                           UsagePolicy{}));
+  ASSERT_TRUE(CreateQueues(config_builder_.Build(), UsagePolicy{}));
 
   for (size_t i = 0; i < kBufferCount; i++) {
     AllocateBuffer();
@@ -131,8 +143,7 @@
     ASSERT_EQ(consumer_queue_->capacity(), i);
     // Dequeue returns timeout since no buffer is ready to consumer, but
     // this implicitly triggers buffer import and bump up |capacity|.
-    LocalHandle fence;
-    auto status = consumer_queue_->Dequeue(100, &slot, &seq, &fence);
+    auto status = consumer_queue_->Dequeue(kNoTimeout, &slot, &mo, &fence);
     ASSERT_FALSE(status.ok());
     ASSERT_EQ(ETIMEDOUT, status.error());
     ASSERT_EQ(consumer_queue_->capacity(), i + 1);
@@ -142,37 +153,37 @@
   LocalHandle post_fence(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
 
   for (size_t i = 0; i < kBufferCount; i++) {
-    LocalHandle fence;
-
     // First time there is no buffer available to dequeue.
-    auto consumer_status = consumer_queue_->Dequeue(100, &slot, &seq, &fence);
+    auto consumer_status =
+        consumer_queue_->Dequeue(kNoTimeout, &slot, &mo, &fence);
     ASSERT_FALSE(consumer_status.ok());
-    ASSERT_EQ(ETIMEDOUT, consumer_status.error());
+    ASSERT_EQ(consumer_status.error(), ETIMEDOUT);
 
     // Make sure Producer buffer is POSTED so that it's ready to Accquire
     // in the consumer's Dequeue() function.
-    auto producer_status = producer_queue_->Dequeue(100, &slot, &fence);
+    auto producer_status =
+        producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
     ASSERT_TRUE(producer_status.ok());
     auto producer = producer_status.take();
     ASSERT_NE(nullptr, producer);
 
-    uint64_t seq_in = static_cast<uint64_t>(i);
-    ASSERT_EQ(producer->Post(post_fence, &seq_in, sizeof(seq_in)), 0);
+    mi.index = static_cast<int64_t>(i);
+    ASSERT_EQ(producer->PostAsync(&mi, post_fence), 0);
 
     // Second time the just the POSTED buffer should be dequeued.
-    uint64_t seq_out = 0;
-    consumer_status = consumer_queue_->Dequeue(100, &slot, &seq_out, &fence);
+    consumer_status = consumer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
     ASSERT_TRUE(consumer_status.ok());
     EXPECT_TRUE(fence.IsValid());
 
     auto consumer = consumer_status.take();
     ASSERT_NE(nullptr, consumer);
-    ASSERT_EQ(seq_in, seq_out);
+    ASSERT_EQ(mi.index, mo.index);
   }
 }
 
 TEST_F(BufferHubQueueTest, TestRemoveBuffer) {
   ASSERT_TRUE(CreateProducerQueue(config_builder_.Build(), UsagePolicy{}));
+  DvrNativeBufferMetadata mo;
 
   // Allocate buffers.
   const size_t kBufferCount = 4u;
@@ -201,7 +212,7 @@
   for (size_t i = 0; i < kBufferCount; i++) {
     Entry* entry = &buffers[i];
     auto producer_status = producer_queue_->Dequeue(
-        /*timeout_ms=*/100, &entry->slot, &entry->fence);
+        kTimeoutMs, &entry->slot, &mo, &entry->fence);
     ASSERT_TRUE(producer_status.ok());
     entry->buffer = producer_status.take();
     ASSERT_NE(nullptr, entry->buffer);
@@ -221,7 +232,7 @@
   buffers[0].buffer = nullptr;
 
   // Now the consumer queue should know it's gone.
-  EXPECT_FALSE(WaitAndHandleOnce(consumer_queue_.get(), /*timeout_ms=*/100));
+  EXPECT_FALSE(WaitAndHandleOnce(consumer_queue_.get(), kTimeoutMs));
   ASSERT_EQ(kBufferCount - 1, consumer_queue_->capacity());
 
   // Allocate a new buffer. This should take the first empty slot.
@@ -290,126 +301,156 @@
   ASSERT_NE(nullptr, silent_queue);
 
   // Check that silent queue doesn't import buffers on creation.
-  EXPECT_EQ(0, silent_queue->capacity());
+  EXPECT_EQ(silent_queue->capacity(), 0U);
 
   // Dequeue and post a buffer.
   size_t slot;
   LocalHandle fence;
+  DvrNativeBufferMetadata mi, mo;
   auto producer_status =
-      producer_queue_->Dequeue(/*timeout_ms=*/100, &slot, &fence);
-  ASSERT_TRUE(producer_status.ok());
+      producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
+  EXPECT_TRUE(producer_status.ok());
   auto producer_buffer = producer_status.take();
-  ASSERT_NE(nullptr, producer_buffer);
-  ASSERT_EQ(0, producer_buffer->Post<void>({}));
+  ASSERT_NE(producer_buffer, nullptr);
+  EXPECT_EQ(producer_buffer->PostAsync(&mi, {}), 0);
   // After post, check the number of remaining available buffers.
-  EXPECT_EQ(kBufferCount - 1, producer_queue_->count());
+  EXPECT_EQ(producer_queue_->count(), kBufferCount - 1);
 
   // Currently we expect no buffer to be available prior to calling
   // WaitForBuffers/HandleQueueEvents.
   // TODO(eieio): Note this behavior may change in the future.
-  EXPECT_EQ(0u, silent_queue->count());
+  EXPECT_EQ(silent_queue->count(), 0U);
   EXPECT_FALSE(silent_queue->HandleQueueEvents());
-  EXPECT_EQ(0u, silent_queue->count());
+  EXPECT_EQ(silent_queue->count(), 0U);
 
   // Build a new consumer queue to test multi-consumer queue features.
   consumer_queue_ = silent_queue->CreateConsumerQueue();
-  ASSERT_NE(nullptr, consumer_queue_);
+  ASSERT_NE(consumer_queue_, nullptr);
 
   // Check that buffers are correctly imported on construction.
-  EXPECT_EQ(kBufferCount, consumer_queue_->capacity());
-  EXPECT_EQ(1u, consumer_queue_->count());
+  EXPECT_EQ(consumer_queue_->capacity(), kBufferCount);
+  // Buffers are only imported, but their availability is not checked until
+  // first call to Dequeue().
+  EXPECT_EQ(consumer_queue_->count(), 0U);
 
   // Reclaim released/ignored buffers.
-  ASSERT_EQ(kBufferCount - 1, producer_queue_->count());
+  EXPECT_EQ(producer_queue_->count(), kBufferCount - 1);
 
   usleep(10000);
-  WaitAndHandleOnce(producer_queue_.get(), /*timeout_ms=*/100);
-  ASSERT_EQ(kBufferCount - 1, producer_queue_->count());
+  WaitAndHandleOnce(producer_queue_.get(), kTimeoutMs);
+  EXPECT_EQ(producer_queue_->count(), kBufferCount - 1);
 
   // Post another buffer.
-  producer_status = producer_queue_->Dequeue(/*timeout_ms=*/100, &slot, &fence);
-  ASSERT_TRUE(producer_status.ok());
+  producer_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
+  EXPECT_TRUE(producer_status.ok());
   producer_buffer = producer_status.take();
-  ASSERT_NE(nullptr, producer_buffer);
-  ASSERT_EQ(0, producer_buffer->Post<void>({}));
+  ASSERT_NE(producer_buffer, nullptr);
+  EXPECT_EQ(producer_buffer->PostAsync(&mi, {}), 0);
 
   // Verify that the consumer queue receives it.
   size_t consumer_queue_count = consumer_queue_->count();
-  WaitAndHandleOnce(consumer_queue_.get(), /*timeout_ms=*/100);
-  EXPECT_LT(consumer_queue_count, consumer_queue_->count());
+  WaitAndHandleOnce(consumer_queue_.get(), kTimeoutMs);
+  EXPECT_GT(consumer_queue_->count(), consumer_queue_count);
 
   // Save the current consumer queue buffer count to compare after the dequeue.
   consumer_queue_count = consumer_queue_->count();
 
   // Dequeue and acquire/release (discard) buffers on the consumer end.
   auto consumer_status =
-      consumer_queue_->Dequeue(/*timeout_ms=*/100, &slot, &fence);
-  ASSERT_TRUE(consumer_status.ok());
+      consumer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
+  EXPECT_TRUE(consumer_status.ok());
   auto consumer_buffer = consumer_status.take();
-  ASSERT_NE(nullptr, consumer_buffer);
+  ASSERT_NE(consumer_buffer, nullptr);
   consumer_buffer->Discard();
 
   // Buffer should be returned to the producer queue without being handled by
   // the silent consumer queue.
-  EXPECT_GT(consumer_queue_count, consumer_queue_->count());
-  EXPECT_EQ(kBufferCount - 2, producer_queue_->count());
-  EXPECT_TRUE(producer_queue_->HandleQueueEvents());
-  EXPECT_EQ(kBufferCount - 1, producer_queue_->count());
+  EXPECT_LT(consumer_queue_->count(), consumer_queue_count);
+  EXPECT_EQ(producer_queue_->count(), kBufferCount - 2);
+
+  WaitAndHandleOnce(producer_queue_.get(), kTimeoutMs);
+  EXPECT_EQ(producer_queue_->count(), kBufferCount - 1);
 }
 
-struct TestMetadata {
+struct TestUserMetadata {
   char a;
   int32_t b;
   int64_t c;
 };
 
-TEST_F(BufferHubQueueTest, TestMetadata) {
-  ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<TestMetadata>().Build(),
-                           UsagePolicy{}));
+constexpr uint64_t kUserMetadataSize =
+    static_cast<uint64_t>(sizeof(TestUserMetadata));
+
+TEST_F(BufferHubQueueTest, TestUserMetadata) {
+  ASSERT_TRUE(CreateQueues(
+      config_builder_.SetMetadata<TestUserMetadata>().Build(), UsagePolicy{}));
 
   AllocateBuffer();
 
-  std::vector<TestMetadata> ms = {
+  std::vector<TestUserMetadata> user_metadata_list = {
       {'0', 0, 0}, {'1', 10, 3333}, {'@', 123, 1000000000}};
 
-  for (auto mi : ms) {
+  for (auto user_metadata : user_metadata_list) {
     size_t slot;
     LocalHandle fence;
-    auto p1_status = producer_queue_->Dequeue(100, &slot, &fence);
-    ASSERT_TRUE(p1_status.ok());
+    DvrNativeBufferMetadata mi, mo;
+
+    auto p1_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
+    EXPECT_TRUE(p1_status.ok());
     auto p1 = p1_status.take();
-    ASSERT_NE(nullptr, p1);
-    ASSERT_EQ(p1->Post(LocalHandle(-1), &mi, sizeof(mi)), 0);
-    TestMetadata mo;
-    auto c1_status = consumer_queue_->Dequeue(100, &slot, &mo, &fence);
-    ASSERT_TRUE(c1_status.ok());
+    ASSERT_NE(p1, nullptr);
+
+    // TODO(b/69469185): Test against metadata from consumer once we implement
+    // release metadata properly.
+    // EXPECT_EQ(mo.user_metadata_ptr, 0U);
+    // EXPECT_EQ(mo.user_metadata_size, 0U);
+
+    mi.user_metadata_size = kUserMetadataSize;
+    mi.user_metadata_ptr = reinterpret_cast<uint64_t>(&user_metadata);
+    EXPECT_EQ(p1->PostAsync(&mi, {}), 0);
+    auto c1_status = consumer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
+    EXPECT_TRUE(c1_status.ok());
     auto c1 = c1_status.take();
-    ASSERT_EQ(mi.a, mo.a);
-    ASSERT_EQ(mi.b, mo.b);
-    ASSERT_EQ(mi.c, mo.c);
-    c1->Release(LocalHandle(-1));
+    ASSERT_NE(c1, nullptr);
+
+    EXPECT_EQ(mo.user_metadata_size, kUserMetadataSize);
+    auto out_user_metadata =
+        reinterpret_cast<TestUserMetadata*>(mo.user_metadata_ptr);
+    EXPECT_EQ(user_metadata.a, out_user_metadata->a);
+    EXPECT_EQ(user_metadata.b, out_user_metadata->b);
+    EXPECT_EQ(user_metadata.c, out_user_metadata->c);
+
+    // When release, empty metadata is also legit.
+    mi.user_metadata_size = 0U;
+    mi.user_metadata_ptr = 0U;
+    c1->ReleaseAsync(&mi, {});
   }
 }
 
-TEST_F(BufferHubQueueTest, TestMetadataMismatch) {
-  ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<int64_t>().Build(),
-                           UsagePolicy{}));
+TEST_F(BufferHubQueueTest, TestUserMetadataMismatch) {
+  ASSERT_TRUE(CreateQueues(
+      config_builder_.SetMetadata<TestUserMetadata>().Build(), UsagePolicy{}));
 
   AllocateBuffer();
 
-  int64_t mi = 3;
+  TestUserMetadata user_metadata;
   size_t slot;
   LocalHandle fence;
-  auto p1_status = producer_queue_->Dequeue(100, &slot, &fence);
-  ASSERT_TRUE(p1_status.ok());
+  DvrNativeBufferMetadata mi, mo;
+  auto p1_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
+  EXPECT_TRUE(p1_status.ok());
   auto p1 = p1_status.take();
-  ASSERT_NE(nullptr, p1);
-  ASSERT_EQ(p1->Post(LocalHandle(-1), &mi, sizeof(mi)), 0);
+  ASSERT_NE(p1, nullptr);
 
-  int32_t mo;
-  // Acquire a buffer with mismatched metadata is not OK.
-  auto c1_status = consumer_queue_->Dequeue(100, &slot, &mo, &fence);
-  ASSERT_FALSE(c1_status.ok());
+  // Post with mismatched user metadata size will fail. But the producer buffer
+  // itself should stay untouched.
+  mi.user_metadata_ptr = reinterpret_cast<uint64_t>(&user_metadata);
+  mi.user_metadata_size = kUserMetadataSize + 1;
+  EXPECT_EQ(p1->PostAsync(&mi, {}), -E2BIG);
+  // Post with the exact same user metdata size can success.
+  mi.user_metadata_ptr = reinterpret_cast<uint64_t>(&user_metadata);
+  mi.user_metadata_size = kUserMetadataSize;
+  EXPECT_EQ(p1->PostAsync(&mi, {}), 0);
 }
 
 TEST_F(BufferHubQueueTest, TestEnqueue) {
@@ -419,32 +460,32 @@
 
   size_t slot;
   LocalHandle fence;
-  auto p1_status = producer_queue_->Dequeue(100, &slot, &fence);
+  DvrNativeBufferMetadata mo;
+  auto p1_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
   ASSERT_TRUE(p1_status.ok());
   auto p1 = p1_status.take();
   ASSERT_NE(nullptr, p1);
 
-  int64_t mo;
   producer_queue_->Enqueue(p1, slot, 0ULL);
-  auto c1_status = consumer_queue_->Dequeue(100, &slot, &mo, &fence);
+  auto c1_status = consumer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
   ASSERT_FALSE(c1_status.ok());
 }
 
 TEST_F(BufferHubQueueTest, TestAllocateBuffer) {
-  ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<int64_t>().Build(),
-                           UsagePolicy{}));
+  ASSERT_TRUE(CreateQueues(config_builder_.Build(), UsagePolicy{}));
 
-  size_t s1;
+  size_t ps1;
   AllocateBuffer();
   LocalHandle fence;
-  auto p1_status = producer_queue_->Dequeue(100, &s1, &fence);
+  DvrNativeBufferMetadata mi, mo;
+  auto p1_status = producer_queue_->Dequeue(kTimeoutMs, &ps1, &mo, &fence);
   ASSERT_TRUE(p1_status.ok());
   auto p1 = p1_status.take();
-  ASSERT_NE(nullptr, p1);
+  ASSERT_NE(p1, nullptr);
 
   // producer queue is exhausted
-  size_t s2;
-  auto p2_status = producer_queue_->Dequeue(100, &s2, &fence);
+  size_t ps2;
+  auto p2_status = producer_queue_->Dequeue(kTimeoutMs, &ps2, &mo, &fence);
   ASSERT_FALSE(p2_status.ok());
   ASSERT_EQ(ETIMEDOUT, p2_status.error());
 
@@ -454,41 +495,43 @@
   ASSERT_EQ(producer_queue_->capacity(), 2U);
 
   // now we can dequeue again
-  p2_status = producer_queue_->Dequeue(100, &s2, &fence);
+  p2_status = producer_queue_->Dequeue(kTimeoutMs, &ps2, &mo, &fence);
   ASSERT_TRUE(p2_status.ok());
   auto p2 = p2_status.take();
-  ASSERT_NE(nullptr, p2);
+  ASSERT_NE(p2, nullptr);
   ASSERT_EQ(producer_queue_->count(), 0U);
   // p1 and p2 should have different slot number
-  ASSERT_NE(s1, s2);
+  ASSERT_NE(ps1, ps2);
 
   // Consumer queue does not import buffers until |Dequeue| or |ImportBuffers|
   // are called. So far consumer_queue_ should be empty.
   ASSERT_EQ(consumer_queue_->count(), 0U);
 
   int64_t seq = 1;
-  ASSERT_EQ(p1->Post(LocalHandle(), seq), 0);
+  mi.index = seq;
+  ASSERT_EQ(p1->PostAsync(&mi, {}), 0);
+
   size_t cs1, cs2;
-  auto c1_status = consumer_queue_->Dequeue(100, &cs1, &seq, &fence);
+  auto c1_status = consumer_queue_->Dequeue(kTimeoutMs, &cs1, &mo, &fence);
   ASSERT_TRUE(c1_status.ok());
   auto c1 = c1_status.take();
-  ASSERT_NE(nullptr, c1);
+  ASSERT_NE(c1, nullptr);
   ASSERT_EQ(consumer_queue_->count(), 0U);
   ASSERT_EQ(consumer_queue_->capacity(), 2U);
-  ASSERT_EQ(cs1, s1);
+  ASSERT_EQ(cs1, ps1);
 
-  ASSERT_EQ(p2->Post(LocalHandle(), seq), 0);
-  auto c2_status = consumer_queue_->Dequeue(100, &cs2, &seq, &fence);
+  ASSERT_EQ(p2->PostAsync(&mi, {}), 0);
+  auto c2_status = consumer_queue_->Dequeue(kTimeoutMs, &cs2, &mo, &fence);
   ASSERT_TRUE(c2_status.ok());
   auto c2 = c2_status.take();
-  ASSERT_NE(nullptr, c2);
-  ASSERT_EQ(cs2, s2);
+  ASSERT_NE(c2, nullptr);
+  ASSERT_EQ(cs2, ps2);
 }
 
 TEST_F(BufferHubQueueTest, TestUsageSetMask) {
   const uint32_t set_mask = GRALLOC_USAGE_SW_WRITE_OFTEN;
-  ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<int64_t>().Build(),
-                           UsagePolicy{set_mask, 0, 0, 0}));
+  ASSERT_TRUE(
+      CreateQueues(config_builder_.Build(), UsagePolicy{set_mask, 0, 0, 0}));
 
   // When allocation, leave out |set_mask| from usage bits on purpose.
   auto status = producer_queue_->AllocateBuffer(
@@ -498,7 +541,8 @@
 
   LocalHandle fence;
   size_t slot;
-  auto p1_status = producer_queue_->Dequeue(100, &slot, &fence);
+  DvrNativeBufferMetadata mo;
+  auto p1_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
   ASSERT_TRUE(p1_status.ok());
   auto p1 = p1_status.take();
   ASSERT_EQ(p1->usage() & set_mask, set_mask);
@@ -506,8 +550,8 @@
 
 TEST_F(BufferHubQueueTest, TestUsageClearMask) {
   const uint32_t clear_mask = GRALLOC_USAGE_SW_WRITE_OFTEN;
-  ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<int64_t>().Build(),
-                           UsagePolicy{0, clear_mask, 0, 0}));
+  ASSERT_TRUE(
+      CreateQueues(config_builder_.Build(), UsagePolicy{0, clear_mask, 0, 0}));
 
   // When allocation, add |clear_mask| into usage bits on purpose.
   auto status = producer_queue_->AllocateBuffer(
@@ -517,10 +561,11 @@
 
   LocalHandle fence;
   size_t slot;
-  auto p1_status = producer_queue_->Dequeue(100, &slot, &fence);
+  DvrNativeBufferMetadata mo;
+  auto p1_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
   ASSERT_TRUE(p1_status.ok());
   auto p1 = p1_status.take();
-  ASSERT_EQ(0u, p1->usage() & clear_mask);
+  ASSERT_EQ(p1->usage() & clear_mask, 0U);
 }
 
 TEST_F(BufferHubQueueTest, TestUsageDenySetMask) {
@@ -598,16 +643,15 @@
   EXPECT_EQ(producer_queue_->capacity(), num_buffers);
 
   size_t slot;
-  uint64_t seq;
   LocalHandle fence;
   pdx::Status<void> status;
   pdx::Status<std::shared_ptr<BufferConsumer>> consumer_status;
   pdx::Status<std::shared_ptr<BufferProducer>> producer_status;
   std::shared_ptr<BufferConsumer> consumer_buffer;
   std::shared_ptr<BufferProducer> producer_buffer;
+  DvrNativeBufferMetadata mi, mo;
 
-  ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<uint64_t>().Build(),
-                           UsagePolicy{}));
+  ASSERT_TRUE(CreateQueues(config_builder_.Build(), UsagePolicy{}));
 
   // Free all buffers when buffers are avaible for dequeue.
   CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount);
@@ -616,7 +660,7 @@
 
   // Free all buffers when one buffer is dequeued.
   CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount);
-  producer_status = producer_queue_->Dequeue(100, &slot, &fence);
+  producer_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
   ASSERT_TRUE(producer_status.ok());
   status = producer_queue_->FreeAllBuffers();
   EXPECT_TRUE(status.ok());
@@ -624,7 +668,7 @@
   // Free all buffers when all buffers are dequeued.
   CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount);
   for (size_t i = 0; i < kBufferCount; i++) {
-    producer_status = producer_queue_->Dequeue(100, &slot, &fence);
+    producer_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
     ASSERT_TRUE(producer_status.ok());
   }
   status = producer_queue_->FreeAllBuffers();
@@ -632,22 +676,22 @@
 
   // Free all buffers when one buffer is posted.
   CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount);
-  producer_status = producer_queue_->Dequeue(100, &slot, &fence);
+  producer_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
   ASSERT_TRUE(producer_status.ok());
   producer_buffer = producer_status.take();
   ASSERT_NE(nullptr, producer_buffer);
-  ASSERT_EQ(0, producer_buffer->Post(fence, &seq, sizeof(seq)));
+  ASSERT_EQ(0, producer_buffer->PostAsync(&mi, fence));
   status = producer_queue_->FreeAllBuffers();
   EXPECT_TRUE(status.ok());
 
   // Free all buffers when all buffers are posted.
   CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount);
   for (size_t i = 0; i < kBufferCount; i++) {
-    producer_status = producer_queue_->Dequeue(100, &slot, &fence);
+    producer_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
     ASSERT_TRUE(producer_status.ok());
     producer_buffer = producer_status.take();
-    ASSERT_NE(nullptr, producer_buffer);
-    ASSERT_EQ(0, producer_buffer->Post(fence, &seq, sizeof(seq)));
+    ASSERT_NE(producer_buffer, nullptr);
+    ASSERT_EQ(producer_buffer->PostAsync(&mi, fence), 0);
   }
   status = producer_queue_->FreeAllBuffers();
   EXPECT_TRUE(status.ok());
@@ -655,12 +699,12 @@
   // Free all buffers when all buffers are acquired.
   CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount);
   for (size_t i = 0; i < kBufferCount; i++) {
-    producer_status = producer_queue_->Dequeue(100, &slot, &fence);
+    producer_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
     ASSERT_TRUE(producer_status.ok());
     producer_buffer = producer_status.take();
-    ASSERT_NE(nullptr, producer_buffer);
-    ASSERT_EQ(0, producer_buffer->Post(fence, &seq, sizeof(seq)));
-    consumer_status = consumer_queue_->Dequeue(100, &slot, &seq, &fence);
+    ASSERT_NE(producer_buffer, nullptr);
+    ASSERT_EQ(producer_buffer->PostAsync(&mi, fence), 0);
+    consumer_status = consumer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
     ASSERT_TRUE(consumer_status.ok());
   }
 
@@ -680,6 +724,156 @@
 #undef CHECK_NO_BUFFER_THEN_ALLOCATE
 }
 
+TEST_F(BufferHubQueueTest, TestProducerToParcelableNotEmpty) {
+  ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<uint64_t>().Build(),
+                           UsagePolicy{}));
+
+  // Allocate only one buffer.
+  AllocateBuffer();
+
+  // Export should fail as the queue is not empty.
+  auto status = producer_queue_->TakeAsParcelable();
+  EXPECT_FALSE(status.ok());
+}
+
+TEST_F(BufferHubQueueTest, TestProducerExportToParcelable) {
+  ASSERT_TRUE(CreateQueues(config_builder_.Build(), UsagePolicy{}));
+
+  auto s1 = producer_queue_->TakeAsParcelable();
+  EXPECT_TRUE(s1.ok());
+
+  ProducerQueueParcelable output_parcelable = s1.take();
+  EXPECT_TRUE(output_parcelable.IsValid());
+
+  Parcel parcel;
+  status_t res;
+  res = output_parcelable.writeToParcel(&parcel);
+  EXPECT_EQ(res, NO_ERROR);
+
+  // After written into parcelable, the output_parcelable is still valid has
+  // keeps the producer channel alive.
+  EXPECT_TRUE(output_parcelable.IsValid());
+
+  // Creating producer buffer should fail.
+  auto s2 = producer_queue_->AllocateBuffer(kBufferWidth, kBufferHeight,
+                                            kBufferLayerCount, kBufferFormat,
+                                            kBufferUsage);
+  ASSERT_FALSE(s2.ok());
+
+  // Reset the data position so that we can read back from the same parcel
+  // without doing actually Binder IPC.
+  parcel.setDataPosition(0);
+  producer_queue_ = nullptr;
+
+  // Recreate the producer queue from the parcel.
+  ProducerQueueParcelable input_parcelable;
+  EXPECT_FALSE(input_parcelable.IsValid());
+
+  res = input_parcelable.readFromParcel(&parcel);
+  EXPECT_EQ(res, NO_ERROR);
+  EXPECT_TRUE(input_parcelable.IsValid());
+
+  EXPECT_EQ(producer_queue_, nullptr);
+  producer_queue_ = ProducerQueue::Import(input_parcelable.TakeChannelHandle());
+  EXPECT_FALSE(input_parcelable.IsValid());
+  ASSERT_NE(producer_queue_, nullptr);
+
+  // Newly created queue from the parcel can allocate buffer, post buffer to
+  // consumer.
+  EXPECT_NO_FATAL_FAILURE(AllocateBuffer());
+  EXPECT_EQ(producer_queue_->count(), 1U);
+  EXPECT_EQ(producer_queue_->capacity(), 1U);
+
+  size_t slot;
+  DvrNativeBufferMetadata producer_meta;
+  DvrNativeBufferMetadata consumer_meta;
+  LocalHandle fence;
+  auto s3 = producer_queue_->Dequeue(0, &slot, &producer_meta, &fence);
+  EXPECT_TRUE(s3.ok());
+
+  std::shared_ptr<BufferProducer> p1 = s3.take();
+  ASSERT_NE(p1, nullptr);
+
+  producer_meta.timestamp = 42;
+  EXPECT_EQ(p1->PostAsync(&producer_meta, LocalHandle()), 0);
+
+  // Make sure the buffer can be dequeued from consumer side.
+  auto s4 = consumer_queue_->Dequeue(kTimeoutMs, &slot, &consumer_meta, &fence);
+  EXPECT_TRUE(s4.ok());
+  EXPECT_EQ(consumer_queue_->capacity(), 1U);
+
+  auto consumer = s4.take();
+  ASSERT_NE(consumer, nullptr);
+  EXPECT_EQ(producer_meta.timestamp, consumer_meta.timestamp);
+}
+
+TEST_F(BufferHubQueueTest, TestCreateConsumerParcelable) {
+  ASSERT_TRUE(CreateProducerQueue(config_builder_.Build(), UsagePolicy{}));
+
+  auto s1 = producer_queue_->CreateConsumerQueueParcelable();
+  EXPECT_TRUE(s1.ok());
+  ConsumerQueueParcelable output_parcelable = s1.take();
+  EXPECT_TRUE(output_parcelable.IsValid());
+
+  // Write to a Parcel new object.
+  Parcel parcel;
+  status_t res;
+  res = output_parcelable.writeToParcel(&parcel);
+
+  // Reset the data position so that we can read back from the same parcel
+  // without doing actually Binder IPC.
+  parcel.setDataPosition(0);
+
+  // No consumer queue created yet.
+  EXPECT_EQ(consumer_queue_, nullptr);
+
+  // If the parcel contains a consumer queue, read into a
+  // ProducerQueueParcelable should fail.
+  ProducerQueueParcelable wrongly_typed_parcelable;
+  EXPECT_FALSE(wrongly_typed_parcelable.IsValid());
+  res = wrongly_typed_parcelable.readFromParcel(&parcel);
+  EXPECT_EQ(res, -EINVAL);
+  parcel.setDataPosition(0);
+
+  // Create the consumer queue from the parcel.
+  ConsumerQueueParcelable input_parcelable;
+  EXPECT_FALSE(input_parcelable.IsValid());
+
+  res = input_parcelable.readFromParcel(&parcel);
+  EXPECT_EQ(res, NO_ERROR);
+  EXPECT_TRUE(input_parcelable.IsValid());
+
+  consumer_queue_ = ConsumerQueue::Import(input_parcelable.TakeChannelHandle());
+  EXPECT_FALSE(input_parcelable.IsValid());
+  ASSERT_NE(consumer_queue_, nullptr);
+
+  EXPECT_NO_FATAL_FAILURE(AllocateBuffer());
+  EXPECT_EQ(producer_queue_->count(), 1U);
+  EXPECT_EQ(producer_queue_->capacity(), 1U);
+
+  size_t slot;
+  DvrNativeBufferMetadata producer_meta;
+  DvrNativeBufferMetadata consumer_meta;
+  LocalHandle fence;
+  auto s2 = producer_queue_->Dequeue(0, &slot, &producer_meta, &fence);
+  EXPECT_TRUE(s2.ok());
+
+  std::shared_ptr<BufferProducer> p1 = s2.take();
+  ASSERT_NE(p1, nullptr);
+
+  producer_meta.timestamp = 42;
+  EXPECT_EQ(p1->PostAsync(&producer_meta, LocalHandle()), 0);
+
+  // Make sure the buffer can be dequeued from consumer side.
+  auto s3 = consumer_queue_->Dequeue(kTimeoutMs, &slot, &consumer_meta, &fence);
+  EXPECT_TRUE(s3.ok());
+  EXPECT_EQ(consumer_queue_->capacity(), 1U);
+
+  auto consumer = s3.take();
+  ASSERT_NE(consumer, nullptr);
+  EXPECT_EQ(producer_meta.timestamp, consumer_meta.timestamp);
+}
+
 }  // namespace
 
 }  // namespace dvr
diff --git a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp
index 28cd63a..4f10f83 100644
--- a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp
+++ b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp
@@ -1,14 +1,16 @@
-#include <private/dvr/buffer_hub_queue_producer.h>
-
 #include <base/logging.h>
+#include <gui/BufferHubProducer.h>
 #include <gui/IProducerListener.h>
 #include <gui/Surface.h>
+#include <pdx/default_transport/channel_parcelable.h>
 
 #include <gtest/gtest.h>
 
 namespace android {
 namespace dvr {
 
+using pdx::LocalHandle;
+
 namespace {
 
 // Default dimensions before setDefaultBufferSize is called by the consumer.
@@ -92,7 +94,11 @@
     ALOGD_IF(TRACE, "Begin test: %s.%s", testInfo->test_case_name(),
              testInfo->name());
 
-    mProducer = BufferHubQueueProducer::Create();
+    auto config = ProducerQueueConfigBuilder().Build();
+    auto queue = ProducerQueue::Create(config, UsagePolicy{});
+    ASSERT_TRUE(queue != nullptr);
+
+    mProducer = BufferHubProducer::Create(std::move(queue));
     ASSERT_TRUE(mProducer != nullptr);
     mSurface = new Surface(mProducer, true);
     ASSERT_TRUE(mSurface != nullptr);
@@ -136,7 +142,7 @@
 
   const sp<IProducerListener> kDummyListener{new DummyProducerListener};
 
-  sp<BufferHubQueueProducer> mProducer;
+  sp<BufferHubProducer> mProducer;
   sp<Surface> mSurface;
 };
 
@@ -546,6 +552,55 @@
   EXPECT_EQ(NO_ERROR, mProducer->disconnect(kTestApi));
 }
 
+TEST_F(BufferHubQueueProducerTest, TakeAsParcelable) {
+  // Connected producer cannot be taken out as a parcelable.
+  EXPECT_NO_FATAL_FAILURE(ConnectProducer());
+  ProducerQueueParcelable producer_parcelable;
+  EXPECT_EQ(mProducer->TakeAsParcelable(&producer_parcelable), BAD_VALUE);
+
+  // Create a valid dummy producer parcelable.
+  auto dummy_channel_parcelable =
+      std::make_unique<pdx::default_transport::ChannelParcelable>(
+          LocalHandle(0), LocalHandle(0), LocalHandle(0));
+  EXPECT_TRUE(dummy_channel_parcelable->IsValid());
+  ProducerQueueParcelable dummy_producer_parcelable(
+      std::move(dummy_channel_parcelable));
+  EXPECT_TRUE(dummy_producer_parcelable.IsValid());
+
+  // Disconnect producer can be taken out, but only to an invalid parcelable.
+  ASSERT_EQ(mProducer->disconnect(kTestApi), NO_ERROR);
+  EXPECT_EQ(mProducer->TakeAsParcelable(&dummy_producer_parcelable), BAD_VALUE);
+  EXPECT_FALSE(producer_parcelable.IsValid());
+  EXPECT_EQ(mProducer->TakeAsParcelable(&producer_parcelable), NO_ERROR);
+  EXPECT_TRUE(producer_parcelable.IsValid());
+
+  // Should still be able to query buffer dimension after disconnect.
+  int32_t value = -1;
+  EXPECT_EQ(NO_ERROR, mProducer->query(NATIVE_WINDOW_WIDTH, &value));
+  EXPECT_EQ(static_cast<uint32_t>(value), kDefaultWidth);
+
+  EXPECT_EQ(mProducer->query(NATIVE_WINDOW_HEIGHT, &value), NO_ERROR);
+  EXPECT_EQ(static_cast<uint32_t>(value), kDefaultHeight);
+
+  EXPECT_EQ(mProducer->query(NATIVE_WINDOW_FORMAT, &value), NO_ERROR);
+  EXPECT_EQ(value, kDefaultFormat);
+
+  // But connect to API will fail.
+  IGraphicBufferProducer::QueueBufferOutput output;
+  EXPECT_EQ(mProducer->connect(kDummyListener, kTestApi, kTestControlledByApp,
+                               &output),
+            BAD_VALUE);
+
+  // Create a new producer from the parcelable and connect to kTestApi should
+  // succeed.
+  sp<BufferHubProducer> new_producer =
+      BufferHubProducer::Create(std::move(producer_parcelable));
+  ASSERT_TRUE(new_producer != nullptr);
+  EXPECT_EQ(new_producer->connect(kDummyListener, kTestApi,
+                                  kTestControlledByApp, &output),
+            NO_ERROR);
+}
+
 }  // namespace
 
 }  // namespace dvr
diff --git a/libs/vr/libdisplay/Android.bp b/libs/vr/libdisplay/Android.bp
index aa9f288..9c67881 100644
--- a/libs/vr/libdisplay/Android.bp
+++ b/libs/vr/libdisplay/Android.bp
@@ -26,6 +26,8 @@
 
 sharedLibraries = [
     "libbase",
+    "libbinder",
+    "libbufferhubqueue",
     "libcutils",
     "liblog",
     "libutils",
@@ -34,14 +36,12 @@
     "libhardware",
     "libsync",
     "libnativewindow",
+    "libpdx_default_transport",
 ]
 
 staticLibraries = [
     "libdvrcommon",
-    "libbufferhubqueue",
-    "libbufferhub",
     "libbroadcastring",
-    "libpdx_default_transport",
 ]
 
 headerLibraries = [
diff --git a/libs/vr/libdisplay/display_client.cpp b/libs/vr/libdisplay/display_client.cpp
index 442c82d..f67e258 100644
--- a/libs/vr/libdisplay/display_client.cpp
+++ b/libs/vr/libdisplay/display_client.cpp
@@ -9,7 +9,6 @@
 #include <mutex>
 
 #include <private/dvr/display_protocol.h>
-#include <private/dvr/native_buffer.h>
 
 using android::pdx::ErrorStatus;
 using android::pdx::LocalHandle;
diff --git a/libs/vr/libdvr/Android.bp b/libs/vr/libdvr/Android.bp
index 04418d2..16906f5 100644
--- a/libs/vr/libdvr/Android.bp
+++ b/libs/vr/libdvr/Android.bp
@@ -15,8 +15,8 @@
 
 cc_library_headers {
     name: "libdvr_headers",
-    owner: "google",
     export_include_dirs: ["include"],
+    vendor_available: true,
 }
 
 cflags = [
@@ -41,8 +41,6 @@
 
 static_libs = [
     "libbroadcastring",
-    "libbufferhub",
-    "libbufferhubqueue",
     "libvrsensor",
     "libdisplay",
     "libvirtualtouchpadclient",
@@ -50,13 +48,13 @@
     "libvr_hwc-binder",
     "libgrallocusage",
     "libperformance",
-    "libpdx_default_transport",
 ]
 
 shared_libs = [
     "android.hardware.graphics.bufferqueue@1.0",
     "android.hidl.token@1.0-utils",
     "libbase",
+    "libbufferhubqueue",
     "libbinder",
     "liblog",
     "libcutils",
@@ -64,6 +62,7 @@
     "libnativewindow",
     "libgui",
     "libui",
+    "libpdx_default_transport",
 ]
 
 cc_library_shared {
diff --git a/libs/vr/libdvr/dvr_api.cpp b/libs/vr/libdvr/dvr_api.cpp
index 7d4e2d1..d14f040 100644
--- a/libs/vr/libdvr/dvr_api.cpp
+++ b/libs/vr/libdvr/dvr_api.cpp
@@ -41,10 +41,19 @@
     }                                                          \
   } while (0)
 
+#define DVR_V1_API_ENTRY_DEPRECATED(name)                      \
+  do {                                                         \
+    if ((offsetof(DvrApi_v1, name) + sizeof(dvr_api->name)) <= \
+        clamped_struct_size) {                                 \
+      dvr_api->name = nullptr;                                 \
+    }                                                          \
+  } while (0)
+
 #include "include/dvr/dvr_api_entries.h"
 
 // Undefine macro definitions to play nice with Google3 style rules.
 #undef DVR_V1_API_ENTRY
+#undef DVR_V1_API_ENTRY_DEPRECATED
 
     return 0;
   }
diff --git a/libs/vr/libdvr/dvr_buffer.cpp b/libs/vr/libdvr/dvr_buffer.cpp
index 1a99234..baf1f2f 100644
--- a/libs/vr/libdvr/dvr_buffer.cpp
+++ b/libs/vr/libdvr/dvr_buffer.cpp
@@ -38,17 +38,13 @@
 
 extern "C" {
 
-void dvrWriteBufferCreateEmpty(DvrWriteBuffer** write_buffer) {
-  if (write_buffer)
-    *write_buffer = new DvrWriteBuffer;
-}
-
 void dvrWriteBufferDestroy(DvrWriteBuffer* write_buffer) {
   if (write_buffer != nullptr) {
     ALOGW_IF(
         write_buffer->slot != -1,
         "dvrWriteBufferDestroy: Destroying a buffer associated with a valid "
-        "buffer queue slot. This may indicate possible leaks.");
+        "buffer queue slot. This may indicate possible leaks, buffer_id=%d.",
+        dvrWriteBufferGetId(write_buffer));
     delete write_buffer;
   }
 }
@@ -57,14 +53,6 @@
   return write_buffer && write_buffer->write_buffer;
 }
 
-int dvrWriteBufferClear(DvrWriteBuffer* write_buffer) {
-  if (!write_buffer)
-    return -EINVAL;
-
-  write_buffer->write_buffer = nullptr;
-  return 0;
-}
-
 int dvrWriteBufferGetId(DvrWriteBuffer* write_buffer) {
   if (!write_buffer || !write_buffer->write_buffer)
     return -EINVAL;
@@ -81,44 +69,13 @@
       write_buffer->write_buffer->buffer()->buffer().get(), hardware_buffer);
 }
 
-int dvrWriteBufferPost(DvrWriteBuffer* write_buffer, int ready_fence_fd,
-                       const void* meta, size_t meta_size_bytes) {
-  if (!write_buffer || !write_buffer->write_buffer)
-    return -EINVAL;
-
-  pdx::LocalHandle fence(ready_fence_fd);
-  int result = write_buffer->write_buffer->Post(fence, meta, meta_size_bytes);
-  return result;
-}
-
-int dvrWriteBufferGain(DvrWriteBuffer* write_buffer, int* release_fence_fd) {
-  if (!write_buffer || !write_buffer->write_buffer || !release_fence_fd)
-    return -EINVAL;
-
-  pdx::LocalHandle release_fence;
-  int result = write_buffer->write_buffer->Gain(&release_fence);
-  *release_fence_fd = release_fence.Release();
-  return result;
-}
-
-int dvrWriteBufferGainAsync(DvrWriteBuffer* write_buffer) {
-  if (!write_buffer || !write_buffer->write_buffer)
-    return -EINVAL;
-
-  return write_buffer->write_buffer->GainAsync();
-}
-
-void dvrReadBufferCreateEmpty(DvrReadBuffer** read_buffer) {
-  if (read_buffer)
-    *read_buffer = new DvrReadBuffer;
-}
-
 void dvrReadBufferDestroy(DvrReadBuffer* read_buffer) {
   if (read_buffer != nullptr) {
     ALOGW_IF(
         read_buffer->slot != -1,
         "dvrReadBufferDestroy: Destroying a buffer associated with a valid "
-        "buffer queue slot. This may indicate possible leaks.");
+        "buffer queue slot. This may indicate possible leaks, buffer_id=%d.",
+        dvrReadBufferGetId(read_buffer));
     delete read_buffer;
   }
 }
@@ -127,14 +84,6 @@
   return read_buffer && read_buffer->read_buffer;
 }
 
-int dvrReadBufferClear(DvrReadBuffer* read_buffer) {
-  if (!read_buffer)
-    return -EINVAL;
-
-  read_buffer->read_buffer = nullptr;
-  return 0;
-}
-
 int dvrReadBufferGetId(DvrReadBuffer* read_buffer) {
   if (!read_buffer || !read_buffer->read_buffer)
     return -EINVAL;
@@ -151,34 +100,6 @@
       read_buffer->read_buffer->buffer()->buffer().get(), hardware_buffer);
 }
 
-int dvrReadBufferAcquire(DvrReadBuffer* read_buffer, int* ready_fence_fd,
-                         void* meta, size_t meta_size_bytes) {
-  if (!read_buffer || !read_buffer->read_buffer)
-    return -EINVAL;
-
-  pdx::LocalHandle ready_fence;
-  int result =
-      read_buffer->read_buffer->Acquire(&ready_fence, meta, meta_size_bytes);
-  *ready_fence_fd = ready_fence.Release();
-  return result;
-}
-
-int dvrReadBufferRelease(DvrReadBuffer* read_buffer, int release_fence_fd) {
-  if (!read_buffer || !read_buffer->read_buffer)
-    return -EINVAL;
-
-  pdx::LocalHandle fence(release_fence_fd);
-  int result = read_buffer->read_buffer->Release(fence);
-  return result;
-}
-
-int dvrReadBufferReleaseAsync(DvrReadBuffer* read_buffer) {
-  if (!read_buffer || !read_buffer->read_buffer)
-    return -EINVAL;
-
-  return read_buffer->read_buffer->ReleaseAsync();
-}
-
 void dvrBufferDestroy(DvrBuffer* buffer) { delete buffer; }
 
 int dvrBufferGetAHardwareBuffer(DvrBuffer* buffer,
@@ -196,27 +117,4 @@
   return android::dvr::kSharedBufferLayoutVersion;
 }
 
-const struct native_handle* dvrWriteBufferGetNativeHandle(
-    DvrWriteBuffer* write_buffer) {
-  if (!write_buffer || !write_buffer->write_buffer)
-    return nullptr;
-
-  return write_buffer->write_buffer->native_handle();
-}
-
-const struct native_handle* dvrReadBufferGetNativeHandle(
-    DvrReadBuffer* read_buffer) {
-  if (!read_buffer || !read_buffer->read_buffer)
-    return nullptr;
-
-  return read_buffer->read_buffer->native_handle();
-}
-
-const struct native_handle* dvrBufferGetNativeHandle(DvrBuffer* buffer) {
-  if (!buffer || !buffer->buffer)
-    return nullptr;
-
-  return buffer->buffer->handle();
-}
-
 }  // extern "C"
diff --git a/libs/vr/libdvr/dvr_buffer_queue.cpp b/libs/vr/libdvr/dvr_buffer_queue.cpp
index 09a49dd..74cee3f 100644
--- a/libs/vr/libdvr/dvr_buffer_queue.cpp
+++ b/libs/vr/libdvr/dvr_buffer_queue.cpp
@@ -2,7 +2,7 @@
 #include "include/dvr/dvr_buffer_queue.h"
 
 #include <android/native_window.h>
-#include <private/dvr/buffer_hub_queue_producer.h>
+#include <gui/BufferHubProducer.h>
 
 #include "dvr_internal.h"
 #include "dvr_buffer_queue_internal.h"
@@ -10,7 +10,6 @@
 using namespace android;
 using android::dvr::BufferConsumer;
 using android::dvr::BufferHubBuffer;
-using android::dvr::BufferHubQueueProducer;
 using android::dvr::BufferProducer;
 using android::dvr::ConsumerQueue;
 using android::dvr::ProducerQueue;
@@ -30,8 +29,7 @@
   if (native_window_ == nullptr) {
     // Lazy creation of |native_window|, as not everyone is using
     // DvrWriteBufferQueue as an external surface.
-    sp<IGraphicBufferProducer> gbp =
-        BufferHubQueueProducer::Create(producer_queue_);
+    sp<IGraphicBufferProducer> gbp = BufferHubProducer::Create(producer_queue_);
     native_window_ = new Surface(gbp, true);
   }
 
@@ -275,14 +273,6 @@
   return write_queue->id();
 }
 
-int dvrWriteBufferQueueGetExternalSurface(DvrWriteBufferQueue* write_queue,
-                                          ANativeWindow** out_window) {
-  ALOGW(
-      "dvrWriteBufferQueueGetExternalSurface: This API has been deprecated and "
-      "renamed to dvrWriteBufferQueueGetANativeWindow.");
-  return dvrWriteBufferQueueGetANativeWindow(write_queue, out_window);
-}
-
 int dvrWriteBufferQueueGetANativeWindow(DvrWriteBufferQueue* write_queue,
                                         ANativeWindow** out_window) {
   if (!write_queue || !out_window)
@@ -299,15 +289,6 @@
   return write_queue->CreateReadQueue(out_read_queue);
 }
 
-int dvrWriteBufferQueueDequeue(DvrWriteBufferQueue* write_queue, int timeout,
-                               DvrWriteBuffer* write_buffer,
-                               int* out_fence_fd) {
-  if (!write_queue || !write_buffer || !out_fence_fd)
-    return -EINVAL;
-
-  return write_queue->Dequeue(timeout, write_buffer, out_fence_fd);
-}
-
 int dvrWriteBufferQueueGainBuffer(DvrWriteBufferQueue* write_queue, int timeout,
                                   DvrWriteBuffer** out_write_buffer,
                                   DvrNativeBufferMetadata* out_meta,
@@ -357,34 +338,6 @@
   return 0;
 }
 
-int DvrReadBufferQueue::Dequeue(int timeout, DvrReadBuffer* read_buffer,
-                                int* out_fence_fd, void* out_meta,
-                                size_t meta_size_bytes) {
-  if (meta_size_bytes != consumer_queue_->metadata_size()) {
-    ALOGE(
-        "DvrReadBufferQueue::Dequeue: Invalid metadata size, expected (%zu), "
-        "but actual (%zu).",
-        consumer_queue_->metadata_size(), meta_size_bytes);
-    return -EINVAL;
-  }
-
-  size_t slot;
-  pdx::LocalHandle acquire_fence;
-  auto buffer_status = consumer_queue_->Dequeue(
-      timeout, &slot, out_meta, meta_size_bytes, &acquire_fence);
-  if (!buffer_status) {
-    ALOGE_IF(buffer_status.error() != ETIMEDOUT,
-             "dvrReadBufferQueueDequeue: Failed to dequeue buffer: %s",
-             buffer_status.GetErrorMessage().c_str());
-    return -buffer_status.error();
-  }
-
-  read_buffer->read_buffer = buffer_status.take();
-  *out_fence_fd = acquire_fence.Release();
-
-  return 0;
-}
-
 int DvrReadBufferQueue::AcquireBuffer(int timeout,
                                       DvrReadBuffer** out_read_buffer,
                                       DvrNativeBufferMetadata* out_meta,
@@ -436,12 +389,22 @@
     return -EINVAL;
   }
   if (read_buffer->read_buffer->id() != consumer_queue_->GetBufferId(slot)) {
-    ALOGE(
-        "DvrReadBufferQueue::ReleaseBuffer: Buffer to be released does not "
-        "belong to this buffer queue. Releasing buffer: id=%d, buffer in "
-        "queue: id=%d",
-        read_buffer->read_buffer->id(), consumer_queue_->GetBufferId(slot));
-    return -EINVAL;
+    if (consumer_queue_->GetBufferId(slot) > 0) {
+      ALOGE(
+          "DvrReadBufferQueue::ReleaseBuffer: Buffer to be released may not "
+          "belong to this queue (queue_id=%d): attempting to release buffer "
+          "(buffer_id=%d) at slot %d which holds a different buffer "
+          "(buffer_id=%d).",
+          consumer_queue_->id(), read_buffer->read_buffer->id(),
+          static_cast<int>(slot), consumer_queue_->GetBufferId(slot));
+    } else {
+      ALOGI(
+          "DvrReadBufferQueue::ReleaseBuffer: Buffer to be released may not "
+          "belong to this queue (queue_id=%d): attempting to release buffer "
+          "(buffer_id=%d) at slot %d which is empty.",
+          consumer_queue_->id(), read_buffer->read_buffer->id(),
+          static_cast<int>(slot));
+    }
   }
 
   pdx::LocalHandle fence(release_fence_fd);
diff --git a/libs/vr/libdvr/include/dvr/dvr_api.h b/libs/vr/libdvr/include/dvr/dvr_api.h
index 499b7c1..80ffc82 100644
--- a/libs/vr/libdvr/include/dvr/dvr_api.h
+++ b/libs/vr/libdvr/include/dvr/dvr_api.h
@@ -443,11 +443,13 @@
 struct DvrApi_v1 {
 // Defines an API entry for V1 (no version suffix).
 #define DVR_V1_API_ENTRY(name) Dvr##name##Ptr name
+#define DVR_V1_API_ENTRY_DEPRECATED(name) Dvr##name##Ptr name
 
 #include "dvr_api_entries.h"
 
 // Undefine macro definitions to play nice with Google3 style rules.
 #undef DVR_V1_API_ENTRY
+#undef DVR_V1_API_ENTRY_DEPRECATED
 };
 
 int dvrGetApi(void* api, size_t struct_size, int version);
diff --git a/libs/vr/libdvr/include/dvr/dvr_api_entries.h b/libs/vr/libdvr/include/dvr/dvr_api_entries.h
index cce8c7e..f0d8ec6 100644
--- a/libs/vr/libdvr/include/dvr/dvr_api_entries.h
+++ b/libs/vr/libdvr/include/dvr/dvr_api_entries.h
@@ -8,6 +8,10 @@
 #error Do not include this header directly.
 #endif
 
+#ifndef DVR_V1_API_ENTRY_DEPRECATED
+#error Do not include this header directly.
+#endif
+
 // Do not delete this line: BEGIN CODEGEN OUTPUT
 // Display manager client
 DVR_V1_API_ENTRY(DisplayManagerCreate);
@@ -32,42 +36,42 @@
 DVR_V1_API_ENTRY(SurfaceStateGetAttributes);
 
 // Write buffer
-DVR_V1_API_ENTRY(WriteBufferCreateEmpty);
+DVR_V1_API_ENTRY_DEPRECATED(WriteBufferCreateEmpty);
 DVR_V1_API_ENTRY(WriteBufferDestroy);
 DVR_V1_API_ENTRY(WriteBufferIsValid);
-DVR_V1_API_ENTRY(WriteBufferClear);
+DVR_V1_API_ENTRY_DEPRECATED(WriteBufferClear);
 DVR_V1_API_ENTRY(WriteBufferGetId);
 DVR_V1_API_ENTRY(WriteBufferGetAHardwareBuffer);
-DVR_V1_API_ENTRY(WriteBufferPost);
-DVR_V1_API_ENTRY(WriteBufferGain);
-DVR_V1_API_ENTRY(WriteBufferGainAsync);
-DVR_V1_API_ENTRY(WriteBufferGetNativeHandle);
+DVR_V1_API_ENTRY_DEPRECATED(WriteBufferPost);
+DVR_V1_API_ENTRY_DEPRECATED(WriteBufferGain);
+DVR_V1_API_ENTRY_DEPRECATED(WriteBufferGainAsync);
+DVR_V1_API_ENTRY_DEPRECATED(WriteBufferGetNativeHandle);
 
 // Read buffer
-DVR_V1_API_ENTRY(ReadBufferCreateEmpty);
+DVR_V1_API_ENTRY_DEPRECATED(ReadBufferCreateEmpty);
 DVR_V1_API_ENTRY(ReadBufferDestroy);
 DVR_V1_API_ENTRY(ReadBufferIsValid);
-DVR_V1_API_ENTRY(ReadBufferClear);
+DVR_V1_API_ENTRY_DEPRECATED(ReadBufferClear);
 DVR_V1_API_ENTRY(ReadBufferGetId);
 DVR_V1_API_ENTRY(ReadBufferGetAHardwareBuffer);
-DVR_V1_API_ENTRY(ReadBufferAcquire);
-DVR_V1_API_ENTRY(ReadBufferRelease);
-DVR_V1_API_ENTRY(ReadBufferReleaseAsync);
-DVR_V1_API_ENTRY(ReadBufferGetNativeHandle);
+DVR_V1_API_ENTRY_DEPRECATED(ReadBufferAcquire);
+DVR_V1_API_ENTRY_DEPRECATED(ReadBufferRelease);
+DVR_V1_API_ENTRY_DEPRECATED(ReadBufferReleaseAsync);
+DVR_V1_API_ENTRY_DEPRECATED(ReadBufferGetNativeHandle);
 
 // Buffer
 DVR_V1_API_ENTRY(BufferDestroy);
 DVR_V1_API_ENTRY(BufferGetAHardwareBuffer);
-DVR_V1_API_ENTRY(BufferGetNativeHandle);
+DVR_V1_API_ENTRY_DEPRECATED(BufferGetNativeHandle);
 DVR_V1_API_ENTRY(BufferGlobalLayoutVersionGet);
 
 // Write buffer queue
 DVR_V1_API_ENTRY(WriteBufferQueueDestroy);
 DVR_V1_API_ENTRY(WriteBufferQueueGetCapacity);
 DVR_V1_API_ENTRY(WriteBufferQueueGetId);
-DVR_V1_API_ENTRY(WriteBufferQueueGetExternalSurface);  // deprecated
+DVR_V1_API_ENTRY_DEPRECATED(WriteBufferQueueGetExternalSurface);
 DVR_V1_API_ENTRY(WriteBufferQueueCreateReadQueue);
-DVR_V1_API_ENTRY(WriteBufferQueueDequeue);
+DVR_V1_API_ENTRY_DEPRECATED(WriteBufferQueueDequeue);
 DVR_V1_API_ENTRY(WriteBufferQueueResizeBuffer);
 
 // Read buffer queue
@@ -75,7 +79,7 @@
 DVR_V1_API_ENTRY(ReadBufferQueueGetCapacity);
 DVR_V1_API_ENTRY(ReadBufferQueueGetId);
 DVR_V1_API_ENTRY(ReadBufferQueueCreateReadQueue);
-DVR_V1_API_ENTRY(ReadBufferQueueDequeue);
+DVR_V1_API_ENTRY_DEPRECATED(ReadBufferQueueDequeue);
 DVR_V1_API_ENTRY(ReadBufferQueueSetBufferAvailableCallback);
 DVR_V1_API_ENTRY(ReadBufferQueueSetBufferRemovedCallback);
 DVR_V1_API_ENTRY(ReadBufferQueueHandleEvents);
diff --git a/libs/vr/libdvr/include/dvr/dvr_buffer.h b/libs/vr/libdvr/include/dvr/dvr_buffer.h
index 935a7b2..4234844 100644
--- a/libs/vr/libdvr/include/dvr/dvr_buffer.h
+++ b/libs/vr/libdvr/include/dvr/dvr_buffer.h
@@ -14,20 +14,12 @@
 typedef struct AHardwareBuffer AHardwareBuffer;
 struct native_handle;
 
-// Creates an empty write buffer that may be filled with an acutal buffer by
-// other functions.
-void dvrWriteBufferCreateEmpty(DvrWriteBuffer** write_buffer);
-
 // Destroys the write buffer.
 void dvrWriteBufferDestroy(DvrWriteBuffer* write_buffer);
 
 // Returns 1 if the given write buffer object contains a buffer, 0 otherwise.
 int dvrWriteBufferIsValid(DvrWriteBuffer* write_buffer);
 
-// Clears the contents of the buffer object. After a call to this function
-// dvrWriteBufferIsValid on the same buffer object returns 0.
-int dvrWriteBufferClear(DvrWriteBuffer* write_buffer);
-
 // Returns the global BufferHub id of this buffer.
 int dvrWriteBufferGetId(DvrWriteBuffer* write_buffer);
 
@@ -36,34 +28,12 @@
 int dvrWriteBufferGetAHardwareBuffer(DvrWriteBuffer* write_buffer,
                                      AHardwareBuffer** hardware_buffer);
 
-// Posts the buffer, notifying any connected read buffers. Takes ownership of
-// |ready_fence_fd|.
-int dvrWriteBufferPost(DvrWriteBuffer* write_buffer, int ready_fence_fd,
-                       const void* meta, size_t meta_size_bytes);
-
-// Gains a buffer that has been released by all connected read buffers.
-int dvrWriteBufferGain(DvrWriteBuffer* write_buffer, int* release_fence_fd);
-int dvrWriteBufferGainAsync(DvrWriteBuffer* write_buffer);
-
-// TODO(eieio): Switch to return int and take an out parameter for the native
-// handle.
-const struct native_handle* dvrWriteBufferGetNativeHandle(
-    DvrWriteBuffer* write_buffer);
-
-// Creates an empty read buffer that may be filled with and actual buffer by
-// other functions.
-void dvrReadBufferCreateEmpty(DvrReadBuffer** read_buffer);
-
 // Destroys the read buffer.
 void dvrReadBufferDestroy(DvrReadBuffer* read_buffer);
 
 // Returns 1 if the given write buffer object contains a buffer, 0 otherwise.
 int dvrReadBufferIsValid(DvrReadBuffer* read_buffer);
 
-// Clears the contents of the buffer object. After a call to this function
-// dvrReadBufferIsValid on the same buffer object returns 0.
-int dvrReadBufferClear(DvrReadBuffer* read_buffer);
-
 // Returns the global BufferHub id of this buffer.
 int dvrReadBufferGetId(DvrReadBuffer* read_buffer);
 
@@ -72,21 +42,6 @@
 int dvrReadBufferGetAHardwareBuffer(DvrReadBuffer* read_buffer,
                                     AHardwareBuffer** hardware_buffer);
 
-// Acquires the read buffer after it has been posted by the write buffer it is
-// connected to.
-int dvrReadBufferAcquire(DvrReadBuffer* read_buffer, int* ready_fence_fd,
-                         void* meta, size_t meta_size_bytes);
-
-// Releases the read buffer, notifying the write buffer it is connected to.
-// Takes ownership of |release_fence_fd|.
-int dvrReadBufferRelease(DvrReadBuffer* read_buffer, int release_fence_fd);
-int dvrReadBufferReleaseAsync(DvrReadBuffer* read_buffer);
-
-// TODO(eieio): Switch to return int and take an out parameter for the native
-// handle.
-const struct native_handle* dvrReadBufferGetNativeHandle(
-    DvrReadBuffer* read_buffer);
-
 // Destroys the buffer.
 void dvrBufferDestroy(DvrBuffer* buffer);
 
@@ -98,10 +53,6 @@
 // Retrieve the shared buffer layout version defined in dvr_shared_buffers.h.
 int dvrBufferGlobalLayoutVersionGet();
 
-// TODO(eieio): Switch to return int and take an out parameter for the native
-// handle.
-const struct native_handle* dvrBufferGetNativeHandle(DvrBuffer* buffer);
-
 __END_DECLS
 
 #endif  // ANDROID_DVR_BUFFER_H_
diff --git a/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h b/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h
index bf695c7..ac789da 100644
--- a/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h
+++ b/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h
@@ -76,10 +76,6 @@
 int dvrWriteBufferQueueGetANativeWindow(DvrWriteBufferQueue* write_queue,
                                         ANativeWindow** out_window);
 
-// @deprecated Please use dvrWriteBufferQueueGetANativeWindow instead.
-int dvrWriteBufferQueueGetExternalSurface(DvrWriteBufferQueue* write_queue,
-                                          ANativeWindow** out_window);
-
 // Create a read buffer queue from an existing write buffer queue.
 //
 // @param write_queue The DvrWriteBufferQueue of interest.
@@ -89,10 +85,6 @@
 int dvrWriteBufferQueueCreateReadQueue(DvrWriteBufferQueue* write_queue,
                                        DvrReadBufferQueue** out_read_queue);
 
-// @deprecated Please use dvrWriteBufferQueueGainBuffer instead.
-int dvrWriteBufferQueueDequeue(DvrWriteBufferQueue* write_queue, int timeout,
-                               DvrWriteBuffer* out_buffer, int* out_fence_fd);
-
 // Gains a buffer to write into.
 //
 // @param write_queue The DvrWriteBufferQueue to gain buffer from.
@@ -176,11 +168,6 @@
 int dvrReadBufferQueueCreateReadQueue(DvrReadBufferQueue* read_queue,
                                       DvrReadBufferQueue** out_read_queue);
 
-// @deprecated Please use dvrReadBufferQueueAcquireBuffer instead.
-int dvrReadBufferQueueDequeue(DvrReadBufferQueue* read_queue, int timeout,
-                              DvrReadBuffer* out_buffer, int* out_fence_fd,
-                              void* out_meta, size_t meta_size_bytes);
-
 // Dequeues a buffer to read from.
 //
 // @param read_queue The DvrReadBufferQueue to acquire buffer from.
diff --git a/libs/vr/libdvr/tests/Android.bp b/libs/vr/libdvr/tests/Android.bp
index 887766a..1ae75fb 100644
--- a/libs/vr/libdvr/tests/Android.bp
+++ b/libs/vr/libdvr/tests/Android.bp
@@ -15,6 +15,7 @@
 shared_libraries = [
     "libbase",
     "libbinder",
+    "libbufferhubqueue",
     "libcutils",
     "libgui",
     "liblog",
@@ -22,22 +23,19 @@
     "libui",
     "libutils",
     "libnativewindow",
+    "libpdx_default_transport",
 ]
 
 static_libraries = [
     "libdvr_static",
-    "libbufferhubqueue",
-    "libbufferhub",
     "libchrome",
     "libdvrcommon",
     "libdisplay",
-    "libpdx_default_transport",
     "libbroadcastring",
 ]
 
 cc_test {
     srcs: [
-        "dvr_buffer_queue-test.cpp",
         "dvr_display_manager-test.cpp",
         "dvr_named_buffer-test.cpp",
     ],
diff --git a/libs/vr/libdvr/tests/Android.mk b/libs/vr/libdvr/tests/Android.mk
new file mode 100644
index 0000000..0f3840d
--- /dev/null
+++ b/libs/vr/libdvr/tests/Android.mk
@@ -0,0 +1,73 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+# TODO(b/73133405): Currently, building cc_test against NDK using Android.bp
+# doesn't work well. Migrate to use Android.bp once b/73133405 gets fixed.
+
+include $(CLEAR_VARS)
+LOCAL_MODULE:= dvr_buffer_queue-test
+
+# Includes the dvr_api.h header. Tests should only include "dvr_api.h",
+# and shall only get access to |dvrGetApi|, as other symbols are hidden from the
+# library.
+LOCAL_C_INCLUDES := \
+    frameworks/native/libs/vr/libdvr/include \
+
+LOCAL_SANITIZE := thread
+
+LOCAL_SRC_FILES := dvr_buffer_queue-test.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+    libandroid \
+    liblog \
+
+LOCAL_CFLAGS := \
+    -DTRACE=0 \
+    -O2 \
+    -g \
+
+# DTS Should only link to NDK libraries.
+LOCAL_SDK_VERSION := 26
+LOCAL_NDK_STL_VARIANT := c++_static
+
+include $(BUILD_NATIVE_TEST)
+
+
+include $(CLEAR_VARS)
+LOCAL_MODULE:= dvr_display-test
+
+LOCAL_C_INCLUDES := \
+    frameworks/native/libs/vr/libdvr/include \
+    frameworks/native/libs/nativewindow/include
+
+LOCAL_SANITIZE := thread
+
+LOCAL_SRC_FILES := dvr_display-test.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+    libandroid \
+    liblog
+
+LOCAL_CFLAGS := \
+    -DTRACE=0 \
+    -O2 \
+    -g
+
+# DTS Should only link to NDK libraries.
+LOCAL_SDK_VERSION := 26
+LOCAL_NDK_STL_VARIANT := c++_static
+
+include $(BUILD_NATIVE_TEST)
\ No newline at end of file
diff --git a/libs/vr/libdvr/tests/dvr_api_test.h b/libs/vr/libdvr/tests/dvr_api_test.h
new file mode 100644
index 0000000..d8359e7
--- /dev/null
+++ b/libs/vr/libdvr/tests/dvr_api_test.h
@@ -0,0 +1,36 @@
+#include <dlfcn.h>
+#include <dvr/dvr_api.h>
+
+#include <gtest/gtest.h>
+
+/** DvrTestBase loads the libdvr.so at runtime and get the Dvr API version 1. */
+class DvrApiTest : public ::testing::Test {
+ protected:
+  void SetUp() override {
+    int flags = RTLD_NOW | RTLD_LOCAL;
+
+    // Here we need to ensure that libdvr is loaded with RTLD_NODELETE flag set
+    // (so that calls to `dlclose` don't actually unload the library). This is a
+    // workaround for an Android NDK bug. See more detail:
+    // https://github.com/android-ndk/ndk/issues/360
+    flags |= RTLD_NODELETE;
+    platform_handle_ = dlopen("libdvr.so", flags);
+    ASSERT_NE(nullptr, platform_handle_) << "Dvr shared library missing.";
+
+    auto dvr_get_api = reinterpret_cast<decltype(&dvrGetApi)>(
+        dlsym(platform_handle_, "dvrGetApi"));
+    ASSERT_NE(nullptr, dvr_get_api) << "Platform library missing dvrGetApi.";
+
+    ASSERT_EQ(dvr_get_api(&api_, sizeof(api_), /*version=*/1), 0)
+        << "Unable to find compatible Dvr API.";
+  }
+
+  void TearDown() override {
+    if (platform_handle_ != nullptr) {
+      dlclose(platform_handle_);
+    }
+  }
+
+  void* platform_handle_ = nullptr;
+  DvrApi_v1 api_;
+};
diff --git a/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp b/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
index 62cd8d4..2d5f004 100644
--- a/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
+++ b/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
@@ -1,6 +1,5 @@
 #include <android/log.h>
 #include <android/native_window.h>
-#include <android-base/unique_fd.h>
 #include <dvr/dvr_api.h>
 #include <dvr/dvr_buffer_queue.h>
 
@@ -9,6 +8,10 @@
 #include <array>
 #include <unordered_map>
 
+#include "dvr_api_test.h"
+
+#define LOG_TAG "dvr_buffer_queue-test"
+
 #ifndef ALOGD
 #define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
 #endif
@@ -27,7 +30,7 @@
 static constexpr uint64_t kBufferUsage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN;
 static constexpr size_t kQueueCapacity = 3;
 
-class DvrBufferQueueTest : public ::testing::Test {
+class DvrBufferQueueTest : public DvrApiTest {
  public:
   static void BufferAvailableCallback(void* context) {
     DvrBufferQueueTest* thiz = static_cast<DvrBufferQueueTest*>(context);
@@ -42,9 +45,10 @@
  protected:
   void TearDown() override {
     if (write_queue_ != nullptr) {
-      dvrWriteBufferQueueDestroy(write_queue_);
+      api_.WriteBufferQueueDestroy(write_queue_);
       write_queue_ = nullptr;
     }
+    DvrApiTest::TearDown();
   }
 
   void HandleBufferAvailable() {
@@ -64,85 +68,85 @@
 };
 
 TEST_F(DvrBufferQueueTest, WriteQueueCreateDestroy) {
-  int ret = dvrWriteBufferQueueCreate(
+  int ret = api_.WriteBufferQueueCreate(
       kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
       /*capacity=*/0, sizeof(DvrNativeBufferMetadata), &write_queue_);
   ASSERT_EQ(0, ret);
 
-  dvrWriteBufferQueueDestroy(write_queue_);
+  api_.WriteBufferQueueDestroy(write_queue_);
   write_queue_ = nullptr;
 }
 
 TEST_F(DvrBufferQueueTest, WriteQueueGetCapacity) {
-  int ret = dvrWriteBufferQueueCreate(
+  int ret = api_.WriteBufferQueueCreate(
       kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
       kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_);
   ASSERT_EQ(0, ret);
 
-  size_t capacity = dvrWriteBufferQueueGetCapacity(write_queue_);
+  size_t capacity = api_.WriteBufferQueueGetCapacity(write_queue_);
 
   ALOGD_IF(TRACE, "TestWrite_QueueGetCapacity, capacity=%zu", capacity);
   ASSERT_EQ(kQueueCapacity, capacity);
 }
 
 TEST_F(DvrBufferQueueTest, CreateReadQueueFromWriteQueue) {
-  int ret = dvrWriteBufferQueueCreate(
+  int ret = api_.WriteBufferQueueCreate(
       kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
       /*capacity=*/0, sizeof(DvrNativeBufferMetadata), &write_queue_);
   ASSERT_EQ(0, ret);
 
   DvrReadBufferQueue* read_queue = nullptr;
-  ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
+  ret = api_.WriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
 
   ASSERT_EQ(0, ret);
   ASSERT_NE(nullptr, read_queue);
 
-  dvrReadBufferQueueDestroy(read_queue);
+  api_.ReadBufferQueueDestroy(read_queue);
 }
 
 TEST_F(DvrBufferQueueTest, CreateReadQueueFromReadQueue) {
-  int ret = dvrWriteBufferQueueCreate(
+  int ret = api_.WriteBufferQueueCreate(
       kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
       /*capacity=*/0, sizeof(DvrNativeBufferMetadata), &write_queue_);
   ASSERT_EQ(0, ret);
 
   DvrReadBufferQueue* read_queue1 = nullptr;
   DvrReadBufferQueue* read_queue2 = nullptr;
-  ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue1);
+  ret = api_.WriteBufferQueueCreateReadQueue(write_queue_, &read_queue1);
 
   ASSERT_EQ(0, ret);
   ASSERT_NE(nullptr, read_queue1);
 
-  ret = dvrReadBufferQueueCreateReadQueue(read_queue1, &read_queue2);
+  ret = api_.ReadBufferQueueCreateReadQueue(read_queue1, &read_queue2);
   ASSERT_EQ(0, ret);
   ASSERT_NE(nullptr, read_queue2);
   ASSERT_NE(read_queue1, read_queue2);
 
-  dvrReadBufferQueueDestroy(read_queue1);
-  dvrReadBufferQueueDestroy(read_queue2);
+  api_.ReadBufferQueueDestroy(read_queue1);
+  api_.ReadBufferQueueDestroy(read_queue2);
 }
 
 TEST_F(DvrBufferQueueTest, GainBuffer) {
-  int ret = dvrWriteBufferQueueCreate(
+  int ret = api_.WriteBufferQueueCreate(
       kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
       kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_);
   ASSERT_EQ(ret, 0);
 
   DvrWriteBuffer* wb = nullptr;
-  EXPECT_FALSE(dvrWriteBufferIsValid(wb));
+  EXPECT_FALSE(api_.WriteBufferIsValid(wb));
 
   DvrNativeBufferMetadata meta;
   int fence_fd = -1;
-  ret = dvrWriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb, &meta,
-                                      &fence_fd);
+  ret = api_.WriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb, &meta,
+                                        &fence_fd);
   ASSERT_EQ(ret, 0);
   EXPECT_EQ(fence_fd, -1);
   EXPECT_NE(wb, nullptr);
-  EXPECT_TRUE(dvrWriteBufferIsValid(wb));
+  EXPECT_TRUE(api_.WriteBufferIsValid(wb));
 }
 
 TEST_F(DvrBufferQueueTest, AcquirePostGainRelease) {
-  int ret = dvrWriteBufferQueueCreate(
+  int ret = api_.WriteBufferQueueCreate(
       kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
       kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_);
   ASSERT_EQ(ret, 0);
@@ -154,40 +158,40 @@
   DvrNativeBufferMetadata meta2;
   int fence_fd = -1;
 
-  ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
+  ret = api_.WriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
 
   ASSERT_EQ(ret, 0);
   ASSERT_NE(read_queue, nullptr);
 
-  dvrReadBufferQueueSetBufferAvailableCallback(read_queue,
-                                               &BufferAvailableCallback, this);
+  api_.ReadBufferQueueSetBufferAvailableCallback(
+      read_queue, &BufferAvailableCallback, this);
 
   // Gain buffer for writing.
-  ret = dvrWriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb, &meta1,
-                                      &fence_fd);
+  ret = api_.WriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb,
+                                        &meta1, &fence_fd);
   ASSERT_EQ(ret, 0);
   ASSERT_NE(wb, nullptr);
-  ASSERT_TRUE(dvrWriteBufferIsValid(wb));
+  ASSERT_TRUE(api_.WriteBufferIsValid(wb));
   ALOGD_IF(TRACE, "TestDequeuePostDequeueRelease, gain buffer %p, fence_fd=%d",
            wb, fence_fd);
-  android::base::unique_fd release_fence(fence_fd);
+  close(fence_fd);
 
   // Post buffer to the read_queue.
   meta1.timestamp = 42;
-  ret = dvrWriteBufferQueuePostBuffer(write_queue_, wb, &meta1, /*fence=*/-1);
+  ret = api_.WriteBufferQueuePostBuffer(write_queue_, wb, &meta1, /*fence=*/-1);
   ASSERT_EQ(ret, 0);
-  ASSERT_FALSE(dvrWriteBufferIsValid(wb));
+  ASSERT_FALSE(api_.WriteBufferIsValid(wb));
   wb = nullptr;
 
   // Acquire buffer for reading.
-  ret = dvrReadBufferQueueAcquireBuffer(read_queue, /*timeout=*/10, &rb, &meta2,
-                                        &fence_fd);
+  ret = api_.ReadBufferQueueAcquireBuffer(read_queue, /*timeout=*/10, &rb,
+                                          &meta2, &fence_fd);
   ASSERT_EQ(ret, 0);
   ASSERT_NE(rb, nullptr);
 
   // Dequeue is successfully, BufferAvailableCallback should be fired once.
   ASSERT_EQ(buffer_available_count_, 1);
-  ASSERT_TRUE(dvrReadBufferIsValid(rb));
+  ASSERT_TRUE(api_.ReadBufferIsValid(rb));
 
   // Metadata should be passed along from producer to consumer properly.
   ASSERT_EQ(meta1.timestamp, meta2.timestamp);
@@ -195,34 +199,34 @@
   ALOGD_IF(TRACE,
            "TestDequeuePostDequeueRelease, acquire buffer %p, fence_fd=%d", rb,
            fence_fd);
-  android::base::unique_fd acquire_fence(fence_fd);
+  close(fence_fd);
 
   // Release buffer to the write_queue.
-  ret = dvrReadBufferQueueReleaseBuffer(read_queue, rb, &meta2,
-                                        /*release_fence_fd=*/-1);
+  ret = api_.ReadBufferQueueReleaseBuffer(read_queue, rb, &meta2,
+                                          /*release_fence_fd=*/-1);
   ASSERT_EQ(ret, 0);
-  ASSERT_FALSE(dvrReadBufferIsValid(rb));
+  ASSERT_FALSE(api_.ReadBufferIsValid(rb));
   rb = nullptr;
 
   // TODO(b/34387835) Currently buffer allocation has to happen after all queues
   // are initialized.
-  size_t capacity = dvrReadBufferQueueGetCapacity(read_queue);
+  size_t capacity = api_.ReadBufferQueueGetCapacity(read_queue);
 
   ALOGD_IF(TRACE, "TestDequeuePostDequeueRelease, capacity=%zu", capacity);
   ASSERT_EQ(kQueueCapacity, capacity);
 
-  dvrReadBufferQueueDestroy(read_queue);
+  api_.ReadBufferQueueDestroy(read_queue);
 }
 
 TEST_F(DvrBufferQueueTest, GetANativeWindow) {
-  int ret = dvrWriteBufferQueueCreate(
+  int ret = api_.WriteBufferQueueCreate(
       kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
-      /*capacity=*/0, sizeof(DvrNativeBufferMetadata), &write_queue_);
+      /*capacity=*/0, /*user_metadata_size=*/0, &write_queue_);
   ASSERT_EQ(0, ret);
   ASSERT_NE(nullptr, write_queue_);
 
   ANativeWindow* window = nullptr;
-  ret = dvrWriteBufferQueueGetANativeWindow(write_queue_, &window);
+  ret = api_.WriteBufferQueueGetANativeWindow(write_queue_, &window);
   ASSERT_EQ(0, ret);
   ASSERT_NE(nullptr, window);
 
@@ -238,7 +242,7 @@
 // Before each dequeue operation, we resize the buffer queue and expect the
 // queue always return buffer with desired dimension.
 TEST_F(DvrBufferQueueTest, ResizeBuffer) {
-  int ret = dvrWriteBufferQueueCreate(
+  int ret = api_.WriteBufferQueueCreate(
       kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
       kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_);
   ASSERT_EQ(0, ret);
@@ -255,37 +259,37 @@
   AHardwareBuffer* ahb3 = nullptr;
   AHardwareBuffer_Desc buffer_desc;
 
-  ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
+  ret = api_.WriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
 
   ASSERT_EQ(0, ret);
   ASSERT_NE(nullptr, read_queue);
 
-  dvrReadBufferQueueSetBufferRemovedCallback(read_queue, &BufferRemovedCallback,
-                                             this);
+  api_.ReadBufferQueueSetBufferRemovedCallback(read_queue,
+                                               &BufferRemovedCallback, this);
 
   // Handle all pending events on the read queue.
-  ret = dvrReadBufferQueueHandleEvents(read_queue);
+  ret = api_.ReadBufferQueueHandleEvents(read_queue);
   ASSERT_EQ(0, ret);
 
-  size_t capacity = dvrReadBufferQueueGetCapacity(read_queue);
+  size_t capacity = api_.ReadBufferQueueGetCapacity(read_queue);
   ALOGD_IF(TRACE, "TestResizeBuffer, capacity=%zu", capacity);
   ASSERT_EQ(kQueueCapacity, capacity);
 
   // Resize before dequeuing.
   constexpr uint32_t w1 = 10;
-  ret = dvrWriteBufferQueueResizeBuffer(write_queue_, w1, kBufferHeight);
+  ret = api_.WriteBufferQueueResizeBuffer(write_queue_, w1, kBufferHeight);
   ASSERT_EQ(0, ret);
 
   // Gain first buffer for writing. All buffers will be resized.
-  ret = dvrWriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb1, &meta,
-                                      &fence_fd);
+  ret = api_.WriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb1,
+                                        &meta, &fence_fd);
   ASSERT_EQ(0, ret);
-  ASSERT_TRUE(dvrWriteBufferIsValid(wb1));
+  ASSERT_TRUE(api_.WriteBufferIsValid(wb1));
   ALOGD_IF(TRACE, "TestResizeBuffer, gain buffer %p", wb1);
-  android::base::unique_fd release_fence1(fence_fd);
+  close(fence_fd);
 
   // Check the buffer dimension.
-  ret = dvrWriteBufferGetAHardwareBuffer(wb1, &ahb1);
+  ret = api_.WriteBufferGetAHardwareBuffer(wb1, &ahb1);
   ASSERT_EQ(0, ret);
   AHardwareBuffer_describe(ahb1, &buffer_desc);
   ASSERT_EQ(w1, buffer_desc.width);
@@ -294,26 +298,26 @@
 
   // For the first resize, all buffers are reallocated.
   int expected_buffer_removed_count = kQueueCapacity;
-  ret = dvrReadBufferQueueHandleEvents(read_queue);
+  ret = api_.ReadBufferQueueHandleEvents(read_queue);
   ASSERT_EQ(0, ret);
   ASSERT_EQ(expected_buffer_removed_count, buffer_removed_count_);
 
   // Resize the queue. We are testing with blob format, keep height to be 1.
   constexpr uint32_t w2 = 20;
-  ret = dvrWriteBufferQueueResizeBuffer(write_queue_, w2, kBufferHeight);
+  ret = api_.WriteBufferQueueResizeBuffer(write_queue_, w2, kBufferHeight);
   ASSERT_EQ(0, ret);
 
   // The next buffer we dequeued should have new width.
-  ret = dvrWriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb2, &meta,
-                                      &fence_fd);
+  ret = api_.WriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb2,
+                                        &meta, &fence_fd);
   ASSERT_EQ(0, ret);
-  ASSERT_TRUE(dvrWriteBufferIsValid(wb2));
+  ASSERT_TRUE(api_.WriteBufferIsValid(wb2));
   ALOGD_IF(TRACE, "TestResizeBuffer, gain buffer %p, fence_fd=%d", wb2,
            fence_fd);
-  android::base::unique_fd release_fence2(fence_fd);
+  close(fence_fd);
 
   // Check the buffer dimension, should be new width
-  ret = dvrWriteBufferGetAHardwareBuffer(wb2, &ahb2);
+  ret = api_.WriteBufferGetAHardwareBuffer(wb2, &ahb2);
   ASSERT_EQ(0, ret);
   AHardwareBuffer_describe(ahb2, &buffer_desc);
   ASSERT_EQ(w2, buffer_desc.width);
@@ -321,26 +325,26 @@
 
   // For the second resize, all but one buffers are reallocated.
   expected_buffer_removed_count += (kQueueCapacity - 1);
-  ret = dvrReadBufferQueueHandleEvents(read_queue);
+  ret = api_.ReadBufferQueueHandleEvents(read_queue);
   ASSERT_EQ(0, ret);
   ASSERT_EQ(expected_buffer_removed_count, buffer_removed_count_);
 
   // Resize the queue for the third time.
   constexpr uint32_t w3 = 30;
-  ret = dvrWriteBufferQueueResizeBuffer(write_queue_, w3, kBufferHeight);
+  ret = api_.WriteBufferQueueResizeBuffer(write_queue_, w3, kBufferHeight);
   ASSERT_EQ(0, ret);
 
   // The next buffer we dequeued should have new width.
-  ret = dvrWriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb3, &meta,
-                                      &fence_fd);
+  ret = api_.WriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb3,
+                                        &meta, &fence_fd);
   ASSERT_EQ(0, ret);
-  ASSERT_TRUE(dvrWriteBufferIsValid(wb3));
+  ASSERT_TRUE(api_.WriteBufferIsValid(wb3));
   ALOGD_IF(TRACE, "TestResizeBuffer, gain buffer %p, fence_fd=%d", wb3,
            fence_fd);
-  android::base::unique_fd release_fence3(fence_fd);
+  close(fence_fd);
 
   // Check the buffer dimension, should be new width
-  ret = dvrWriteBufferGetAHardwareBuffer(wb3, &ahb3);
+  ret = api_.WriteBufferGetAHardwareBuffer(wb3, &ahb3);
   ASSERT_EQ(0, ret);
   AHardwareBuffer_describe(ahb3, &buffer_desc);
   ASSERT_EQ(w3, buffer_desc.width);
@@ -348,26 +352,26 @@
 
   // For the third resize, all but two buffers are reallocated.
   expected_buffer_removed_count += (kQueueCapacity - 2);
-  ret = dvrReadBufferQueueHandleEvents(read_queue);
+  ret = api_.ReadBufferQueueHandleEvents(read_queue);
   ASSERT_EQ(0, ret);
   ASSERT_EQ(expected_buffer_removed_count, buffer_removed_count_);
 
-  dvrReadBufferQueueDestroy(read_queue);
+  api_.ReadBufferQueueDestroy(read_queue);
 }
 
 TEST_F(DvrBufferQueueTest, ReadQueueEventFd) {
-  int ret = dvrWriteBufferQueueCreate(
+  int ret = api_.WriteBufferQueueCreate(
       kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
       kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_);
   ASSERT_EQ(0, ret);
 
   DvrReadBufferQueue* read_queue = nullptr;
-  ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
+  ret = api_.WriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
 
   ASSERT_EQ(0, ret);
   ASSERT_NE(nullptr, read_queue);
 
-  int event_fd = dvrReadBufferQueueGetEventFd(read_queue);
+  int event_fd = api_.ReadBufferQueueGetEventFd(read_queue);
   ASSERT_GT(event_fd, 0);
 }
 
@@ -375,14 +379,14 @@
 // Dvr{Read,Write}Buffer(s) during their lifecycles. And for the same buffer_id,
 // the corresponding AHardwareBuffer handle stays the same.
 TEST_F(DvrBufferQueueTest, StableBufferIdAndHardwareBuffer) {
-  int ret = dvrWriteBufferQueueCreate(
+  int ret = api_.WriteBufferQueueCreate(
       kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
       kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_);
   ASSERT_EQ(0, ret);
 
   int fence_fd = -1;
   DvrReadBufferQueue* read_queue = nullptr;
-  EXPECT_EQ(0, dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue));
+  EXPECT_EQ(0, api_.WriteBufferQueueCreateReadQueue(write_queue_, &read_queue));
 
   // Read buffers.
   std::array<DvrReadBuffer*, kQueueCapacity> rbs;
@@ -400,16 +404,16 @@
   // This test runs the following operations many many times. Thus we prefer to
   // use ASSERT_XXX rather than EXPECT_XXX to avoid spamming the output.
   std::function<void(size_t i)> Gain = [&](size_t i) {
-    int ret = dvrWriteBufferQueueGainBuffer(write_queue_, /*timeout=*/10,
-                                            &wbs[i], &metas[i], &fence_fd);
+    int ret = api_.WriteBufferQueueGainBuffer(write_queue_, /*timeout=*/10,
+                                              &wbs[i], &metas[i], &fence_fd);
     ASSERT_EQ(ret, 0);
     ASSERT_LT(fence_fd, 0);  // expect invalid fence.
-    ASSERT_TRUE(dvrWriteBufferIsValid(wbs[i]));
-    int buffer_id = dvrWriteBufferGetId(wbs[i]);
+    ASSERT_TRUE(api_.WriteBufferIsValid(wbs[i]));
+    int buffer_id = api_.WriteBufferGetId(wbs[i]);
     ASSERT_GT(buffer_id, 0);
 
     AHardwareBuffer* hb = nullptr;
-    ASSERT_EQ(0, dvrWriteBufferGetAHardwareBuffer(wbs[i], &hb));
+    ASSERT_EQ(0, api_.WriteBufferGetAHardwareBuffer(wbs[i], &hb));
 
     auto whb_it = whbs.find(buffer_id);
     if (whb_it == whbs.end()) {
@@ -425,26 +429,26 @@
   };
 
   std::function<void(size_t i)> Post = [&](size_t i) {
-    ASSERT_TRUE(dvrWriteBufferIsValid(wbs[i]));
+    ASSERT_TRUE(api_.WriteBufferIsValid(wbs[i]));
 
     metas[i].timestamp++;
-    int ret = dvrWriteBufferQueuePostBuffer(write_queue_, wbs[i], &metas[i],
-                                            /*fence=*/-1);
+    int ret = api_.WriteBufferQueuePostBuffer(write_queue_, wbs[i], &metas[i],
+                                              /*fence=*/-1);
     ASSERT_EQ(ret, 0);
   };
 
   std::function<void(size_t i)> Acquire = [&](size_t i) {
-    int ret = dvrReadBufferQueueAcquireBuffer(read_queue, /*timeout=*/10,
-                                              &rbs[i], &metas[i], &fence_fd);
+    int ret = api_.ReadBufferQueueAcquireBuffer(read_queue, /*timeout=*/10,
+                                                &rbs[i], &metas[i], &fence_fd);
     ASSERT_EQ(ret, 0);
     ASSERT_LT(fence_fd, 0);  // expect invalid fence.
-    ASSERT_TRUE(dvrReadBufferIsValid(rbs[i]));
+    ASSERT_TRUE(api_.ReadBufferIsValid(rbs[i]));
 
-    int buffer_id = dvrReadBufferGetId(rbs[i]);
+    int buffer_id = api_.ReadBufferGetId(rbs[i]);
     ASSERT_GT(buffer_id, 0);
 
     AHardwareBuffer* hb = nullptr;
-    ASSERT_EQ(0, dvrReadBufferGetAHardwareBuffer(rbs[i], &hb));
+    ASSERT_EQ(0, api_.ReadBufferGetAHardwareBuffer(rbs[i], &hb));
 
     auto rhb_it = rhbs.find(buffer_id);
     if (rhb_it == rhbs.end()) {
@@ -460,10 +464,10 @@
   };
 
   std::function<void(size_t i)> Release = [&](size_t i) {
-    ASSERT_TRUE(dvrReadBufferIsValid(rbs[i]));
+    ASSERT_TRUE(api_.ReadBufferIsValid(rbs[i]));
 
-    int ret = dvrReadBufferQueueReleaseBuffer(read_queue, rbs[i], &metas[i],
-                                              /*release_fence_fd=*/-1);
+    int ret = api_.ReadBufferQueueReleaseBuffer(read_queue, rbs[i], &metas[i],
+                                                /*release_fence_fd=*/-1);
     ASSERT_EQ(ret, 0);
   };
 
@@ -521,4 +525,55 @@
   }
 }
 
+TEST_F(DvrBufferQueueTest, ConsumerReleaseAfterProducerDestroy) {
+  int ret = api_.WriteBufferQueueCreate(
+      kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
+      kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_);
+  ASSERT_EQ(ret, 0);
+
+  DvrReadBufferQueue* read_queue = nullptr;
+  DvrReadBuffer* rb = nullptr;
+  DvrWriteBuffer* wb = nullptr;
+  DvrNativeBufferMetadata meta1;
+  DvrNativeBufferMetadata meta2;
+  int fence_fd = -1;
+
+  ret = api_.WriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
+  ASSERT_EQ(ret, 0);
+
+  api_.ReadBufferQueueSetBufferAvailableCallback(
+      read_queue, &BufferAvailableCallback, this);
+
+  // Gain buffer for writing.
+  ret = api_.WriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb,
+                                        &meta1, &fence_fd);
+  ASSERT_EQ(ret, 0);
+  close(fence_fd);
+
+  // Post buffer to the read_queue.
+  ret = api_.WriteBufferQueuePostBuffer(write_queue_, wb, &meta1, /*fence=*/-1);
+  ASSERT_EQ(ret, 0);
+  wb = nullptr;
+
+  // Acquire buffer for reading.
+  ret = api_.ReadBufferQueueAcquireBuffer(read_queue, /*timeout=*/10, &rb,
+                                          &meta2, &fence_fd);
+  ASSERT_EQ(ret, 0);
+  close(fence_fd);
+
+  // Destroy the write buffer queue and make sure the reader queue is picking
+  // these events up.
+  api_.WriteBufferQueueDestroy(write_queue_);
+  ret = api_.ReadBufferQueueHandleEvents(read_queue);
+  ASSERT_EQ(0, ret);
+
+  // Release buffer to the write_queue.
+  ret = api_.ReadBufferQueueReleaseBuffer(read_queue, rb, &meta2,
+                                          /*release_fence_fd=*/-1);
+  ASSERT_EQ(ret, 0);
+  rb = nullptr;
+
+  api_.ReadBufferQueueDestroy(read_queue);
+}
+
 }  // namespace
diff --git a/libs/vr/libdvr/tests/dvr_display-test.cpp b/libs/vr/libdvr/tests/dvr_display-test.cpp
new file mode 100644
index 0000000..c72f940
--- /dev/null
+++ b/libs/vr/libdvr/tests/dvr_display-test.cpp
@@ -0,0 +1,351 @@
+#include <android/hardware_buffer.h>
+#include <android/log.h>
+#include <dvr/dvr_api.h>
+#include <dvr/dvr_display_types.h>
+#include <dvr/dvr_surface.h>
+
+#include <gtest/gtest.h>
+
+#include "dvr_api_test.h"
+
+#define LOG_TAG "dvr_display-test"
+
+#ifndef ALOGD
+#define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
+#endif
+
+class DvrDisplayTest : public DvrApiTest {
+ protected:
+  void SetUp() override {
+    DvrApiTest::SetUp();
+    int ret = api_.GetNativeDisplayMetrics(sizeof(display_metrics_),
+                                           &display_metrics_);
+    ASSERT_EQ(ret, 0) << "Failed to get display metrics.";
+    ALOGD(
+        "display_width: %d, display_height: %d, display_x_dpi: %d, "
+        "display_y_dpi: %d, vsync_period_ns: %d.",
+        display_metrics_.display_width, display_metrics_.display_height,
+        display_metrics_.display_x_dpi, display_metrics_.display_y_dpi,
+        display_metrics_.vsync_period_ns);
+  }
+
+  void TearDown() override {
+    if (write_queue_ != nullptr) {
+      api_.WriteBufferQueueDestroy(write_queue_);
+      write_queue_ = nullptr;
+    }
+    if (direct_surface_ != nullptr) {
+      api_.SurfaceDestroy(direct_surface_);
+      direct_surface_ = nullptr;
+    }
+    DvrApiTest::TearDown();
+  }
+
+  /* Convert a write buffer to an android hardware buffer and fill in
+   * color_textures evenly to the buffer.
+   * AssertionError if the width of the buffer is not equal to the input width,
+   * AssertionError if the height of the buffer is not equal to the input
+   * height.
+   */
+  void FillWriteBuffer(DvrWriteBuffer* write_buffer,
+                       const std::vector<uint32_t>& color_textures,
+                       uint32_t width, uint32_t height);
+
+  // Write buffer queue properties.
+  static constexpr uint64_t kUsage = AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE |
+                                     AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT |
+                                     AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN;
+  uint32_t kFormat = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
+  static constexpr size_t kMetadataSize = 0;
+  static constexpr int kTimeoutMs = 1000;  // Time for getting buffer.
+  uint32_t kLayerCount = 1;
+  DvrWriteBufferQueue* write_queue_ = nullptr;
+  DvrSurface* direct_surface_ = nullptr;
+
+  // Device display properties.
+  DvrNativeDisplayMetrics display_metrics_;
+};
+
+TEST_F(DvrDisplayTest, DisplayWithOneBuffer) {
+  // Create a direct surface.
+  std::vector<DvrSurfaceAttribute> direct_surface_attributes = {
+      {.key = DVR_SURFACE_ATTRIBUTE_DIRECT,
+       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
+       .value.bool_value = true},
+      {.key = DVR_SURFACE_ATTRIBUTE_Z_ORDER,
+       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_INT32,
+       .value.int32_value = 10},
+      {.key = DVR_SURFACE_ATTRIBUTE_VISIBLE,
+       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
+       .value.bool_value = true},
+  };
+  int ret =
+      api_.SurfaceCreate(direct_surface_attributes.data(),
+                         direct_surface_attributes.size(), &direct_surface_);
+  ASSERT_EQ(ret, 0) << "Failed to create direct surface.";
+
+  // Create a buffer queue with the direct surface.
+  constexpr size_t kCapacity = 1;
+  uint32_t width = display_metrics_.display_width;
+  uint32_t height = display_metrics_.display_height;
+  ret = api_.SurfaceCreateWriteBufferQueue(
+      direct_surface_, width, height, kFormat, kLayerCount, kUsage, kCapacity,
+      kMetadataSize, &write_queue_);
+  EXPECT_EQ(0, ret) << "Failed to create buffer queue.";
+  ASSERT_NE(nullptr, write_queue_) << "Write buffer queue should not be null.";
+
+  // Get buffer from WriteBufferQueue.
+  DvrWriteBuffer* write_buffer = nullptr;
+  DvrNativeBufferMetadata out_meta;
+  int out_fence_fd = -1;
+  ret = api_.WriteBufferQueueGainBuffer(write_queue_, kTimeoutMs, &write_buffer,
+                                        &out_meta, &out_fence_fd);
+  EXPECT_EQ(0, ret) << "Failed to get the buffer.";
+  ASSERT_NE(nullptr, write_buffer) << "Gained buffer should not be null.";
+
+  // Color the write buffer.
+  FillWriteBuffer(write_buffer,
+                  {0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000},
+                  width, height);
+
+  // Post buffer.
+  int ready_fence_fd = -1;
+  ret = api_.WriteBufferQueuePostBuffer(write_queue_, write_buffer, &out_meta,
+                                        ready_fence_fd);
+  EXPECT_EQ(0, ret) << "Failed to post the buffer.";
+
+  sleep(5);  // For visual check on the device under test.
+  // Should observe three primary colors on the screen center.
+}
+
+TEST_F(DvrDisplayTest, DisplayWithDoubleBuffering) {
+  // Create a direct surface.
+  std::vector<DvrSurfaceAttribute> direct_surface_attributes = {
+      {.key = DVR_SURFACE_ATTRIBUTE_DIRECT,
+       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
+       .value.bool_value = true},
+      {.key = DVR_SURFACE_ATTRIBUTE_Z_ORDER,
+       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_INT32,
+       .value.int32_value = 10},
+      {.key = DVR_SURFACE_ATTRIBUTE_VISIBLE,
+       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
+       .value.bool_value = true},
+  };
+  int ret =
+      api_.SurfaceCreate(direct_surface_attributes.data(),
+                         direct_surface_attributes.size(), &direct_surface_);
+  ASSERT_EQ(ret, 0) << "Failed to create direct surface.";
+
+  // Create a buffer queue with the direct surface.
+  constexpr size_t kCapacity = 2;
+  uint32_t width = display_metrics_.display_width;
+  uint32_t height = display_metrics_.display_height;
+  ret = api_.SurfaceCreateWriteBufferQueue(
+      direct_surface_, width, height, kFormat, kLayerCount, kUsage, kCapacity,
+      kMetadataSize, &write_queue_);
+  EXPECT_EQ(0, ret) << "Failed to create buffer queue.";
+  ASSERT_NE(nullptr, write_queue_) << "Write buffer queue should not be null.";
+
+  int num_display_cycles_in_5s = 5 / (display_metrics_.vsync_period_ns / 1e9);
+  ALOGD("The number of display cycles: %d", num_display_cycles_in_5s);
+  int bufferhub_id_prev_write_buffer = -1;
+  for (int i = 0; i < num_display_cycles_in_5s; ++i) {
+    // Get a buffer from the WriteBufferQueue.
+    DvrWriteBuffer* write_buffer = nullptr;
+    DvrNativeBufferMetadata out_meta;
+    int out_fence_fd = -1;
+    ret = api_.WriteBufferQueueGainBuffer(
+        write_queue_, kTimeoutMs, &write_buffer, &out_meta, &out_fence_fd);
+    EXPECT_EQ(0, ret) << "Failed to get the a write buffer.";
+    ASSERT_NE(nullptr, write_buffer) << "The gained buffer should not be null.";
+
+    int bufferhub_id = api_.WriteBufferGetId(write_buffer);
+    ALOGD("Display cycle: %d, bufferhub id of the write buffer: %d", i,
+          bufferhub_id);
+    EXPECT_NE(bufferhub_id_prev_write_buffer, bufferhub_id)
+        << "Double buffering should be using the two buffers in turns, not "
+           "reusing the same write buffer.";
+    bufferhub_id_prev_write_buffer = bufferhub_id;
+
+    // Color the write buffer.
+    if (i % 2) {
+      FillWriteBuffer(write_buffer, {0xffff0000, 0xff00ff00, 0xff0000ff}, width,
+                      height);
+    } else {
+      FillWriteBuffer(write_buffer, {0xff00ff00, 0xff0000ff, 0xffff0000}, width,
+                      height);
+    }
+
+    // Post the write buffer.
+    int ready_fence_fd = -1;
+    ret = api_.WriteBufferQueuePostBuffer(write_queue_, write_buffer, &out_meta,
+                                          ready_fence_fd);
+    EXPECT_EQ(0, ret) << "Failed to post the buffer.";
+  }
+  // Should observe blinking screen in secondary colors
+  // although it is actually displaying primary colors.
+}
+
+TEST_F(DvrDisplayTest, DisplayWithTwoHardwareLayers) {
+  // Create the direct_surface_0 of z order 10 and direct_surface_1 of z
+  // order 11.
+  DvrSurface* direct_surface_0 = nullptr;
+  std::vector<DvrSurfaceAttribute> direct_surface_0_attributes = {
+      {.key = DVR_SURFACE_ATTRIBUTE_DIRECT,
+       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
+       .value.bool_value = true},
+      {.key = DVR_SURFACE_ATTRIBUTE_Z_ORDER,
+       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_INT32,
+       .value.int32_value = 10},
+      {.key = DVR_SURFACE_ATTRIBUTE_VISIBLE,
+       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
+       .value.bool_value = true},
+  };
+  int ret =
+      api_.SurfaceCreate(direct_surface_0_attributes.data(),
+                         direct_surface_0_attributes.size(), &direct_surface_0);
+  EXPECT_EQ(ret, 0) << "Failed to create direct surface.";
+
+  DvrSurface* direct_surface_1 = nullptr;
+  std::vector<DvrSurfaceAttribute> direct_surface_1_attributes = {
+      {.key = DVR_SURFACE_ATTRIBUTE_DIRECT,
+       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
+       .value.bool_value = true},
+      {.key = DVR_SURFACE_ATTRIBUTE_Z_ORDER,
+       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_INT32,
+       .value.int32_value = 11},
+      {.key = DVR_SURFACE_ATTRIBUTE_VISIBLE,
+       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
+       .value.bool_value = true},
+  };
+  ret =
+      api_.SurfaceCreate(direct_surface_1_attributes.data(),
+                         direct_surface_1_attributes.size(), &direct_surface_1);
+  EXPECT_EQ(ret, 0) << "Failed to create direct surface.";
+
+  // Create a buffer queue for each of the direct surfaces.
+  constexpr size_t kCapacity = 1;
+  uint32_t width = display_metrics_.display_width;
+  uint32_t height = display_metrics_.display_height;
+
+  DvrWriteBufferQueue* write_queue_0 = nullptr;
+  ret = api_.SurfaceCreateWriteBufferQueue(
+      direct_surface_0, width, height, kFormat, kLayerCount, kUsage, kCapacity,
+      kMetadataSize, &write_queue_0);
+  EXPECT_EQ(0, ret) << "Failed to create buffer queue.";
+  EXPECT_NE(nullptr, write_queue_0) << "Write buffer queue should not be null.";
+
+  DvrWriteBufferQueue* write_queue_1 = nullptr;
+  ret = api_.SurfaceCreateWriteBufferQueue(
+      direct_surface_1, width, height, kFormat, kLayerCount, kUsage, kCapacity,
+      kMetadataSize, &write_queue_1);
+  EXPECT_EQ(0, ret) << "Failed to create buffer queue.";
+  EXPECT_NE(nullptr, write_queue_1) << "Write buffer queue should not be null.";
+
+  // Get a buffer from each of the write buffer queues.
+  DvrWriteBuffer* write_buffer_0 = nullptr;
+  DvrNativeBufferMetadata out_meta_0;
+  int out_fence_fd = -1;
+  ret = api_.WriteBufferQueueGainBuffer(
+      write_queue_0, kTimeoutMs, &write_buffer_0, &out_meta_0, &out_fence_fd);
+  EXPECT_EQ(0, ret) << "Failed to get the buffer.";
+  EXPECT_NE(nullptr, write_buffer_0) << "Gained buffer should not be null.";
+
+  DvrWriteBuffer* write_buffer_1 = nullptr;
+  DvrNativeBufferMetadata out_meta_1;
+  out_fence_fd = -1;
+  ret = api_.WriteBufferQueueGainBuffer(
+      write_queue_1, kTimeoutMs, &write_buffer_1, &out_meta_1, &out_fence_fd);
+  EXPECT_EQ(0, ret) << "Failed to get the buffer.";
+  EXPECT_NE(nullptr, write_buffer_1) << "Gained buffer should not be null.";
+
+  // Color the write buffers.
+  FillWriteBuffer(write_buffer_0, {0xffff0000, 0xff00ff00, 0xff0000ff}, width,
+                  height);
+  FillWriteBuffer(write_buffer_1, {0x7f00ff00, 0x7f0000ff, 0x7fff0000}, width,
+                  height);
+
+  // Post buffers.
+  int ready_fence_fd = -1;
+  ret = api_.WriteBufferQueuePostBuffer(write_queue_0, write_buffer_0,
+                                        &out_meta_0, ready_fence_fd);
+  EXPECT_EQ(0, ret) << "Failed to post the buffer.";
+
+  ready_fence_fd = -1;
+  ret = api_.WriteBufferQueuePostBuffer(write_queue_1, write_buffer_1,
+                                        &out_meta_1, ready_fence_fd);
+  EXPECT_EQ(0, ret) << "Failed to post the buffer.";
+
+  sleep(5);  // For visual check on the device under test.
+  // Should observe three secondary colors.
+
+  // Test finished. Clean up buffers and surfaces.
+  if (write_queue_0 != nullptr) {
+    api_.WriteBufferQueueDestroy(write_queue_0);
+    write_queue_0 = nullptr;
+  }
+  if (write_queue_1 != nullptr) {
+    api_.WriteBufferQueueDestroy(write_queue_1);
+    write_queue_1 = nullptr;
+  }
+  if (direct_surface_0 != nullptr) {
+    api_.SurfaceDestroy(direct_surface_0);
+  }
+  if (direct_surface_1 != nullptr) {
+    api_.SurfaceDestroy(direct_surface_1);
+  }
+}
+
+void DvrDisplayTest::FillWriteBuffer(
+    DvrWriteBuffer* write_buffer, const std::vector<uint32_t>& color_textures,
+    uint32_t width, uint32_t height) {
+  uint32_t num_colors = color_textures.size();
+  // Convert the first write buffer to an android hardware buffer.
+  AHardwareBuffer* ah_buffer = nullptr;
+  int ret = api_.WriteBufferGetAHardwareBuffer(write_buffer, &ah_buffer);
+  ASSERT_EQ(0, ret) << "Failed to get a hardware buffer from the write buffer.";
+  ASSERT_NE(nullptr, ah_buffer) << "AHardware buffer should not be null.";
+  AHardwareBuffer_Desc ah_buffer_describe;
+  AHardwareBuffer_describe(ah_buffer, &ah_buffer_describe);
+  ASSERT_EQ(ah_buffer_describe.format, kFormat)
+      << "The format of the android hardware buffer is wrong.";
+  ASSERT_EQ(ah_buffer_describe.layers, kLayerCount)
+      << "The obtained android hardware buffer should have 2 layers.";
+  ASSERT_EQ(ah_buffer_describe.width, width)
+      << "The obtained android hardware buffer width is wrong.";
+  ASSERT_EQ(ah_buffer_describe.height, height)
+      << "The obtained android hardware buffer height is wrong.";
+  // Change the content of the android hardware buffer.
+  void* buffer_data = nullptr;
+  int32_t fence = -1;
+  ret = AHardwareBuffer_lock(ah_buffer, AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN,
+                             fence, nullptr, &buffer_data);
+  ASSERT_EQ(0, ret) << "Failed to lock the hardware buffer.";
+  ASSERT_NE(nullptr, buffer_data) << "Buffer data should not be null.";
+
+  uint32_t num_pixels = width * height / num_colors;
+  for (uint32_t color_index = 0; color_index < num_colors - 1; ++color_index) {
+    uint32_t color_texture = color_textures[color_index];
+    for (uint32_t i = 0; i < num_pixels; ++i) {
+      memcpy(reinterpret_cast<void*>(reinterpret_cast<int64_t>(buffer_data) +
+                                     (i + num_pixels * color_index) *
+                                         sizeof(color_texture)),
+             &color_texture, sizeof(color_texture));
+    }
+  }
+  uint32_t color_texture = color_textures[num_colors - 1];
+  uint32_t num_colored_pixels = num_pixels * (num_colors - 1);
+  num_pixels = width * height - num_colored_pixels;
+  for (uint32_t i = 0; i < num_pixels; ++i) {
+    memcpy(reinterpret_cast<void*>(reinterpret_cast<int64_t>(buffer_data) +
+                                   (i + num_colored_pixels) *
+                                       sizeof(color_texture)),
+           &color_texture, sizeof(color_texture));
+  }
+  fence = -1;
+  ret = AHardwareBuffer_unlock(ah_buffer, &fence);
+  EXPECT_EQ(0, ret) << "Failed to unlock the hardware buffer.";
+
+  // Release the android hardware buffer.
+  AHardwareBuffer_release(ah_buffer);
+}
diff --git a/libs/vr/libdvr/tests/dvr_display_manager-test.cpp b/libs/vr/libdvr/tests/dvr_display_manager-test.cpp
index f83b26e..c9a5c09 100644
--- a/libs/vr/libdvr/tests/dvr_display_manager-test.cpp
+++ b/libs/vr/libdvr/tests/dvr_display_manager-test.cpp
@@ -845,10 +845,10 @@
   ASSERT_NE(nullptr, write_queue.get());
 
   DvrWriteBuffer* buffer = nullptr;
-  dvrWriteBufferCreateEmpty(&buffer);
+  DvrNativeBufferMetadata metadata;
   int fence_fd = -1;
-  int error =
-      dvrWriteBufferQueueDequeue(write_queue.get(), 1000, buffer, &fence_fd);
+  int error = dvrWriteBufferQueueGainBuffer(write_queue.get(), /*timeout=*/1000,
+                                            &buffer, &metadata, &fence_fd);
   ASSERT_EQ(0, error);
 
   AHardwareBuffer* hardware_buffer = nullptr;
diff --git a/libs/vr/libdvrcommon/Android.bp b/libs/vr/libdvrcommon/Android.bp
index 8e63d24..e751768 100644
--- a/libs/vr/libdvrcommon/Android.bp
+++ b/libs/vr/libdvrcommon/Android.bp
@@ -26,9 +26,10 @@
     "libui",
     "libgui",
     "libhardware",
+    "libpdx_default_transport",
 ]
 
-staticLibraries = ["libpdx_default_transport", "libbroadcastring"]
+staticLibraries = ["libbroadcastring"]
 
 headerLibraries = [
     "libeigen",
diff --git a/libs/vr/libpdx/Android.bp b/libs/vr/libpdx/Android.bp
index 113074b..1a9d727 100644
--- a/libs/vr/libpdx/Android.bp
+++ b/libs/vr/libpdx/Android.bp
@@ -22,6 +22,12 @@
         "service_dispatcher.cpp",
         "status.cpp",
     ],
+    shared_libs: [
+        "libbinder",
+        "libcutils",
+        "libutils",
+        "liblog",
+    ],
 }
 
 cc_test {
diff --git a/libs/vr/libpdx/client.cpp b/libs/vr/libpdx/client.cpp
index a01c4d6..3c66a40 100644
--- a/libs/vr/libpdx/client.cpp
+++ b/libs/vr/libpdx/client.cpp
@@ -119,6 +119,10 @@
   return channel_->GetChannelHandle();
 }
 
+const LocalChannelHandle& Client::GetChannelHandle() const {
+  return channel_->GetChannelHandle();
+}
+
 ///////////////////////////// Transaction implementation //////////////////////
 
 Transaction::Transaction(Client& client) : client_{client} {}
diff --git a/libs/vr/libpdx/private/pdx/channel_parcelable.h b/libs/vr/libpdx/private/pdx/channel_parcelable.h
new file mode 100644
index 0000000..59ef9d3
--- /dev/null
+++ b/libs/vr/libpdx/private/pdx/channel_parcelable.h
@@ -0,0 +1,31 @@
+#ifndef ANDROID_PDX_CHANNEL_PARCELABLE_H_
+#define ANDROID_PDX_CHANNEL_PARCELABLE_H_
+
+#include <binder/Parcelable.h>
+#include <pdx/channel_handle.h>
+
+namespace android {
+namespace pdx {
+
+/**
+ * A parcelable object holds all necessary objects to recreate a ClientChannel.
+ * In addition to the android::Parcelable interface, this interface exposees
+ * more PDX-related interface.
+ */
+class ChannelParcelable : public Parcelable {
+ public:
+  virtual ~ChannelParcelable() = default;
+
+  // Returns whether the parcelable object holds a valid client channel.
+  virtual bool IsValid() const = 0;
+
+  // Returns a channel handle constructed from this parcelable object and takes
+  // the ownership of all resources from the parcelable object. In another word,
+  // the parcelable object will become invalid after TakeChannelHandle returns.
+  virtual LocalChannelHandle TakeChannelHandle() = 0;
+};
+
+}  // namespace pdx
+}  // namespace android
+
+#endif  // ANDROID_PDX_CHANNEL_PARCELABLE_H_
diff --git a/libs/vr/libpdx/private/pdx/client.h b/libs/vr/libpdx/private/pdx/client.h
index 656de7e..c35dabd 100644
--- a/libs/vr/libpdx/private/pdx/client.h
+++ b/libs/vr/libpdx/private/pdx/client.h
@@ -49,6 +49,7 @@
 
   // Returns a reference to IPC channel handle.
   LocalChannelHandle& GetChannelHandle();
+  const LocalChannelHandle& GetChannelHandle() const;
 
  protected:
   friend Transaction;
diff --git a/libs/vr/libpdx/private/pdx/client_channel.h b/libs/vr/libpdx/private/pdx/client_channel.h
index 10a49bb..f33a60e 100644
--- a/libs/vr/libpdx/private/pdx/client_channel.h
+++ b/libs/vr/libpdx/private/pdx/client_channel.h
@@ -4,6 +4,7 @@
 #include <vector>
 
 #include <pdx/channel_handle.h>
+#include <pdx/channel_parcelable.h>
 #include <pdx/file_handle.h>
 #include <pdx/status.h>
 
@@ -32,6 +33,7 @@
   virtual std::vector<EventSource> GetEventSources() const = 0;
 
   virtual LocalChannelHandle& GetChannelHandle() = 0;
+  virtual const LocalChannelHandle& GetChannelHandle() const = 0;
   virtual void* AllocateTransactionState() = 0;
   virtual void FreeTransactionState(void* state) = 0;
 
@@ -61,6 +63,11 @@
                              LocalHandle* handle) const = 0;
   virtual bool GetChannelHandle(void* transaction_state, ChannelReference ref,
                                 LocalChannelHandle* handle) const = 0;
+
+  // Returns the internal state of the channel as a parcelable object. The
+  // ClientChannel is invalidated however, the channel is kept alive by the
+  // parcelable object and may be transferred to another process.
+  virtual std::unique_ptr<ChannelParcelable> TakeChannelParcelable() = 0;
 };
 
 }  // namespace pdx
diff --git a/libs/vr/libpdx/private/pdx/mock_client_channel.h b/libs/vr/libpdx/private/pdx/mock_client_channel.h
index 49e0682..b1a1299 100644
--- a/libs/vr/libpdx/private/pdx/mock_client_channel.h
+++ b/libs/vr/libpdx/private/pdx/mock_client_channel.h
@@ -14,6 +14,7 @@
   MOCK_CONST_METHOD0(GetEventSources, std::vector<EventSource>());
   MOCK_METHOD1(GetEventMask, Status<int>(int));
   MOCK_METHOD0(GetChannelHandle, LocalChannelHandle&());
+  MOCK_CONST_METHOD0(GetChannelHandle, const LocalChannelHandle&());
   MOCK_METHOD0(AllocateTransactionState, void*());
   MOCK_METHOD1(FreeTransactionState, void(void* state));
   MOCK_METHOD3(SendImpulse,
@@ -49,6 +50,7 @@
   MOCK_CONST_METHOD3(GetChannelHandle,
                      bool(void* transaction_state, ChannelReference ref,
                           LocalChannelHandle* handle));
+  MOCK_METHOD0(TakeChannelParcelable, std::unique_ptr<ChannelParcelable>());
 };
 
 }  // namespace pdx
diff --git a/libs/vr/libpdx/private/pdx/service.h b/libs/vr/libpdx/private/pdx/service.h
index 0d30614..13aa3e9 100644
--- a/libs/vr/libpdx/private/pdx/service.h
+++ b/libs/vr/libpdx/private/pdx/service.h
@@ -589,6 +589,14 @@
   }
 
   /*
+   * Return true if a channel with the given ID exists in the Channel map.
+   */
+  bool HasChannelId(int channel_id) const {
+    std::lock_guard<std::mutex> autolock(channels_mutex_);
+    return channels_.find(channel_id) != channels_.end();
+  }
+
+  /*
    * Subclasses of Service may override this method to provide a text string
    * describing the state of the service. This method is called by
    * HandleSystemMessage in response to the standard
diff --git a/libs/vr/libpdx_default_transport/Android.bp b/libs/vr/libpdx_default_transport/Android.bp
index f891c59..74b8c8b 100644
--- a/libs/vr/libpdx_default_transport/Android.bp
+++ b/libs/vr/libpdx_default_transport/Android.bp
@@ -26,13 +26,21 @@
     whole_static_libs: ["libpdx_uds"],
 }
 
-cc_library_static {
+cc_library_shared {
     name: "libpdx_default_transport",
     defaults: [
         "pdx_default_transport_compiler_defaults",
         "pdx_default_transport_lib_defaults",
         "pdx_use_transport_uds",
     ],
+    shared_libs: [
+        "libbase",
+        "libbinder",
+        "libcutils",
+        "liblog",
+        "libutils",
+        "libcrypto",
+    ],
 }
 
 cc_binary {
@@ -42,10 +50,9 @@
         "pdx_tool.cpp",
     ],
     shared_libs: [
+        "libbinder",
         "libcutils",
         "liblog",
-    ],
-    static_libs: [
         "libpdx_default_transport",
     ],
 }
@@ -59,12 +66,11 @@
     ],
     shared_libs: [
         "libbase",
+        "libbinder",
         "libchrome",
         "libcutils",
         "liblog",
         "libutils",
-    ],
-    static_libs: [
         "libpdx_default_transport",
     ],
 }
diff --git a/libs/vr/libpdx_default_transport/private/servicefs/pdx/default_transport/channel_parcelable.h b/libs/vr/libpdx_default_transport/private/servicefs/pdx/default_transport/channel_parcelable.h
new file mode 100644
index 0000000..a8623b2
--- /dev/null
+++ b/libs/vr/libpdx_default_transport/private/servicefs/pdx/default_transport/channel_parcelable.h
@@ -0,0 +1,17 @@
+#ifndef ANDROID_PDX_DEFAULT_TRANSPORT_SERVICEFS_CHANNEL_PARCELABLE_H_
+#define ANDROID_PDX_DEFAULT_TRANSPORT_SERVICEFS_CHANNEL_PARCELABLE_H_
+
+#include <servicefs/channel_parcelable.h>
+
+namespace android {
+namespace pdx {
+namespace default_transport {
+
+using ChannelParcelable = ::android::pdx::servicefs::ChannelParcelable;
+
+}  // namespace default_transport
+}  // namespace pdx
+}  // namespace android
+
+
+#endif  // ANDROID_PDX_DEFAULT_TRANSPORT_SERVICEFS_CHANNEL_PARCELABLE_H_
diff --git a/libs/vr/libpdx_default_transport/private/uds/pdx/default_transport/channel_parcelable.h b/libs/vr/libpdx_default_transport/private/uds/pdx/default_transport/channel_parcelable.h
new file mode 100644
index 0000000..bcd74e6
--- /dev/null
+++ b/libs/vr/libpdx_default_transport/private/uds/pdx/default_transport/channel_parcelable.h
@@ -0,0 +1,17 @@
+#ifndef ANDROID_PDX_DEFAULT_TRANSPORT_UDS_CHANNEL_PARCELABLE_H_
+#define ANDROID_PDX_DEFAULT_TRANSPORT_UDS_CHANNEL_PARCELABLE_H_
+
+#include <uds/channel_parcelable.h>
+
+namespace android {
+namespace pdx {
+namespace default_transport {
+
+using ChannelParcelable = ::android::pdx::uds::ChannelParcelable;
+
+}  // namespace default_transport
+}  // namespace pdx
+}  // namespace android
+
+
+#endif  // ANDROID_PDX_DEFAULT_TRANSPORT_UDS_CHANNEL_PARCELABLE_H_
diff --git a/libs/vr/libpdx_uds/Android.bp b/libs/vr/libpdx_uds/Android.bp
index d0b7cab..d640950 100644
--- a/libs/vr/libpdx_uds/Android.bp
+++ b/libs/vr/libpdx_uds/Android.bp
@@ -13,6 +13,7 @@
     srcs: [
         "channel_event_set.cpp",
         "channel_manager.cpp",
+        "channel_parcelable.cpp",
         "client_channel_factory.cpp",
         "client_channel.cpp",
         "ipc_helper.cpp",
@@ -23,6 +24,9 @@
         "libbase",
         "libpdx",
     ],
+    shared_libs: [
+        "libbinder",
+    ],
     whole_static_libs: [
         "libselinux",
     ],
@@ -52,5 +56,6 @@
         "libcutils",
         "liblog",
         "libutils",
+        "libbinder",
     ],
 }
diff --git a/libs/vr/libpdx_uds/channel_parcelable.cpp b/libs/vr/libpdx_uds/channel_parcelable.cpp
new file mode 100644
index 0000000..e7bce27
--- /dev/null
+++ b/libs/vr/libpdx_uds/channel_parcelable.cpp
@@ -0,0 +1,125 @@
+#include "uds/channel_parcelable.h"
+
+#include <binder/Parcel.h>
+#include <uds/channel_manager.h>
+
+namespace android {
+namespace pdx {
+namespace uds {
+
+namespace {
+
+static constexpr uint32_t kUdsMagicParcelHeader = 0x7564736d;  // 'udsm'.
+
+}  // namespace
+
+ChannelParcelable::ChannelParcelable(LocalHandle data_fd,
+                                     LocalHandle pollin_event_fd,
+                                     LocalHandle pollhup_event_fd)
+    : data_fd_{std::move(data_fd)},
+      pollin_event_fd_{std::move(pollin_event_fd)},
+      pollhup_event_fd_{std::move(pollhup_event_fd)} {}
+
+bool ChannelParcelable::IsValid() const {
+  return !!data_fd_ && !!pollin_event_fd_ && !!pollhup_event_fd_;
+}
+
+LocalChannelHandle ChannelParcelable::TakeChannelHandle() {
+  if (!IsValid()) {
+    ALOGE("ChannelParcelable::TakeChannelHandle: Invalid channel parcel.");
+    return {};  // Returns an empty channel handle.
+  }
+
+  return ChannelManager::Get().CreateHandle(std::move(data_fd_),
+                                            std::move(pollin_event_fd_),
+                                            std::move(pollhup_event_fd_));
+}
+
+status_t ChannelParcelable::writeToParcel(Parcel* parcel) const {
+  status_t res = NO_ERROR;
+
+  if (!IsValid()) {
+    ALOGE("ChannelParcelable::writeToParcel: Invalid channel parcel.");
+    return BAD_VALUE;
+  }
+
+  res = parcel->writeUint32(kUdsMagicParcelHeader);
+  if (res != NO_ERROR) {
+    ALOGE("ChannelParcelable::writeToParcel: Cannot write magic: res=%d.", res);
+    return res;
+  }
+
+  res = parcel->writeFileDescriptor(data_fd_.Get());
+  if (res != NO_ERROR) {
+    ALOGE("ChannelParcelable::writeToParcel: Cannot write data fd: res=%d.",
+          res);
+    return res;
+  }
+
+  res = parcel->writeFileDescriptor(pollin_event_fd_.Get());
+  if (res != NO_ERROR) {
+    ALOGE(
+        "ChannelParcelable::writeToParcel: Cannot write pollin event fd: "
+        "res=%d.",
+        res);
+    return res;
+  }
+
+  res = parcel->writeFileDescriptor(pollhup_event_fd_.Get());
+  if (res != NO_ERROR) {
+    ALOGE(
+        "ChannelParcelable::writeToParcel: Cannot write pollhup event fd: "
+        "res=%d.",
+        res);
+    return res;
+  }
+
+  return res;
+}
+
+status_t ChannelParcelable::readFromParcel(const Parcel* parcel) {
+  uint32_t magic = 0;
+  status_t res = NO_ERROR;
+
+  if (IsValid()) {
+    ALOGE(
+        "ChannelParcelable::readFromParcel: This channel parcel is already "
+        "initailzied.");
+    return ALREADY_EXISTS;
+  }
+
+  res = parcel->readUint32(&magic);
+  if (res != NO_ERROR) {
+    ALOGE("ChannelParcelable::readFromParcel: Failed to read magic: res=%d.",
+          res);
+    return res;
+  }
+
+  if (magic != kUdsMagicParcelHeader) {
+    ALOGE(
+        "ChannelParcelable::readFromParcel: Unknown magic: 0x%x, epxected: "
+        "0x%x",
+        magic, kUdsMagicParcelHeader);
+    return BAD_VALUE;
+  }
+
+  // TODO(b/69010509): We have to dup() the FD from android::Parcel as it
+  // doesn't support taking out the FD's ownership. We can remove the dup() here
+  // once android::Parcel support such operation.
+  data_fd_.Reset(dup(parcel->readFileDescriptor()));
+  pollin_event_fd_.Reset(dup(parcel->readFileDescriptor()));
+  pollhup_event_fd_.Reset(dup(parcel->readFileDescriptor()));
+  if (!IsValid()) {
+    ALOGE(
+        "ChannelParcelable::readFromParcel: Cannot read fd from parcel: "
+        "data_fd=%d, pollin_event_fd=%d, pollhup_event_fd=%d.",
+        data_fd_.Get(), pollin_event_fd_.Get(), pollhup_event_fd_.Get());
+    return DEAD_OBJECT;
+  }
+
+  return res;
+}
+
+}  // namespace uds
+}  // namespace pdx
+}  // namespace android
diff --git a/libs/vr/libpdx_uds/client_channel.cpp b/libs/vr/libpdx_uds/client_channel.cpp
index 2e9c1de..6073c3c 100644
--- a/libs/vr/libpdx_uds/client_channel.cpp
+++ b/libs/vr/libpdx_uds/client_channel.cpp
@@ -1,3 +1,4 @@
+#include "uds/channel_parcelable.h"
 #include "uds/client_channel.h"
 
 #include <errno.h>
@@ -292,6 +293,29 @@
   return state->GetLocalChannelHandle(ref, handle);
 }
 
+std::unique_ptr<pdx::ChannelParcelable> ClientChannel::TakeChannelParcelable()
+    {
+  if (!channel_handle_)
+    return nullptr;
+
+  if (auto* channel_data =
+          ChannelManager::Get().GetChannelData(channel_handle_.value())) {
+    auto fds = channel_data->TakeFds();
+    auto parcelable = std::make_unique<ChannelParcelable>(
+        std::move(std::get<0>(fds)), std::move(std::get<1>(fds)),
+        std::move(std::get<2>(fds)));
+
+    // Here we need to explicitly close the channel handle so that the channel
+    // won't get shutdown in the destructor, while the FDs in ChannelParcelable
+    // can keep the channel alive so that new client can be created from it
+    // later.
+    channel_handle_.Close();
+    return parcelable;
+  } else {
+    return nullptr;
+  }
+}
+
 }  // namespace uds
 }  // namespace pdx
 }  // namespace android
diff --git a/libs/vr/libpdx_uds/private/uds/channel_event_set.h b/libs/vr/libpdx_uds/private/uds/channel_event_set.h
index 99e7502..e960740 100644
--- a/libs/vr/libpdx_uds/private/uds/channel_event_set.h
+++ b/libs/vr/libpdx_uds/private/uds/channel_event_set.h
@@ -54,6 +54,14 @@
   BorrowedHandle pollhup_event_fd() const { return pollhup_event_fd_.Borrow(); }
   BorrowedHandle data_fd() const { return data_fd_.Borrow(); }
 
+  // Moves file descriptors out of ChannelEventReceiver. Note these operations
+  // immediately invalidates the receiver.
+  std::tuple<LocalHandle, LocalHandle, LocalHandle> TakeFds() {
+    epoll_fd_.Close();
+    return {std::move(data_fd_), std::move(pollin_event_fd_),
+            std::move(pollhup_event_fd_)};
+  }
+
   Status<int> GetPendingEvents() const;
   Status<int> PollPendingEvents(int timeout_ms) const;
 
diff --git a/libs/vr/libpdx_uds/private/uds/channel_parcelable.h b/libs/vr/libpdx_uds/private/uds/channel_parcelable.h
new file mode 100644
index 0000000..1c3fae9
--- /dev/null
+++ b/libs/vr/libpdx_uds/private/uds/channel_parcelable.h
@@ -0,0 +1,35 @@
+#ifndef ANDROID_PDX_UDS_CHANNEL_PARCELABLE_H_
+#define ANDROID_PDX_UDS_CHANNEL_PARCELABLE_H_
+
+#include <pdx/channel_parcelable.h>
+#include <pdx/file_handle.h>
+
+namespace android {
+namespace pdx {
+namespace uds {
+
+class ChannelParcelable : public pdx::ChannelParcelable {
+ public:
+  ChannelParcelable() = default;
+  ChannelParcelable(LocalHandle data_fd, LocalHandle pollin_event_fd,
+                    LocalHandle pollhup_event_fd);
+
+  // Implements pdx::ChannelParcelable interface.
+  bool IsValid() const override;
+  LocalChannelHandle TakeChannelHandle() override;
+
+  // Implements android::Parcelable interface.
+  status_t writeToParcel(Parcel* parcel) const override;
+  status_t readFromParcel(const Parcel* parcel) override;
+
+ private:
+  LocalHandle data_fd_;
+  LocalHandle pollin_event_fd_;
+  LocalHandle pollhup_event_fd_;
+};
+
+}  // namespace uds
+}  // namespace pdx
+}  // namespace android
+
+#endif  // ANDROID_PDX_UDS_CHANNEL_PARCELABLE_H_
diff --git a/libs/vr/libpdx_uds/private/uds/client_channel.h b/libs/vr/libpdx_uds/private/uds/client_channel.h
index 7a5ddf4..3561c6f 100644
--- a/libs/vr/libpdx_uds/private/uds/client_channel.h
+++ b/libs/vr/libpdx_uds/private/uds/client_channel.h
@@ -41,6 +41,9 @@
   }
 
   LocalChannelHandle& GetChannelHandle() override { return channel_handle_; }
+  const LocalChannelHandle& GetChannelHandle() const override {
+    return channel_handle_;
+  }
   void* AllocateTransactionState() override;
   void FreeTransactionState(void* state) override;
 
@@ -74,6 +77,8 @@
   bool GetChannelHandle(void* transaction_state, ChannelReference ref,
                         LocalChannelHandle* handle) const override;
 
+  std::unique_ptr<pdx::ChannelParcelable> TakeChannelParcelable() override;
+
  private:
   explicit ClientChannel(LocalChannelHandle channel_handle);
 
diff --git a/libs/vr/libpdx_uds/service_endpoint.cpp b/libs/vr/libpdx_uds/service_endpoint.cpp
index 0ee77f4..32d40e8 100644
--- a/libs/vr/libpdx_uds/service_endpoint.cpp
+++ b/libs/vr/libpdx_uds/service_endpoint.cpp
@@ -594,9 +594,10 @@
 
   if (socket_fd_ && event.data.fd == socket_fd_.Get()) {
     auto status = AcceptConnection(message);
-    if (!status)
-      return status;
-    return ReenableEpollEvent(socket_fd_.Borrow());
+    auto reenable_status = ReenableEpollEvent(socket_fd_.Borrow());
+    if (!reenable_status)
+      return reenable_status;
+    return status;
   }
 
   BorrowedHandle channel_fd{event.data.fd};
diff --git a/libs/vr/libperformance/Android.bp b/libs/vr/libperformance/Android.bp
index 6a46876..35d3dea 100644
--- a/libs/vr/libperformance/Android.bp
+++ b/libs/vr/libperformance/Android.bp
@@ -19,13 +19,13 @@
 
 includeFiles = [ "include" ]
 
-staticLibraries = ["libpdx_default_transport"]
-
 sharedLibraries = [
     "libbase",
+    "libbinder",
     "libcutils",
     "liblog",
     "libutils",
+    "libpdx_default_transport",
 ]
 
 cc_library {
@@ -37,7 +37,6 @@
         "-Werror",
     ],
     export_include_dirs: includeFiles,
-    static_libs: staticLibraries,
     shared_libs: sharedLibraries,
     name: "libperformance",
 }
diff --git a/libs/vr/libvrflinger/Android.bp b/libs/vr/libvrflinger/Android.bp
index 4d80e91..4dc669b 100644
--- a/libs/vr/libvrflinger/Android.bp
+++ b/libs/vr/libvrflinger/Android.bp
@@ -26,16 +26,11 @@
 includeFiles = [ "include" ]
 
 staticLibraries = [
-    "libsurfaceflingerincludes",
-    "libhwcomposer-command-buffer",
-    "libbufferhub",
-    "libbufferhubqueue",
     "libdisplay",
     "libdvrcommon",
     "libperformance",
     "libvrsensor",
     "libbroadcastring",
-    "libpdx_default_transport",
     "libvr_manager",
     "libbroadcastring",
 ]
@@ -44,8 +39,10 @@
     "android.frameworks.vr.composer@1.0",
     "android.hardware.graphics.allocator@2.0",
     "android.hardware.graphics.composer@2.1",
+    "android.hardware.graphics.composer@2.2",
     "libbinder",
     "libbase",
+    "libbufferhubqueue",
     "libcutils",
     "liblog",
     "libhardware",
@@ -61,16 +58,21 @@
     "libhidlbase",
     "libhidltransport",
     "libfmq",
+    "libpdx_default_transport",
 ]
 
 headerLibraries = [
-    "libdvr_headers"
+    "android.hardware.graphics.composer@2.1-command-buffer",
+    "android.hardware.graphics.composer@2.2-command-buffer",
+    "libdvr_headers",
+    "libsurfaceflinger_headers",
 ]
 
 cc_library_static {
     srcs: sourceFiles,
     export_include_dirs: includeFiles,
 
+    clang: true,
     cflags: [
         "-DLOG_TAG=\"vr_flinger\"",
         "-DTRACE=0",
@@ -82,6 +84,9 @@
         "-Wno-error=sign-compare", // to fix later
         "-Wno-unused-variable",
     ],
+    cppflags: [
+        "-std=c++1z"
+    ],
     shared_libs: sharedLibraries,
     whole_static_libs: staticLibraries,
     header_libs: headerLibraries,
diff --git a/libs/vr/libvrflinger/display_manager_service.cpp b/libs/vr/libvrflinger/display_manager_service.cpp
index ef8cca3..34b3b0a 100644
--- a/libs/vr/libvrflinger/display_manager_service.cpp
+++ b/libs/vr/libvrflinger/display_manager_service.cpp
@@ -45,6 +45,14 @@
   const int user_id = message.GetEffectiveUserId();
   const bool trusted = user_id == AID_ROOT || IsTrustedUid(user_id);
 
+  // Check if the display_manager_ has a defunct channel.
+  if (display_manager_ && !HasChannelId(display_manager_->channel_id())) {
+    ALOGE("DisplayManagerService::OnChannelOpen: Found defunct channel %d with "
+          "no OnChannelClose, clearing prior display manager.",
+          display_manager_->channel_id());
+    display_manager_ = nullptr;
+  }
+
   // Prevent more than one display manager from registering at a time or
   // untrusted UIDs from connecting.
   if (display_manager_ || !trusted) {
diff --git a/libs/vr/libvrflinger/display_service.cpp b/libs/vr/libvrflinger/display_service.cpp
index ac68a5e..87162c0 100644
--- a/libs/vr/libvrflinger/display_service.cpp
+++ b/libs/vr/libvrflinger/display_service.cpp
@@ -38,10 +38,12 @@
 namespace dvr {
 
 DisplayService::DisplayService(Hwc2::Composer* hidl,
+                               hwc2_display_t primary_display_id,
                                RequestDisplayCallback request_display_callback)
     : BASE("DisplayService",
            Endpoint::Create(display::DisplayProtocol::kClientPath)) {
-  hardware_composer_.Initialize(hidl, request_display_callback);
+    hardware_composer_.Initialize(
+        hidl, primary_display_id, request_display_callback);
 }
 
 bool DisplayService::IsInitialized() const {
@@ -175,12 +177,12 @@
 
 Status<display::Metrics> DisplayService::OnGetMetrics(
     pdx::Message& /*message*/) {
-  return {{static_cast<uint32_t>(GetDisplayMetrics().width),
-           static_cast<uint32_t>(GetDisplayMetrics().height),
-           static_cast<uint32_t>(GetDisplayMetrics().dpi.x),
-           static_cast<uint32_t>(GetDisplayMetrics().dpi.y),
-           static_cast<uint32_t>(
-               hardware_composer_.native_display_metrics().vsync_period_ns),
+  const auto& params = hardware_composer_.GetPrimaryDisplayParams();
+  return {{static_cast<uint32_t>(params.width),
+           static_cast<uint32_t>(params.height),
+           static_cast<uint32_t>(params.dpi.x),
+           static_cast<uint32_t>(params.dpi.y),
+           static_cast<uint32_t>(params.vsync_period_ns),
            0,
            0,
            0,
diff --git a/libs/vr/libvrflinger/display_service.h b/libs/vr/libvrflinger/display_service.h
index 55e33ab..3090bd1 100644
--- a/libs/vr/libvrflinger/display_service.h
+++ b/libs/vr/libvrflinger/display_service.h
@@ -65,12 +65,9 @@
     hardware_composer_.SetVSyncCallback(callback);
   }
 
-  HWCDisplayMetrics GetDisplayMetrics() {
-    return hardware_composer_.display_metrics();
-  }
-
   void GrantDisplayOwnership() { hardware_composer_.Enable(); }
   void SeizeDisplayOwnership() { hardware_composer_.Disable(); }
+  void OnBootFinished() { hardware_composer_.OnBootFinished(); }
 
  private:
   friend BASE;
@@ -81,6 +78,7 @@
   using RequestDisplayCallback = std::function<void(bool)>;
 
   DisplayService(android::Hwc2::Composer* hidl,
+                 hwc2_display_t primary_display_id,
                  RequestDisplayCallback request_display_callback);
 
   pdx::Status<BorrowedNativeBufferHandle> OnGetGlobalBuffer(
diff --git a/libs/vr/libvrflinger/hardware_composer.cpp b/libs/vr/libvrflinger/hardware_composer.cpp
index fb69d5c..44ce78c 100644
--- a/libs/vr/libvrflinger/hardware_composer.cpp
+++ b/libs/vr/libvrflinger/hardware_composer.cpp
@@ -45,14 +45,22 @@
 
 namespace {
 
-const char kBacklightBrightnessSysFile[] =
-    "/sys/class/leds/lcd-backlight/brightness";
-
 const char kDvrPerformanceProperty[] = "sys.dvr.performance";
 const char kDvrStandaloneProperty[] = "ro.boot.vr";
 
 const char kRightEyeOffsetProperty[] = "dvr.right_eye_offset_ns";
 
+const char kUseExternalDisplayProperty[] = "persist.vr.use_external_display";
+
+// How long to wait after boot finishes before we turn the display off.
+constexpr int kBootFinishedDisplayOffTimeoutSec = 10;
+
+constexpr int kDefaultDisplayWidth = 1920;
+constexpr int kDefaultDisplayHeight = 1080;
+constexpr int64_t kDefaultVsyncPeriodNs = 16666667;
+// Hardware composer reports dpi as dots per thousand inches (dpi * 1000).
+constexpr int kDefaultDpi = 400000;
+
 // Get time offset from a vsync to when the pose for that vsync should be
 // predicted out to. For example, if scanout gets halfway through the frame
 // at the halfway point between vsyncs, then this could be half the period.
@@ -109,6 +117,11 @@
 #define TRACE_FORMAT(format, ...) \
   TraceArgs PASTE(__tracer, __LINE__) { format, ##__VA_ARGS__ }
 
+// Returns "primary" or "external". Useful for writing more readable logs.
+const char* GetDisplayName(bool is_primary) {
+  return is_primary ? "primary" : "external";
+}
+
 }  // anonymous namespace
 
 HardwareComposer::HardwareComposer()
@@ -121,7 +134,8 @@
 }
 
 bool HardwareComposer::Initialize(
-    Hwc2::Composer* composer, RequestDisplayCallback request_display_callback) {
+    Hwc2::Composer* composer, hwc2_display_t primary_display_id,
+    RequestDisplayCallback request_display_callback) {
   if (initialized_) {
     ALOGE("HardwareComposer::Initialize: already initialized.");
     return false;
@@ -131,42 +145,7 @@
 
   request_display_callback_ = request_display_callback;
 
-  HWC::Error error = HWC::Error::None;
-
-  Hwc2::Config config;
-  error = composer->getActiveConfig(HWC_DISPLAY_PRIMARY, &config);
-
-  if (error != HWC::Error::None) {
-    ALOGE("HardwareComposer: Failed to get current display config : %d",
-          config);
-    return false;
-  }
-
-  error = GetDisplayMetrics(composer, HWC_DISPLAY_PRIMARY, config,
-                            &native_display_metrics_);
-
-  if (error != HWC::Error::None) {
-    ALOGE(
-        "HardwareComposer: Failed to get display attributes for current "
-        "configuration : %d",
-        error.value);
-    return false;
-  }
-
-  ALOGI(
-      "HardwareComposer: primary display attributes: width=%d height=%d "
-      "vsync_period_ns=%d DPI=%dx%d",
-      native_display_metrics_.width, native_display_metrics_.height,
-      native_display_metrics_.vsync_period_ns, native_display_metrics_.dpi.x,
-      native_display_metrics_.dpi.y);
-
-  // Set the display metrics but never use rotation to avoid the long latency of
-  // rotation processing in hwc.
-  display_transform_ = HWC_TRANSFORM_NONE;
-  display_metrics_ = native_display_metrics_;
-
-  // Setup the display metrics used by all Layer instances.
-  Layer::SetDisplayMetrics(native_display_metrics_);
+  primary_display_ = GetDisplayParams(composer, primary_display_id, true);
 
   post_thread_event_fd_.Reset(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
   LOG_ALWAYS_FATAL_IF(
@@ -187,6 +166,21 @@
 
 void HardwareComposer::Disable() {
   UpdatePostThreadState(PostThreadState::Suspended, true);
+
+  std::unique_lock<std::mutex> lock(post_thread_mutex_);
+  post_thread_ready_.wait(lock, [this] {
+    return !post_thread_resumed_;
+  });
+}
+
+void HardwareComposer::OnBootFinished() {
+  std::lock_guard<std::mutex> lock(post_thread_mutex_);
+  if (boot_finished_)
+    return;
+  boot_finished_ = true;
+  post_thread_wait_.notify_one();
+  if (is_standalone_device_)
+    request_display_callback_(true);
 }
 
 // Update the post thread quiescent state based on idle and suspended inputs.
@@ -218,59 +212,65 @@
     eventfd_read(post_thread_event_fd_.Get(), &value);
     post_thread_wait_.notify_one();
   }
+}
 
-  // Wait until the post thread is in the requested state.
-  post_thread_ready_.wait(lock, [this, effective_suspend] {
-    return effective_suspend != post_thread_resumed_;
-  });
+void HardwareComposer::CreateComposer() {
+  if (composer_)
+    return;
+  composer_.reset(new Hwc2::impl::Composer("default"));
+  composer_callback_ = new ComposerCallback;
+  composer_->registerCallback(composer_callback_);
+  LOG_ALWAYS_FATAL_IF(!composer_callback_->GotFirstHotplug(),
+      "Registered composer callback but didn't get hotplug for primary"
+      " display");
 }
 
 void HardwareComposer::OnPostThreadResumed() {
-  // Phones create a new composer client on resume and destroy it on pause.
-  // Standalones only create the composer client once and then use SetPowerMode
-  // to control the screen on pause/resume.
-  if (!is_standalone_device_ || !composer_) {
-    composer_.reset(new Hwc2::Composer("default"));
-    composer_callback_ = new ComposerCallback;
-    composer_->registerCallback(composer_callback_);
-    Layer::SetComposer(composer_.get());
-  } else {
-    SetPowerMode(true);
-  }
-
-  EnableVsync(true);
-
-  // TODO(skiazyk): We need to do something about accessing this directly,
-  // supposedly there is a backlight service on the way.
-  // TODO(steventhomas): When we change the backlight setting, will surface
-  // flinger (or something else) set it back to its original value once we give
-  // control of the display back to surface flinger?
-  SetBacklightBrightness(255);
+  ALOGI("OnPostThreadResumed");
+  EnableDisplay(*target_display_, true);
 
   // Trigger target-specific performance mode change.
   property_set(kDvrPerformanceProperty, "performance");
 }
 
 void HardwareComposer::OnPostThreadPaused() {
+  ALOGI("OnPostThreadPaused");
   retire_fence_fds_.clear();
   layers_.clear();
 
-  if (composer_) {
-    EnableVsync(false);
-  }
-
+  // Phones create a new composer client on resume and destroy it on pause.
+  // Standalones only create the composer client once and then use SetPowerMode
+  // to control the screen on pause/resume.
   if (!is_standalone_device_) {
     composer_callback_ = nullptr;
     composer_.reset(nullptr);
-    Layer::SetComposer(nullptr);
   } else {
-    SetPowerMode(false);
+    EnableDisplay(*target_display_, false);
   }
 
   // Trigger target-specific performance mode change.
   property_set(kDvrPerformanceProperty, "idle");
 }
 
+bool HardwareComposer::PostThreadCondWait(std::unique_lock<std::mutex>& lock,
+                                          int timeout_sec,
+                                          const std::function<bool()>& pred) {
+  auto pred_with_quit = [&] {
+    return pred() || (post_thread_state_ & PostThreadState::Quit);
+  };
+  if (timeout_sec >= 0) {
+    post_thread_wait_.wait_for(lock, std::chrono::seconds(timeout_sec),
+                               pred_with_quit);
+  } else {
+    post_thread_wait_.wait(lock, pred_with_quit);
+  }
+  if (post_thread_state_ & PostThreadState::Quit) {
+    ALOGI("HardwareComposer::PostThread: Quitting.");
+    return true;
+  }
+  return false;
+}
+
 HWC::Error HardwareComposer::Validate(hwc2_display_t display) {
   uint32_t num_types;
   uint32_t num_requests;
@@ -278,27 +278,55 @@
       composer_->validateDisplay(display, &num_types, &num_requests);
 
   if (error == HWC2_ERROR_HAS_CHANGES) {
-    // TODO(skiazyk): We might need to inspect the requested changes first, but
-    // so far it seems like we shouldn't ever hit a bad state.
-    // error = hwc2_funcs_.accept_display_changes_fn_(hardware_composer_device_,
-    //                                               display);
+    ALOGE("Hardware composer has requested composition changes, "
+          "which we don't support.");
+    // Accept the changes anyway and see if we can get something on the screen.
     error = composer_->acceptDisplayChanges(display);
   }
 
   return error;
 }
 
-HWC::Error HardwareComposer::EnableVsync(bool enabled) {
-  return composer_->setVsyncEnabled(
-      HWC_DISPLAY_PRIMARY,
+bool HardwareComposer::EnableVsync(const DisplayParams& display, bool enabled) {
+  HWC::Error error = composer_->setVsyncEnabled(display.id,
       (Hwc2::IComposerClient::Vsync)(enabled ? HWC2_VSYNC_ENABLE
                                              : HWC2_VSYNC_DISABLE));
+  if (error != HWC::Error::None) {
+    ALOGE("Error attempting to %s vsync on %s display: %s",
+        enabled ? "enable" : "disable", GetDisplayName(display.is_primary),
+        error.to_string().c_str());
+  }
+  return error == HWC::Error::None;
 }
 
-HWC::Error HardwareComposer::SetPowerMode(bool active) {
+bool HardwareComposer::SetPowerMode(const DisplayParams& display, bool active) {
+  ALOGI("Turning %s display %s", GetDisplayName(display.is_primary),
+      active ? "on" : "off");
   HWC::PowerMode power_mode = active ? HWC::PowerMode::On : HWC::PowerMode::Off;
-  return composer_->setPowerMode(
-      HWC_DISPLAY_PRIMARY, power_mode.cast<Hwc2::IComposerClient::PowerMode>());
+  HWC::Error error = composer_->setPowerMode(display.id,
+      power_mode.cast<Hwc2::IComposerClient::PowerMode>());
+  if (error != HWC::Error::None) {
+    ALOGE("Error attempting to turn %s display %s: %s",
+          GetDisplayName(display.is_primary), active ? "on" : "off",
+        error.to_string().c_str());
+  }
+  return error == HWC::Error::None;
+}
+
+bool HardwareComposer::EnableDisplay(const DisplayParams& display,
+                                     bool enabled) {
+  bool power_result;
+  bool vsync_result;
+  // When turning a display on, we set the power state then set vsync. When
+  // turning a display off we do it in the opposite order.
+  if (enabled) {
+    power_result = SetPowerMode(display, enabled);
+    vsync_result = EnableVsync(display, enabled);
+  } else {
+    vsync_result = EnableVsync(display, enabled);
+    power_result = SetPowerMode(display, enabled);
+  }
+  return power_result && vsync_result;
 }
 
 HWC::Error HardwareComposer::Present(hwc2_display_t display) {
@@ -317,78 +345,105 @@
   return error;
 }
 
-HWC::Error HardwareComposer::GetDisplayAttribute(Hwc2::Composer* composer,
-                                                 hwc2_display_t display,
-                                                 hwc2_config_t config,
-                                                 hwc2_attribute_t attribute,
-                                                 int32_t* out_value) const {
-  return composer->getDisplayAttribute(
-      display, config, (Hwc2::IComposerClient::Attribute)attribute, out_value);
-}
+DisplayParams HardwareComposer::GetDisplayParams(
+    Hwc2::Composer* composer, hwc2_display_t display, bool is_primary) {
+  DisplayParams params;
+  params.id = display;
+  params.is_primary = is_primary;
 
-HWC::Error HardwareComposer::GetDisplayMetrics(
-    Hwc2::Composer* composer, hwc2_display_t display, hwc2_config_t config,
-    HWCDisplayMetrics* out_metrics) const {
-  HWC::Error error;
+  Hwc2::Config config;
+  HWC::Error error = composer->getActiveConfig(display, &config);
 
-  error = GetDisplayAttribute(composer, display, config, HWC2_ATTRIBUTE_WIDTH,
-                              &out_metrics->width);
-  if (error != HWC::Error::None) {
-    ALOGE(
-        "HardwareComposer::GetDisplayMetrics: Failed to get display width: %s",
-        error.to_string().c_str());
-    return error;
+  if (error == HWC::Error::None) {
+    auto get_attr = [&](hwc2_attribute_t attr, const char* attr_name)
+        -> std::optional<int32_t> {
+      int32_t val;
+      HWC::Error error = composer->getDisplayAttribute(
+          display, config, (Hwc2::IComposerClient::Attribute)attr, &val);
+      if (error != HWC::Error::None) {
+        ALOGE("Failed to get %s display attr %s: %s",
+            GetDisplayName(is_primary), attr_name,
+            error.to_string().c_str());
+        return std::nullopt;
+      }
+      return val;
+    };
+
+    auto width = get_attr(HWC2_ATTRIBUTE_WIDTH, "width");
+    auto height = get_attr(HWC2_ATTRIBUTE_HEIGHT, "height");
+
+    if (width && height) {
+      params.width = *width;
+      params.height = *height;
+    } else {
+      ALOGI("Failed to get width and/or height for %s display. Using default"
+          " size %dx%d.", GetDisplayName(is_primary), kDefaultDisplayWidth,
+          kDefaultDisplayHeight);
+      params.width = kDefaultDisplayWidth;
+      params.height = kDefaultDisplayHeight;
+    }
+
+    auto vsync_period = get_attr(HWC2_ATTRIBUTE_VSYNC_PERIOD, "vsync period");
+    if (vsync_period) {
+      params.vsync_period_ns = *vsync_period;
+    } else {
+      ALOGI("Failed to get vsync period for %s display. Using default vsync"
+          " period %.2fms", GetDisplayName(is_primary),
+          static_cast<float>(kDefaultVsyncPeriodNs) / 1000000);
+      params.vsync_period_ns = kDefaultVsyncPeriodNs;
+    }
+
+    auto dpi_x = get_attr(HWC2_ATTRIBUTE_DPI_X, "DPI X");
+    auto dpi_y = get_attr(HWC2_ATTRIBUTE_DPI_Y, "DPI Y");
+    if (dpi_x && dpi_y) {
+      params.dpi.x = *dpi_x;
+      params.dpi.y = *dpi_y;
+    } else {
+      ALOGI("Failed to get dpi_x and/or dpi_y for %s display. Using default"
+          " dpi %d.", GetDisplayName(is_primary), kDefaultDpi);
+      params.dpi.x = kDefaultDpi;
+      params.dpi.y = kDefaultDpi;
+    }
+  } else {
+    ALOGE("HardwareComposer: Failed to get current %s display config: %d."
+        " Using default display values.",
+        GetDisplayName(is_primary), error.value);
+    params.width = kDefaultDisplayWidth;
+    params.height = kDefaultDisplayHeight;
+    params.dpi.x = kDefaultDpi;
+    params.dpi.y = kDefaultDpi;
+    params.vsync_period_ns = kDefaultVsyncPeriodNs;
   }
 
-  error = GetDisplayAttribute(composer, display, config, HWC2_ATTRIBUTE_HEIGHT,
-                              &out_metrics->height);
-  if (error != HWC::Error::None) {
-    ALOGE(
-        "HardwareComposer::GetDisplayMetrics: Failed to get display height: %s",
-        error.to_string().c_str());
-    return error;
-  }
+  ALOGI(
+      "HardwareComposer: %s display attributes: width=%d height=%d "
+      "vsync_period_ns=%d DPI=%dx%d",
+      GetDisplayName(is_primary),
+      params.width,
+      params.height,
+      params.vsync_period_ns,
+      params.dpi.x,
+      params.dpi.y);
 
-  error = GetDisplayAttribute(composer, display, config,
-                              HWC2_ATTRIBUTE_VSYNC_PERIOD,
-                              &out_metrics->vsync_period_ns);
-  if (error != HWC::Error::None) {
-    ALOGE(
-        "HardwareComposer::GetDisplayMetrics: Failed to get display height: %s",
-        error.to_string().c_str());
-    return error;
-  }
-
-  error = GetDisplayAttribute(composer, display, config, HWC2_ATTRIBUTE_DPI_X,
-                              &out_metrics->dpi.x);
-  if (error != HWC::Error::None) {
-    ALOGE(
-        "HardwareComposer::GetDisplayMetrics: Failed to get display DPI X: %s",
-        error.to_string().c_str());
-    return error;
-  }
-
-  error = GetDisplayAttribute(composer, display, config, HWC2_ATTRIBUTE_DPI_Y,
-                              &out_metrics->dpi.y);
-  if (error != HWC::Error::None) {
-    ALOGE(
-        "HardwareComposer::GetDisplayMetrics: Failed to get display DPI Y: %s",
-        error.to_string().c_str());
-    return error;
-  }
-
-  return HWC::Error::None;
+  return params;
 }
 
 std::string HardwareComposer::Dump() {
   std::unique_lock<std::mutex> lock(post_thread_mutex_);
   std::ostringstream stream;
 
-  stream << "Display metrics:     " << display_metrics_.width << "x"
-         << display_metrics_.height << " " << (display_metrics_.dpi.x / 1000.0)
-         << "x" << (display_metrics_.dpi.y / 1000.0) << " dpi @ "
-         << (1000000000.0 / display_metrics_.vsync_period_ns) << " Hz"
-         << std::endl;
+  auto print_display_metrics = [&](const DisplayParams& params) {
+    stream << GetDisplayName(params.is_primary)
+           << " display metrics:     " << params.width << "x"
+           << params.height << " " << (params.dpi.x / 1000.0)
+           << "x" << (params.dpi.y / 1000.0) << " dpi @ "
+           << (1000000000.0 / params.vsync_period_ns) << " Hz"
+           << std::endl;
+  };
+
+  print_display_metrics(primary_display_);
+  if (external_display_)
+    print_display_metrics(*external_display_);
 
   stream << "Post thread resumed: " << post_thread_resumed_ << std::endl;
   stream << "Active layers:       " << layers_.size() << std::endl;
@@ -411,7 +466,7 @@
   return stream.str();
 }
 
-void HardwareComposer::PostLayers() {
+void HardwareComposer::PostLayers(hwc2_display_t display) {
   ATRACE_NAME("HardwareComposer::PostLayers");
 
   // Setup the hardware composer layers with current buffers.
@@ -419,13 +474,6 @@
     layer.Prepare();
   }
 
-  HWC::Error error = Validate(HWC_DISPLAY_PRIMARY);
-  if (error != HWC::Error::None) {
-    ALOGE("HardwareComposer::PostLayers: Validate failed: %s",
-          error.to_string().c_str());
-    return;
-  }
-
   // Now that we have taken in a frame from the application, we have a chance
   // to drop the frame before passing the frame along to HWC.
   // If the display driver has become backed up, we detect it here and then
@@ -466,7 +514,14 @@
   }
 #endif
 
-  error = Present(HWC_DISPLAY_PRIMARY);
+  HWC::Error error = Validate(display);
+  if (error != HWC::Error::None) {
+    ALOGE("HardwareComposer::PostLayers: Validate failed: %s display=%" PRIu64,
+          error.to_string().c_str(), display);
+    return;
+  }
+
+  error = Present(display);
   if (error != HWC::Error::None) {
     ALOGE("HardwareComposer::PostLayers: Present failed: %s",
           error.to_string().c_str());
@@ -475,8 +530,8 @@
 
   std::vector<Hwc2::Layer> out_layers;
   std::vector<int> out_fences;
-  error = composer_->getReleaseFences(HWC_DISPLAY_PRIMARY, &out_layers,
-                                      &out_fences);
+  error = composer_->getReleaseFences(display,
+                                      &out_layers, &out_fences);
   ALOGE_IF(error != HWC::Error::None,
            "HardwareComposer::PostLayers: Failed to get release fences: %s",
            error.to_string().c_str());
@@ -499,10 +554,11 @@
   const bool display_idle = surfaces.size() == 0;
   {
     std::unique_lock<std::mutex> lock(post_thread_mutex_);
-    pending_surfaces_ = std::move(surfaces);
+    surfaces_ = std::move(surfaces);
+    surfaces_changed_ = true;
   }
 
-  if (request_display_callback_ && (!is_standalone_device_ || !composer_))
+  if (request_display_callback_ && !is_standalone_device_)
     request_display_callback_(!display_idle);
 
   // Set idle state based on whether there are any surfaces to handle.
@@ -570,6 +626,9 @@
   // Copy from latest record in shared_config_ring_ to local copy.
   DvrConfig record;
   if (shared_config_ring_.GetNewest(&shared_config_ring_sequence_, &record)) {
+    ALOGI("DvrConfig updated: sequence %u, post offset %d",
+          shared_config_ring_sequence_, record.frame_post_offset_ns);
+    ++shared_config_ring_sequence_;
     post_thread_config_ = record;
   }
 }
@@ -612,21 +671,11 @@
   }
 }
 
-Status<int64_t> HardwareComposer::GetVSyncTime() {
-  auto status = composer_callback_->GetVsyncTime(HWC_DISPLAY_PRIMARY);
-  ALOGE_IF(!status,
-           "HardwareComposer::GetVSyncTime: Failed to get vsync timestamp: %s",
-           status.GetErrorMessage().c_str());
-  return status;
-}
-
-// Waits for the next vsync and returns the timestamp of the vsync event. If
-// vsync already passed since the last call, returns the latest vsync timestamp
-// instead of blocking.
-Status<int64_t> HardwareComposer::WaitForVSync() {
-  const int64_t predicted_vsync_time =
-      last_vsync_timestamp_ +
-      display_metrics_.vsync_period_ns * vsync_prediction_interval_;
+// Sleep until the next predicted vsync, returning the predicted vsync
+// timestamp.
+Status<int64_t> HardwareComposer::WaitForPredictedVSync() {
+  const int64_t predicted_vsync_time = last_vsync_timestamp_ +
+      (target_display_->vsync_period_ns * vsync_prediction_interval_);
   const int error = SleepUntil(predicted_vsync_time);
   if (error < 0) {
     ALOGE("HardwareComposer::WaifForVSync:: Failed to sleep: %s",
@@ -665,16 +714,6 @@
   bool thread_policy_setup =
       SetThreadPolicy("graphics:high", "/system/performance");
 
-#if ENABLE_BACKLIGHT_BRIGHTNESS
-  // TODO(hendrikw): This isn't required at the moment. It's possible that there
-  //                 is another method to access this when needed.
-  // Open the backlight brightness control sysfs node.
-  backlight_brightness_fd_ = LocalHandle(kBacklightBrightnessSysFile, O_RDWR);
-  ALOGW_IF(!backlight_brightness_fd_,
-           "HardwareComposer: Failed to open backlight brightness control: %s",
-           strerror(errno));
-#endif  // ENABLE_BACKLIGHT_BRIGHTNESS
-
   // Create a timerfd based on CLOCK_MONOTINIC.
   vsync_sleep_timer_fd_.Reset(timerfd_create(CLOCK_MONOTONIC, 0));
   LOG_ALWAYS_FATAL_IF(
@@ -682,20 +721,50 @@
       "HardwareComposer: Failed to create vsync sleep timerfd: %s",
       strerror(errno));
 
-  const int64_t ns_per_frame = display_metrics_.vsync_period_ns;
-  const int64_t photon_offset_ns = GetPosePredictionTimeOffset(ns_per_frame);
-
-  // TODO(jbates) Query vblank time from device, when such an API is available.
-  // This value (6.3%) was measured on A00 in low persistence mode.
-  int64_t vblank_ns = ns_per_frame * 63 / 1000;
-  int64_t right_eye_photon_offset_ns = (ns_per_frame - vblank_ns) / 2;
-
-  // Check property for overriding right eye offset value.
-  right_eye_photon_offset_ns =
-      property_get_int64(kRightEyeOffsetProperty, right_eye_photon_offset_ns);
-
+  struct VsyncEyeOffsets { int64_t left_ns, right_ns; };
   bool was_running = false;
 
+  auto get_vsync_eye_offsets = [this]() -> VsyncEyeOffsets {
+    VsyncEyeOffsets offsets;
+    offsets.left_ns =
+        GetPosePredictionTimeOffset(target_display_->vsync_period_ns);
+
+    // TODO(jbates) Query vblank time from device, when such an API is
+    // available. This value (6.3%) was measured on A00 in low persistence mode.
+    int64_t vblank_ns = target_display_->vsync_period_ns * 63 / 1000;
+    offsets.right_ns = (target_display_->vsync_period_ns - vblank_ns) / 2;
+
+    // Check property for overriding right eye offset value.
+    offsets.right_ns =
+        property_get_int64(kRightEyeOffsetProperty, offsets.right_ns);
+
+    return offsets;
+  };
+
+  VsyncEyeOffsets vsync_eye_offsets = get_vsync_eye_offsets();
+
+  if (is_standalone_device_) {
+    // First, wait until boot finishes.
+    std::unique_lock<std::mutex> lock(post_thread_mutex_);
+    if (PostThreadCondWait(lock, -1, [this] { return boot_finished_; })) {
+      return;
+    }
+
+    // Then, wait until we're either leaving the quiescent state, or the boot
+    // finished display off timeout expires.
+    if (PostThreadCondWait(lock, kBootFinishedDisplayOffTimeoutSec,
+                           [this] { return !post_thread_quiescent_; })) {
+      return;
+    }
+
+    LOG_ALWAYS_FATAL_IF(post_thread_state_ & PostThreadState::Suspended,
+                        "Vr flinger should own the display by now.");
+    post_thread_resumed_ = true;
+    post_thread_ready_.notify_all();
+    if (!composer_)
+      CreateComposer();
+  }
+
   while (1) {
     ATRACE_NAME("HardwareComposer::PostThread");
 
@@ -706,31 +775,36 @@
       std::unique_lock<std::mutex> lock(post_thread_mutex_);
       ALOGI("HardwareComposer::PostThread: Entering quiescent state.");
 
-      // Tear down resources if necessary.
-      if (was_running)
-        OnPostThreadPaused();
-
+      // Tear down resources.
+      OnPostThreadPaused();
       was_running = false;
       post_thread_resumed_ = false;
       post_thread_ready_.notify_all();
 
-      if (post_thread_state_ & PostThreadState::Quit) {
-        ALOGI("HardwareComposer::PostThread: Quitting.");
+      if (PostThreadCondWait(lock, -1,
+                             [this] { return !post_thread_quiescent_; })) {
+        // A true return value means we've been asked to quit.
         return;
       }
 
-      post_thread_wait_.wait(lock, [this] { return !post_thread_quiescent_; });
-
       post_thread_resumed_ = true;
       post_thread_ready_.notify_all();
 
       ALOGI("HardwareComposer::PostThread: Exiting quiescent state.");
     }
 
-    if (!was_running) {
-      // Setup resources.
+    if (!composer_)
+      CreateComposer();
+
+    bool target_display_changed = UpdateTargetDisplay();
+    bool just_resumed_running = !was_running;
+    was_running = true;
+
+    if (target_display_changed)
+      vsync_eye_offsets = get_vsync_eye_offsets();
+
+    if (just_resumed_running) {
       OnPostThreadResumed();
-      was_running = true;
 
       // Try to setup the scheduler policy if it failed during startup. Only
       // attempt to do this on transitions from inactive to active to avoid
@@ -739,12 +813,16 @@
         thread_policy_setup =
             SetThreadPolicy("graphics:high", "/system/performance");
       }
+    }
 
+    if (target_display_changed || just_resumed_running) {
       // Initialize the last vsync timestamp with the current time. The
       // predictor below uses this time + the vsync interval in absolute time
       // units for the initial delay. Once the driver starts reporting vsync the
       // predictor will sync up with the real vsync.
       last_vsync_timestamp_ = GetSystemClockNs();
+      vsync_prediction_interval_ = 1;
+      retire_fence_fds_.clear();
     }
 
     int64_t vsync_timestamp = 0;
@@ -754,7 +832,7 @@
                    vsync_count_ + 1, last_vsync_timestamp_,
                    vsync_prediction_interval_);
 
-      auto status = WaitForVSync();
+      auto status = WaitForPredictedVSync();
       ALOGE_IF(
           !status,
           "HardwareComposer::PostThread: Failed to wait for vsync event: %s",
@@ -775,16 +853,16 @@
     if (vsync_prediction_interval_ == 1)
       ++vsync_count_;
 
-    const bool layer_config_changed = UpdateLayerConfig();
+    UpdateLayerConfig();
 
     // Publish the vsync event.
     if (vsync_ring_) {
       DvrVsync vsync;
       vsync.vsync_count = vsync_count_;
       vsync.vsync_timestamp_ns = vsync_timestamp;
-      vsync.vsync_left_eye_offset_ns = photon_offset_ns;
-      vsync.vsync_right_eye_offset_ns = right_eye_photon_offset_ns;
-      vsync.vsync_period_ns = ns_per_frame;
+      vsync.vsync_left_eye_offset_ns = vsync_eye_offsets.left_ns;
+      vsync.vsync_right_eye_offset_ns = vsync_eye_offsets.right_ns;
+      vsync.vsync_period_ns = target_display_->vsync_period_ns;
 
       vsync_ring_->Publish(vsync);
     }
@@ -792,14 +870,14 @@
     // Signal all of the vsync clients. Because absolute time is used for the
     // wakeup time below, this can take a little time if necessary.
     if (vsync_callback_)
-      vsync_callback_(HWC_DISPLAY_PRIMARY, vsync_timestamp,
-                      /*frame_time_estimate*/ 0, vsync_count_);
+      vsync_callback_(vsync_timestamp, /*frame_time_estimate*/ 0, vsync_count_);
 
     {
       // Sleep until shortly before vsync.
       ATRACE_NAME("sleep");
 
-      const int64_t display_time_est_ns = vsync_timestamp + ns_per_frame;
+      const int64_t display_time_est_ns =
+          vsync_timestamp + target_display_->vsync_period_ns;
       const int64_t now_ns = GetSystemClockNs();
       const int64_t sleep_time_ns = display_time_est_ns - now_ns -
                                     post_thread_config_.frame_post_offset_ns;
@@ -809,26 +887,18 @@
       ATRACE_INT64("sleep_time_ns", sleep_time_ns);
       if (sleep_time_ns > 0) {
         int error = SleepUntil(wakeup_time_ns);
-        ALOGE_IF(error < 0, "HardwareComposer::PostThread: Failed to sleep: %s",
+        ALOGE_IF(error < 0 && error != kPostThreadInterrupted,
+                 "HardwareComposer::PostThread: Failed to sleep: %s",
                  strerror(-error));
-        if (error == kPostThreadInterrupted) {
-          if (layer_config_changed) {
-            // If the layer config changed we need to validateDisplay() even if
-            // we're going to drop the frame, to flush the Composer object's
-            // internal command buffer and apply our layer changes.
-            Validate(HWC_DISPLAY_PRIMARY);
-          }
-          continue;
-        }
+        // If the sleep was interrupted (error == kPostThreadInterrupted),
+        // we still go through and present this frame because we may have set
+        // layers earlier and we want to flush the Composer's internal command
+        // buffer by continuing through to validate and present.
       }
     }
 
     {
-      auto status = GetVSyncTime();
-      if (!status) {
-        ALOGE("HardwareComposer::PostThread: Failed to get VSYNC time: %s",
-              status.GetErrorMessage().c_str());
-      }
+      auto status = composer_callback_->GetVsyncTime(target_display_->id);
 
       // If we failed to read vsync there might be a problem with the driver.
       // Since there's nothing we can do just behave as though we didn't get an
@@ -855,20 +925,84 @@
       }
     }
 
-    PostLayers();
+    PostLayers(target_display_->id);
   }
 }
 
+bool HardwareComposer::UpdateTargetDisplay() {
+  bool target_display_changed = false;
+  auto displays = composer_callback_->GetDisplays();
+  if (displays.external_display_was_hotplugged) {
+    bool was_using_external_display = !target_display_->is_primary;
+    if (was_using_external_display) {
+      // The external display was hotplugged, so make sure to ignore any bad
+      // display errors as we destroy the layers.
+      for (auto& layer: layers_)
+        layer.IgnoreBadDisplayErrorsOnDestroy(true);
+    }
+
+    if (displays.external_display) {
+      // External display was connected
+      external_display_ = GetDisplayParams(composer_.get(),
+          *displays.external_display, /*is_primary*/ false);
+
+      if (property_get_bool(kUseExternalDisplayProperty, false)) {
+        ALOGI("External display connected. Switching to external display.");
+        target_display_ = &(*external_display_);
+        target_display_changed = true;
+      } else {
+        ALOGI("External display connected, but sysprop %s is unset, so"
+              " using primary display.", kUseExternalDisplayProperty);
+        if (was_using_external_display) {
+          target_display_ = &primary_display_;
+          target_display_changed = true;
+        }
+      }
+    } else {
+      // External display was disconnected
+      external_display_ = std::nullopt;
+      if (was_using_external_display) {
+        ALOGI("External display disconnected. Switching to primary display.");
+        target_display_ = &primary_display_;
+        target_display_changed = true;
+      }
+    }
+  }
+
+  if (target_display_changed) {
+    // If we're switching to the external display, turn the primary display off.
+    if (!target_display_->is_primary) {
+      EnableDisplay(primary_display_, false);
+    }
+    // If we're switching to the primary display, and the external display is
+    // still connected, turn the external display off.
+    else if (target_display_->is_primary && external_display_) {
+      EnableDisplay(*external_display_, false);
+    }
+
+    // Turn the new target display on.
+    EnableDisplay(*target_display_, true);
+
+    // When we switch displays we need to recreate all the layers, so clear the
+    // current list, which will trigger layer recreation.
+    layers_.clear();
+  }
+
+  return target_display_changed;
+}
+
 // Checks for changes in the surface stack and updates the layer config to
 // accomodate the new stack.
-bool HardwareComposer::UpdateLayerConfig() {
+void HardwareComposer::UpdateLayerConfig() {
   std::vector<std::shared_ptr<DirectDisplaySurface>> surfaces;
   {
     std::unique_lock<std::mutex> lock(post_thread_mutex_);
-    if (pending_surfaces_.empty())
-      return false;
 
-    surfaces = std::move(pending_surfaces_);
+    if (!surfaces_changed_ && (!layers_.empty() || surfaces_.empty()))
+      return;
+
+    surfaces = surfaces_;
+    surfaces_changed_ = false;
   }
 
   ATRACE_NAME("UpdateLayerConfig_HwLayers");
@@ -905,8 +1039,8 @@
       layers_.erase(search);
     } else {
       // Insert a layer for the new surface.
-      layers.emplace_back(surface, blending, display_transform_,
-                          HWC::Composition::Device, layer_index);
+      layers.emplace_back(composer_.get(), *target_display_, surface, blending,
+          HWC::Composition::Device, layer_index);
     }
 
     ALOGI_IF(
@@ -927,26 +1061,36 @@
 
   ALOGD_IF(TRACE, "HardwareComposer::UpdateLayerConfig: %zd active layers",
            layers_.size());
-  return true;
 }
 
 void HardwareComposer::SetVSyncCallback(VSyncCallback callback) {
   vsync_callback_ = callback;
 }
 
-void HardwareComposer::SetBacklightBrightness(int brightness) {
-  if (backlight_brightness_fd_) {
-    std::array<char, 32> text;
-    const int length = snprintf(text.data(), text.size(), "%d", brightness);
-    write(backlight_brightness_fd_.Get(), text.data(), length);
-  }
-}
-
 Return<void> HardwareComposer::ComposerCallback::onHotplug(
-    Hwc2::Display display, IComposerCallback::Connection /*conn*/) {
-  // See if the driver supports the vsync_event node in sysfs.
-  if (display < HWC_NUM_PHYSICAL_DISPLAY_TYPES &&
-      !displays_[display].driver_vsync_event_fd) {
+    Hwc2::Display display, IComposerCallback::Connection conn) {
+  std::lock_guard<std::mutex> lock(mutex_);
+  ALOGI("onHotplug display=%" PRIu64 " conn=%d", display, conn);
+
+  bool is_primary = !got_first_hotplug_ || display == primary_display_.id;
+
+  // Our first onHotplug callback is always for the primary display.
+  if (!got_first_hotplug_) {
+    LOG_ALWAYS_FATAL_IF(conn != IComposerCallback::Connection::CONNECTED,
+        "Initial onHotplug callback should be primary display connected");
+    got_first_hotplug_ = true;
+  } else if (is_primary) {
+    ALOGE("Ignoring unexpected onHotplug() call for primary display");
+    return Void();
+  }
+
+  if (conn == IComposerCallback::Connection::CONNECTED) {
+    if (!is_primary)
+      external_display_ = DisplayInfo();
+    DisplayInfo& display_info = is_primary ?
+        primary_display_ : *external_display_;
+    display_info.id = display;
+
     std::array<char, 1024> buffer;
     snprintf(buffer.data(), buffer.size(),
              "/sys/class/graphics/fb%" PRIu64 "/vsync_event", display);
@@ -955,15 +1099,20 @@
           "HardwareComposer::ComposerCallback::onHotplug: Driver supports "
           "vsync_event node for display %" PRIu64,
           display);
-      displays_[display].driver_vsync_event_fd = std::move(handle);
+      display_info.driver_vsync_event_fd = std::move(handle);
     } else {
       ALOGI(
           "HardwareComposer::ComposerCallback::onHotplug: Driver does not "
           "support vsync_event node for display %" PRIu64,
           display);
     }
+  } else if (conn == IComposerCallback::Connection::DISCONNECTED) {
+    external_display_ = std::nullopt;
   }
 
+  if (!is_primary)
+    external_display_was_hotplugged_ = true;
+
   return Void();
 }
 
@@ -974,36 +1123,45 @@
 
 Return<void> HardwareComposer::ComposerCallback::onVsync(Hwc2::Display display,
                                                          int64_t timestamp) {
-  TRACE_FORMAT("vsync_callback|display=%" PRIu64 ";timestamp=%" PRId64 "|",
-               display, timestamp);
-  if (display < HWC_NUM_PHYSICAL_DISPLAY_TYPES) {
-    displays_[display].callback_vsync_timestamp = timestamp;
-  } else {
-    ALOGW(
-        "HardwareComposer::ComposerCallback::onVsync: Received vsync on "
-        "non-physical display: display=%" PRId64,
-        display);
+  DisplayInfo* display_info = GetDisplayInfo(display);
+  if (display_info) {
+    TRACE_FORMAT("vsync_callback|display=%" PRIu64 ";timestamp=%" PRId64 "|",
+                 display, timestamp);
+    display_info->callback_vsync_timestamp = timestamp;
   }
+
   return Void();
 }
 
+HardwareComposer::ComposerCallback::Displays
+HardwareComposer::ComposerCallback::GetDisplays() {
+  std::lock_guard<std::mutex> lock(mutex_);
+  Displays displays;
+  displays.primary_display = primary_display_.id;
+  if (external_display_)
+    displays.external_display = external_display_->id;
+  if (external_display_was_hotplugged_) {
+    external_display_was_hotplugged_ = false;
+    displays.external_display_was_hotplugged = true;
+  }
+  return displays;
+}
+
 Status<int64_t> HardwareComposer::ComposerCallback::GetVsyncTime(
-    Hwc2::Display display) {
-  if (display >= HWC_NUM_PHYSICAL_DISPLAY_TYPES) {
-    ALOGE(
-        "HardwareComposer::ComposerCallback::GetVsyncTime: Invalid physical "
-        "display requested: display=%" PRIu64,
-        display);
+    hwc2_display_t display) {
+  DisplayInfo* display_info = GetDisplayInfo(display);
+  if (!display_info) {
+    ALOGW("Attempt to get vsync time for unknown display %" PRIu64, display);
     return ErrorStatus(EINVAL);
   }
 
   // See if the driver supports direct vsync events.
-  LocalHandle& event_fd = displays_[display].driver_vsync_event_fd;
+  LocalHandle& event_fd = display_info->driver_vsync_event_fd;
   if (!event_fd) {
     // Fall back to returning the last timestamp returned by the vsync
     // callback.
-    std::lock_guard<std::mutex> autolock(vsync_mutex_);
-    return displays_[display].callback_vsync_timestamp;
+    std::lock_guard<std::mutex> autolock(mutex_);
+    return display_info->callback_vsync_timestamp;
   }
 
   // When the driver supports the vsync_event sysfs node we can use it to
@@ -1051,18 +1209,32 @@
   return {timestamp};
 }
 
-Hwc2::Composer* Layer::composer_{nullptr};
-HWCDisplayMetrics Layer::display_metrics_{0, 0, {0, 0}, 0};
+HardwareComposer::ComposerCallback::DisplayInfo*
+HardwareComposer::ComposerCallback::GetDisplayInfo(hwc2_display_t display) {
+  if (display == primary_display_.id) {
+    return &primary_display_;
+  } else if (external_display_ && display == external_display_->id) {
+    return &(*external_display_);
+  }
+  return nullptr;
+}
 
 void Layer::Reset() {
   if (hardware_composer_layer_) {
-    composer_->destroyLayer(HWC_DISPLAY_PRIMARY, hardware_composer_layer_);
+    HWC::Error error =
+        composer_->destroyLayer(display_params_.id, hardware_composer_layer_);
+    if (error != HWC::Error::None &&
+        (!ignore_bad_display_errors_on_destroy_ ||
+         error != HWC::Error::BadDisplay)) {
+      ALOGE("destroyLayer() failed for display %" PRIu64 ", layer %" PRIu64
+          ". error: %s", display_params_.id, hardware_composer_layer_,
+          error.to_string().c_str());
+    }
     hardware_composer_layer_ = 0;
   }
 
   z_order_ = 0;
   blending_ = HWC::BlendMode::None;
-  transform_ = HWC::Transform::None;
   composition_type_ = HWC::Composition::Invalid;
   target_composition_type_ = composition_type_;
   source_ = EmptyVariant{};
@@ -1070,25 +1242,29 @@
   surface_rect_functions_applied_ = false;
   pending_visibility_settings_ = true;
   cached_buffer_map_.clear();
+  ignore_bad_display_errors_on_destroy_ = false;
 }
 
-Layer::Layer(const std::shared_ptr<DirectDisplaySurface>& surface,
-             HWC::BlendMode blending, HWC::Transform transform,
-             HWC::Composition composition_type, size_t z_order)
-    : z_order_{z_order},
+Layer::Layer(Hwc2::Composer* composer, const DisplayParams& display_params,
+             const std::shared_ptr<DirectDisplaySurface>& surface,
+             HWC::BlendMode blending, HWC::Composition composition_type,
+             size_t z_order)
+    : composer_(composer),
+      display_params_(display_params),
+      z_order_{z_order},
       blending_{blending},
-      transform_{transform},
       target_composition_type_{composition_type},
       source_{SourceSurface{surface}} {
   CommonLayerSetup();
 }
 
-Layer::Layer(const std::shared_ptr<IonBuffer>& buffer, HWC::BlendMode blending,
-             HWC::Transform transform, HWC::Composition composition_type,
-             size_t z_order)
-    : z_order_{z_order},
+Layer::Layer(Hwc2::Composer* composer, const DisplayParams& display_params,
+             const std::shared_ptr<IonBuffer>& buffer, HWC::BlendMode blending,
+             HWC::Composition composition_type, size_t z_order)
+    : composer_(composer),
+      display_params_(display_params),
+      z_order_{z_order},
       blending_{blending},
-      transform_{transform},
       target_composition_type_{composition_type},
       source_{SourceBuffer{buffer}} {
   CommonLayerSetup();
@@ -1102,10 +1278,11 @@
   if (this != &other) {
     Reset();
     using std::swap;
+    swap(composer_, other.composer_);
+    swap(display_params_, other.display_params_);
     swap(hardware_composer_layer_, other.hardware_composer_layer_);
     swap(z_order_, other.z_order_);
     swap(blending_, other.blending_);
-    swap(transform_, other.transform_);
     swap(composition_type_, other.composition_type_);
     swap(target_composition_type_, other.target_composition_type_);
     swap(source_, other.source_);
@@ -1114,6 +1291,8 @@
          other.surface_rect_functions_applied_);
     swap(pending_visibility_settings_, other.pending_visibility_settings_);
     swap(cached_buffer_map_, other.cached_buffer_map_);
+    swap(ignore_bad_display_errors_on_destroy_,
+         other.ignore_bad_display_errors_on_destroy_);
   }
   return *this;
 }
@@ -1151,17 +1330,16 @@
     pending_visibility_settings_ = false;
 
     HWC::Error error;
-    hwc2_display_t display = HWC_DISPLAY_PRIMARY;
 
     error = composer_->setLayerBlendMode(
-        display, hardware_composer_layer_,
+        display_params_.id, hardware_composer_layer_,
         blending_.cast<Hwc2::IComposerClient::BlendMode>());
     ALOGE_IF(error != HWC::Error::None,
              "Layer::UpdateLayerSettings: Error setting layer blend mode: %s",
              error.to_string().c_str());
 
-    error =
-        composer_->setLayerZOrder(display, hardware_composer_layer_, z_order_);
+    error = composer_->setLayerZOrder(display_params_.id,
+        hardware_composer_layer_, z_order_);
     ALOGE_IF(error != HWC::Error::None,
              "Layer::UpdateLayerSettings: Error setting z_ order: %s",
              error.to_string().c_str());
@@ -1170,36 +1348,35 @@
 
 void Layer::UpdateLayerSettings() {
   HWC::Error error;
-  hwc2_display_t display = HWC_DISPLAY_PRIMARY;
 
   UpdateVisibilitySettings();
 
   // TODO(eieio): Use surface attributes or some other mechanism to control
   // the layer display frame.
   error = composer_->setLayerDisplayFrame(
-      display, hardware_composer_layer_,
-      {0, 0, display_metrics_.width, display_metrics_.height});
+      display_params_.id, hardware_composer_layer_,
+      {0, 0, display_params_.width, display_params_.height});
   ALOGE_IF(error != HWC::Error::None,
            "Layer::UpdateLayerSettings: Error setting layer display frame: %s",
            error.to_string().c_str());
 
   error = composer_->setLayerVisibleRegion(
-      display, hardware_composer_layer_,
-      {{0, 0, display_metrics_.width, display_metrics_.height}});
+      display_params_.id, hardware_composer_layer_,
+      {{0, 0, display_params_.width, display_params_.height}});
   ALOGE_IF(error != HWC::Error::None,
            "Layer::UpdateLayerSettings: Error setting layer visible region: %s",
            error.to_string().c_str());
 
-  error =
-      composer_->setLayerPlaneAlpha(display, hardware_composer_layer_, 1.0f);
+  error = composer_->setLayerPlaneAlpha(display_params_.id,
+      hardware_composer_layer_, 1.0f);
   ALOGE_IF(error != HWC::Error::None,
            "Layer::UpdateLayerSettings: Error setting layer plane alpha: %s",
            error.to_string().c_str());
 }
 
 void Layer::CommonLayerSetup() {
-  HWC::Error error =
-      composer_->createLayer(HWC_DISPLAY_PRIMARY, &hardware_composer_layer_);
+  HWC::Error error = composer_->createLayer(display_params_.id,
+                                            &hardware_composer_layer_);
   ALOGE_IF(error != HWC::Error::None,
            "Layer::CommonLayerSetup: Failed to create layer on primary "
            "display: %s",
@@ -1243,10 +1420,10 @@
     if (composition_type_ == HWC::Composition::Invalid) {
       composition_type_ = HWC::Composition::SolidColor;
       composer_->setLayerCompositionType(
-          HWC_DISPLAY_PRIMARY, hardware_composer_layer_,
+          display_params_.id, hardware_composer_layer_,
           composition_type_.cast<Hwc2::IComposerClient::Composition>());
       Hwc2::IComposerClient::Color layer_color = {0, 0, 0, 0};
-      composer_->setLayerColor(HWC_DISPLAY_PRIMARY, hardware_composer_layer_,
+      composer_->setLayerColor(display_params_.id, hardware_composer_layer_,
                                layer_color);
     } else {
       // The composition type is already set. Nothing else to do until a
@@ -1256,7 +1433,7 @@
     if (composition_type_ != target_composition_type_) {
       composition_type_ = target_composition_type_;
       composer_->setLayerCompositionType(
-          HWC_DISPLAY_PRIMARY, hardware_composer_layer_,
+          display_params_.id, hardware_composer_layer_,
           composition_type_.cast<Hwc2::IComposerClient::Composition>());
     }
 
@@ -1267,7 +1444,7 @@
 
     HWC::Error error{HWC::Error::None};
     error =
-        composer_->setLayerBuffer(HWC_DISPLAY_PRIMARY, hardware_composer_layer_,
+        composer_->setLayerBuffer(display_params_.id, hardware_composer_layer_,
                                   slot, handle, acquire_fence_.Get());
 
     ALOGE_IF(error != HWC::Error::None,
@@ -1277,7 +1454,7 @@
     if (!surface_rect_functions_applied_) {
       const float float_right = right;
       const float float_bottom = bottom;
-      error = composer_->setLayerSourceCrop(HWC_DISPLAY_PRIMARY,
+      error = composer_->setLayerSourceCrop(display_params_.id,
                                             hardware_composer_layer_,
                                             {0, 0, float_right, float_bottom});
 
diff --git a/libs/vr/libvrflinger/hardware_composer.h b/libs/vr/libvrflinger/hardware_composer.h
index 7010db9..1d8d463 100644
--- a/libs/vr/libvrflinger/hardware_composer.h
+++ b/libs/vr/libvrflinger/hardware_composer.h
@@ -13,6 +13,7 @@
 #include <condition_variable>
 #include <memory>
 #include <mutex>
+#include <optional>
 #include <thread>
 #include <tuple>
 #include <vector>
@@ -35,16 +36,19 @@
 namespace android {
 namespace dvr {
 
-// Basic display metrics for physical displays. Dimensions and densities are
-// relative to the physical display orientation, which may be different from the
-// logical display orientation exposed to applications.
-struct HWCDisplayMetrics {
+// Basic display metrics for physical displays.
+struct DisplayParams {
+  hwc2_display_t id;
+  bool is_primary;
+
   int width;
   int height;
+
   struct {
     int x;
     int y;
   } dpi;
+
   int vsync_period_ns;
 };
 
@@ -58,26 +62,29 @@
   // automatically handles ACQUIRE/RELEASE phases for the surface's buffer train
   // every frame.
   //
+  // |composer| The composer instance.
+  // |display_params| Info about the display to use.
   // |blending| receives HWC_BLENDING_* values.
-  // |transform| receives HWC_TRANSFORM_* values.
   // |composition_type| receives either HWC_FRAMEBUFFER for most layers or
   // HWC_FRAMEBUFFER_TARGET (unless you know what you are doing).
   // |index| is the index of this surface in the DirectDisplaySurface array.
-  Layer(const std::shared_ptr<DirectDisplaySurface>& surface,
-        HWC::BlendMode blending, HWC::Transform transform,
-        HWC::Composition composition_type, size_t z_roder);
+  Layer(Hwc2::Composer* composer, const DisplayParams& display_params,
+        const std::shared_ptr<DirectDisplaySurface>& surface,
+        HWC::BlendMode blending, HWC::Composition composition_type,
+        size_t z_order);
 
   // Sets up the layer to use a direct buffer as its content source. No special
   // handling of the buffer is performed; responsibility for updating or
   // changing the buffer each frame is on the caller.
   //
+  // |composer| The composer instance.
+  // |display_params| Info about the display to use.
   // |blending| receives HWC_BLENDING_* values.
-  // |transform| receives HWC_TRANSFORM_* values.
   // |composition_type| receives either HWC_FRAMEBUFFER for most layers or
   // HWC_FRAMEBUFFER_TARGET (unless you know what you are doing).
-  Layer(const std::shared_ptr<IonBuffer>& buffer, HWC::BlendMode blending,
-        HWC::Transform transform, HWC::Composition composition_type,
-        size_t z_order);
+  Layer(Hwc2::Composer* composer, const DisplayParams& display_params,
+        const std::shared_ptr<IonBuffer>& buffer, HWC::BlendMode blending,
+        HWC::Composition composition_type, size_t z_order);
 
   Layer(Layer&&);
   Layer& operator=(Layer&&);
@@ -144,12 +151,8 @@
   }
   bool operator<(int surface_id) const { return GetSurfaceId() < surface_id; }
 
-  // Sets the composer instance used by all Layer instances.
-  static void SetComposer(Hwc2::Composer* composer) { composer_ = composer; }
-
-  // Sets the display metrics used by all Layer instances.
-  static void SetDisplayMetrics(HWCDisplayMetrics display_metrics) {
-    display_metrics_ = display_metrics;
+  void IgnoreBadDisplayErrorsOnDestroy(bool ignore) {
+    ignore_bad_display_errors_on_destroy_ = ignore;
   }
 
  private:
@@ -169,16 +172,11 @@
   // associated and always returns false.
   bool CheckAndUpdateCachedBuffer(std::size_t slot, int buffer_id);
 
-  // Composer instance shared by all instances of Layer. This must be set
-  // whenever a new instance of the Composer is created. This may be set to
-  // nullptr as long as there are no instances of Layer that might need to use
-  // it.
-  static Hwc2::Composer* composer_;
+  // Composer instance.
+  Hwc2::Composer* composer_ = nullptr;
 
-  // Display metrics shared by all instances of Layer. This must be set at least
-  // once during VrFlinger initialization and is expected to remain constant
-  // thereafter.
-  static HWCDisplayMetrics display_metrics_;
+  // Parameters of the display to use for this layer.
+  DisplayParams display_params_;
 
   // The hardware composer layer and metrics to use during the prepare cycle.
   hwc2_layer_t hardware_composer_layer_ = 0;
@@ -187,7 +185,6 @@
   // Prepare phase.
   size_t z_order_ = 0;
   HWC::BlendMode blending_ = HWC::BlendMode::None;
-  HWC::Transform transform_ = HWC::Transform::None;
   HWC::Composition composition_type_ = HWC::Composition::Invalid;
   HWC::Composition target_composition_type_ = HWC::Composition::Device;
 
@@ -283,6 +280,12 @@
   // importing a buffer HWC already knows about.
   std::map<std::size_t, int> cached_buffer_map_;
 
+  // When calling destroyLayer() on an external display that's been removed we
+  // typically get HWC2_ERROR_BAD_DISPLAY errors. If
+  // ignore_bad_display_errors_on_destroy_ is true, don't log the bad display
+  // errors, since they're expected.
+  bool ignore_bad_display_errors_on_destroy_ = false;
+
   Layer(const Layer&) = delete;
   void operator=(const Layer&) = delete;
 };
@@ -298,13 +301,14 @@
 class HardwareComposer {
  public:
   // Type for vsync callback.
-  using VSyncCallback = std::function<void(int, int64_t, int64_t, uint32_t)>;
+  using VSyncCallback = std::function<void(int64_t, int64_t, uint32_t)>;
   using RequestDisplayCallback = std::function<void(bool)>;
 
   HardwareComposer();
   ~HardwareComposer();
 
   bool Initialize(Hwc2::Composer* composer,
+                  hwc2_display_t primary_display_id,
                   RequestDisplayCallback request_display_callback);
 
   bool IsInitialized() const { return initialized_; }
@@ -316,22 +320,15 @@
   // it's paused. This should only be called from surface flinger's main thread.
   void Disable();
 
-  // Get the HMD display metrics for the current display.
-  display::Metrics GetHmdDisplayMetrics() const;
+  // Called on a binder thread.
+  void OnBootFinished();
 
   std::string Dump();
 
   void SetVSyncCallback(VSyncCallback callback);
 
-  // Metrics of the logical display, which is always landscape.
-  int DisplayWidth() const { return display_metrics_.width; }
-  int DisplayHeight() const { return display_metrics_.height; }
-  HWCDisplayMetrics display_metrics() const { return display_metrics_; }
-
-  // Metrics of the native display, which depends on the specific hardware
-  // implementation of the display.
-  HWCDisplayMetrics native_display_metrics() const {
-    return native_display_metrics_;
+  const DisplayParams& GetPrimaryDisplayParams() const {
+    return primary_display_;
   }
 
   // Sets the display surfaces to compose the hardware layer stack.
@@ -342,16 +339,16 @@
   void OnDeletedGlobalBuffer(DvrGlobalBufferKey key);
 
  private:
-  HWC::Error GetDisplayAttribute(Hwc2::Composer* composer,
-                                 hwc2_display_t display, hwc2_config_t config,
-                                 hwc2_attribute_t attributes,
-                                 int32_t* out_value) const;
-  HWC::Error GetDisplayMetrics(Hwc2::Composer* composer, hwc2_display_t display,
-                               hwc2_config_t config,
-                               HWCDisplayMetrics* out_metrics) const;
+  DisplayParams GetDisplayParams(Hwc2::Composer* composer,
+      hwc2_display_t display, bool is_primary);
 
-  HWC::Error EnableVsync(bool enabled);
-  HWC::Error SetPowerMode(bool active);
+  // Turn display vsync on/off. Returns true on success, false on failure.
+  bool EnableVsync(const DisplayParams& display, bool enabled);
+  // Turn display power on/off. Returns true on success, false on failure.
+  bool SetPowerMode(const DisplayParams& display, bool active);
+  // Convenience function to turn a display on/off. Turns both power and vsync
+  // on/off. Returns true on success, false on failure.
+  bool EnableDisplay(const DisplayParams& display, bool enabled);
 
   class ComposerCallback : public Hwc2::IComposerCallback {
    public:
@@ -362,24 +359,38 @@
     hardware::Return<void> onVsync(Hwc2::Display display,
                                    int64_t timestamp) override;
 
-    pdx::Status<int64_t> GetVsyncTime(Hwc2::Display display);
+    bool GotFirstHotplug() { return got_first_hotplug_; }
+
+    struct Displays {
+      hwc2_display_t primary_display = 0;
+      std::optional<hwc2_display_t> external_display;
+      bool external_display_was_hotplugged = false;
+    };
+
+    Displays GetDisplays();
+    pdx::Status<int64_t> GetVsyncTime(hwc2_display_t display);
 
    private:
-    std::mutex vsync_mutex_;
-
-    struct Display {
+    struct DisplayInfo {
+      hwc2_display_t id = 0;
       pdx::LocalHandle driver_vsync_event_fd;
       int64_t callback_vsync_timestamp{0};
     };
-    std::array<Display, HWC_NUM_PHYSICAL_DISPLAY_TYPES> displays_;
+
+    DisplayInfo* GetDisplayInfo(hwc2_display_t display);
+
+    std::mutex mutex_;
+
+    bool got_first_hotplug_ = false;
+    DisplayInfo primary_display_;
+    std::optional<DisplayInfo> external_display_;
+    bool external_display_was_hotplugged_ = false;
   };
 
   HWC::Error Validate(hwc2_display_t display);
   HWC::Error Present(hwc2_display_t display);
 
-  void SetBacklightBrightness(int brightness);
-
-  void PostLayers();
+  void PostLayers(hwc2_display_t display);
   void PostThread();
 
   // The post thread has two controlling states:
@@ -407,23 +418,40 @@
   int PostThreadPollInterruptible(const pdx::LocalHandle& event_fd,
                                   int requested_events, int timeout_ms);
 
-  // WaitForVSync and SleepUntil are blocking calls made on the post thread that
-  // can be interrupted by a control thread. If interrupted, these calls return
-  // kPostThreadInterrupted.
+  // WaitForPredictedVSync and SleepUntil are blocking calls made on the post
+  // thread that can be interrupted by a control thread. If interrupted, these
+  // calls return kPostThreadInterrupted.
   int ReadWaitPPState();
-  pdx::Status<int64_t> WaitForVSync();
-  pdx::Status<int64_t> GetVSyncTime();
+  pdx::Status<int64_t> WaitForPredictedVSync();
   int SleepUntil(int64_t wakeup_timestamp);
 
+  // Initialize any newly connected displays, and set target_display_ to the
+  // display we should render to. Returns true if target_display_
+  // changed. Called only from the post thread.
+  bool UpdateTargetDisplay();
+
   // Reconfigures the layer stack if the display surfaces changed since the last
   // frame. Called only from the post thread.
-  bool UpdateLayerConfig();
+  void UpdateLayerConfig();
+
+  // Called on the post thread to create the Composer instance.
+  void CreateComposer();
 
   // Called on the post thread when the post thread is resumed.
   void OnPostThreadResumed();
   // Called on the post thread when the post thread is paused or quits.
   void OnPostThreadPaused();
 
+  // Use post_thread_wait_ to wait for a specific condition, specified by pred.
+  // timeout_sec < 0 means wait indefinitely, otherwise it specifies the timeout
+  // in seconds.
+  // The lock must be held when this function is called.
+  // Returns true if the wait was interrupted because the post thread was asked
+  // to quit.
+  bool PostThreadCondWait(std::unique_lock<std::mutex>& lock,
+                          int timeout_sec,
+                          const std::function<bool()>& pred);
+
   // Map the given shared memory buffer to our broadcast ring to track updates
   // to the config parameters.
   int MapConfigBuffer(IonBuffer& ion_buffer);
@@ -438,18 +466,19 @@
   sp<ComposerCallback> composer_callback_;
   RequestDisplayCallback request_display_callback_;
 
-  // Display metrics of the physical display.
-  HWCDisplayMetrics native_display_metrics_;
-  // Display metrics of the logical display, adjusted so that orientation is
-  // landscape.
-  HWCDisplayMetrics display_metrics_;
-  // Transform required to get from native to logical display orientation.
-  HWC::Transform display_transform_ = HWC::Transform::None;
+  DisplayParams primary_display_;
+  std::optional<DisplayParams> external_display_;
+  DisplayParams* target_display_ = &primary_display_;
 
-  // Pending surface list. Set by the display service when DirectSurfaces are
-  // added, removed, or change visibility. Written by the message dispatch
-  // thread and read by the post thread.
-  std::vector<std::shared_ptr<DirectDisplaySurface>> pending_surfaces_;
+  // The list of surfaces we should draw. Set by the display service when
+  // DirectSurfaces are added, removed, or change visibility. Written by the
+  // message dispatch thread and read by the post thread.
+  std::vector<std::shared_ptr<DirectDisplaySurface>> surfaces_;
+  // Set to true by the dispatch thread whenever surfaces_ changes. Set to false
+  // by the post thread when the new list of surfaces is processed.
+  bool surfaces_changed_ = false;
+
+  std::vector<std::shared_ptr<DirectDisplaySurface>> current_surfaces_;
 
   // Layer set for handling buffer flow into hardware composer layers. This
   // vector must be sorted by surface_id in ascending order.
@@ -472,8 +501,9 @@
   std::condition_variable post_thread_wait_;
   std::condition_variable post_thread_ready_;
 
-  // Backlight LED brightness sysfs node.
-  pdx::LocalHandle backlight_brightness_fd_;
+  // When boot is finished this will be set to true and the post thread will be
+  // notified via post_thread_wait_.
+  bool boot_finished_ = false;
 
   // VSync sleep timerfd.
   pdx::LocalHandle vsync_sleep_timer_fd_;
diff --git a/libs/vr/libvrflinger/include/dvr/vr_flinger.h b/libs/vr/libvrflinger/include/dvr/vr_flinger.h
index 33cbc84..c740dde 100644
--- a/libs/vr/libvrflinger/include/dvr/vr_flinger.h
+++ b/libs/vr/libvrflinger/include/dvr/vr_flinger.h
@@ -4,6 +4,12 @@
 #include <thread>
 #include <memory>
 
+#define HWC2_INCLUDE_STRINGIFICATION
+#define HWC2_USE_CPP11
+#include <hardware/hwcomposer2.h>
+#undef HWC2_INCLUDE_STRINGIFICATION
+#undef HWC2_USE_CPP11
+
 #include <pdx/service_dispatcher.h>
 #include <vr/vr_manager/vr_manager.h>
 
@@ -21,7 +27,9 @@
  public:
   using RequestDisplayCallback = std::function<void(bool)>;
   static std::unique_ptr<VrFlinger> Create(
-      Hwc2::Composer* hidl, RequestDisplayCallback request_display_callback);
+      Hwc2::Composer* hidl,
+      hwc2_display_t primary_display_id,
+      RequestDisplayCallback request_display_callback);
   ~VrFlinger();
 
   // These functions are all called on surface flinger's main thread.
@@ -35,6 +43,7 @@
  private:
   VrFlinger();
   bool Init(Hwc2::Composer* hidl,
+            hwc2_display_t primary_display_id,
             RequestDisplayCallback request_display_callback);
 
   // Needs to be a separate class for binder's ref counting
diff --git a/libs/vr/libvrflinger/vr_flinger.cpp b/libs/vr/libvrflinger/vr_flinger.cpp
index 85dc586..26aed4f 100644
--- a/libs/vr/libvrflinger/vr_flinger.cpp
+++ b/libs/vr/libvrflinger/vr_flinger.cpp
@@ -29,9 +29,10 @@
 namespace dvr {
 
 std::unique_ptr<VrFlinger> VrFlinger::Create(
-    Hwc2::Composer* hidl, RequestDisplayCallback request_display_callback) {
+    Hwc2::Composer* hidl, hwc2_display_t primary_display_id,
+    RequestDisplayCallback request_display_callback) {
   std::unique_ptr<VrFlinger> vr_flinger(new VrFlinger);
-  if (vr_flinger->Init(hidl, request_display_callback))
+  if (vr_flinger->Init(hidl, primary_display_id, request_display_callback))
     return vr_flinger;
   else
     return nullptr;
@@ -56,6 +57,7 @@
 }
 
 bool VrFlinger::Init(Hwc2::Composer* hidl,
+                     hwc2_display_t primary_display_id,
                      RequestDisplayCallback request_display_callback) {
   if (!hidl || !request_display_callback)
     return false;
@@ -74,8 +76,8 @@
   dispatcher_ = android::pdx::ServiceDispatcher::Create();
   CHECK_ERROR(!dispatcher_, error, "Failed to create service dispatcher.");
 
-  display_service_ =
-      android::dvr::DisplayService::Create(hidl, request_display_callback);
+  display_service_ = android::dvr::DisplayService::Create(
+      hidl, primary_display_id, request_display_callback);
   CHECK_ERROR(!display_service_, error, "Failed to create display service.");
   dispatcher_->AddService(display_service_);
 
@@ -91,7 +93,7 @@
       std::bind(&android::dvr::VSyncService::VSyncEvent,
                 std::static_pointer_cast<android::dvr::VSyncService>(service),
                 std::placeholders::_1, std::placeholders::_2,
-                std::placeholders::_3, std::placeholders::_4));
+                std::placeholders::_3));
 
   dispatcher_thread_ = std::thread([this]() {
     prctl(PR_SET_NAME, reinterpret_cast<unsigned long>("VrDispatch"), 0, 0, 0);
@@ -113,6 +115,7 @@
 }
 
 void VrFlinger::OnBootFinished() {
+  display_service_->OnBootFinished();
   sp<IVrManager> vr_manager = interface_cast<IVrManager>(
       defaultServiceManager()->checkService(String16("vrmanager")));
   if (vr_manager.get()) {
diff --git a/libs/vr/libvrflinger/vsync_service.cpp b/libs/vr/libvrflinger/vsync_service.cpp
index fdeb899..b8d8b08 100644
--- a/libs/vr/libvrflinger/vsync_service.cpp
+++ b/libs/vr/libvrflinger/vsync_service.cpp
@@ -32,21 +32,19 @@
 
 VSyncService::~VSyncService() {}
 
-void VSyncService::VSyncEvent(int display, int64_t timestamp_ns,
+void VSyncService::VSyncEvent(int64_t timestamp_ns,
                               int64_t compositor_time_ns,
                               uint32_t vsync_count) {
   ATRACE_NAME("VSyncService::VSyncEvent");
   std::lock_guard<std::mutex> autolock(mutex_);
 
-  if (display == HWC_DISPLAY_PRIMARY) {
-    last_vsync_ = current_vsync_;
-    current_vsync_ = timestamp_ns;
-    compositor_time_ns_ = compositor_time_ns;
-    current_vsync_count_ = vsync_count;
+  last_vsync_ = current_vsync_;
+  current_vsync_ = timestamp_ns;
+  compositor_time_ns_ = compositor_time_ns;
+  current_vsync_count_ = vsync_count;
 
-    NotifyWaiters();
-    UpdateClients();
-  }
+  NotifyWaiters();
+  UpdateClients();
 }
 
 std::shared_ptr<Channel> VSyncService::OnChannelOpen(pdx::Message& message) {
diff --git a/libs/vr/libvrflinger/vsync_service.h b/libs/vr/libvrflinger/vsync_service.h
index 215948e..822f02b 100644
--- a/libs/vr/libvrflinger/vsync_service.h
+++ b/libs/vr/libvrflinger/vsync_service.h
@@ -63,9 +63,10 @@
                       const std::shared_ptr<pdx::Channel>& channel) override;
 
   // Called by the hardware composer HAL, or similar, whenever a vsync event
-  // occurs. |compositor_time_ns| is the number of ns before the next vsync when
-  // the compositor will preempt the GPU to do EDS and lens warp.
-  void VSyncEvent(int display, int64_t timestamp_ns, int64_t compositor_time_ns,
+  // occurs on the primary display. |compositor_time_ns| is the number of ns
+  // before the next vsync when the compositor will preempt the GPU to do EDS
+  // and lens warp.
+  void VSyncEvent(int64_t timestamp_ns, int64_t compositor_time_ns,
                   uint32_t vsync_count);
 
  private:
diff --git a/libs/vr/libvrsensor/Android.bp b/libs/vr/libvrsensor/Android.bp
index e92178a..8542790 100644
--- a/libs/vr/libvrsensor/Android.bp
+++ b/libs/vr/libvrsensor/Android.bp
@@ -14,7 +14,6 @@
 
 sourceFiles = [
     "pose_client.cpp",
-    "sensor_client.cpp",
     "latency_model.cpp",
 ]
 
@@ -24,20 +23,20 @@
 
 staticLibraries = [
     "libdisplay",
-    "libbufferhub",
-    "libbufferhubqueue",
     "libdvrcommon",
     "libbroadcastring",
-    "libpdx_default_transport",
 ]
 
 sharedLibraries = [
     "libbase",
+    "libbinder",
+    "libbufferhubqueue",
     "libcutils",
     "libhardware",
     "liblog",
     "libutils",
     "libui",
+    "libpdx_default_transport",
 ]
 
 cc_library {
diff --git a/libs/vr/libvrsensor/include/private/dvr/sensor-ipc.h b/libs/vr/libvrsensor/include/private/dvr/sensor-ipc.h
deleted file mode 100644
index b2ebd95..0000000
--- a/libs/vr/libvrsensor/include/private/dvr/sensor-ipc.h
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef ANDROID_DVR_SENSOR_IPC_H_
-#define ANDROID_DVR_SENSOR_IPC_H_
-
-#define DVR_SENSOR_SERVICE_BASE "system/vr/sensors"
-
-#define DVR_SENSOR_SERVICE_CLIENT (DVR_SENSOR_SERVICE_BASE "/client")
-
-/*
- * Endpoint ops
- */
-enum {
-  DVR_SENSOR_START = 0,
-  DVR_SENSOR_STOP,
-  DVR_SENSOR_POLL,
-};
-
-#endif  // ANDROID_DVR_SENSOR_IPC_H_
diff --git a/libs/vr/libvrsensor/include/private/dvr/sensor_client.h b/libs/vr/libvrsensor/include/private/dvr/sensor_client.h
deleted file mode 100644
index 15a9b8f..0000000
--- a/libs/vr/libvrsensor/include/private/dvr/sensor_client.h
+++ /dev/null
@@ -1,37 +0,0 @@
-#ifndef ANDROID_DVR_SENSOR_CLIENT_H_
-#define ANDROID_DVR_SENSOR_CLIENT_H_
-
-#include <hardware/sensors.h>
-#include <pdx/client.h>
-#include <poll.h>
-
-namespace android {
-namespace dvr {
-
-// SensorClient is a remote interface to the sensor service in sensord.
-class SensorClient : public pdx::ClientBase<SensorClient> {
- public:
-  ~SensorClient();
-
-  int StartSensor();
-  int StopSensor();
-  int Poll(sensors_event_t* events, int max_count);
-
- private:
-  friend BASE;
-
-  // Set up a channel associated with the sensor of the indicated type.
-  // NOTE(segal): If our hardware ends up with multiple sensors of the same
-  // type, we'll have to change this.
-  explicit SensorClient(int sensor_type);
-
-  int sensor_type_;
-
-  SensorClient(const SensorClient&);
-  SensorClient& operator=(const SensorClient&);
-};
-
-}  // namespace dvr
-}  // namespace android
-
-#endif  // ANDROID_DVR_SENSOR_CLIENT_H_
diff --git a/libs/vr/libvrsensor/sensor_client.cpp b/libs/vr/libvrsensor/sensor_client.cpp
deleted file mode 100644
index 04e88cc..0000000
--- a/libs/vr/libvrsensor/sensor_client.cpp
+++ /dev/null
@@ -1,79 +0,0 @@
-#define LOG_TAG "SensorClient"
-#include <private/dvr/sensor_client.h>
-
-#include <log/log.h>
-#include <poll.h>
-
-#include <pdx/default_transport/client_channel_factory.h>
-#include <private/dvr/sensor-ipc.h>
-
-using android::pdx::Transaction;
-
-namespace android {
-namespace dvr {
-
-SensorClient::SensorClient(int sensor_type)
-    : BASE(pdx::default_transport::ClientChannelFactory::Create(
-          DVR_SENSOR_SERVICE_CLIENT)),
-      sensor_type_(sensor_type) {}
-
-SensorClient::~SensorClient() {}
-
-int SensorClient::StartSensor() {
-  Transaction trans{*this};
-  auto status = trans.Send<int>(DVR_SENSOR_START, &sensor_type_,
-                                sizeof(sensor_type_), nullptr, 0);
-  ALOGE_IF(!status, "startSensor() failed because: %s\n",
-           status.GetErrorMessage().c_str());
-  return ReturnStatusOrError(status);
-}
-
-int SensorClient::StopSensor() {
-  Transaction trans{*this};
-  auto status = trans.Send<int>(DVR_SENSOR_STOP);
-  ALOGE_IF(!status, "stopSensor() failed because: %s\n",
-           status.GetErrorMessage().c_str());
-  return ReturnStatusOrError(status);
-}
-
-int SensorClient::Poll(sensors_event_t* events, int max_events) {
-  int num_events = 0;
-  struct iovec rvec[] = {
-      {.iov_base = &num_events, .iov_len = sizeof(int)},
-      {.iov_base = events, .iov_len = max_events * sizeof(sensors_event_t)},
-  };
-  Transaction trans{*this};
-  auto status = trans.SendVector<int>(DVR_SENSOR_POLL, nullptr, rvec);
-  ALOGE_IF(!status, "Sensor poll() failed because: %s\n",
-           status.GetErrorMessage().c_str());
-  return !status ? -status.error() : num_events;
-}
-
-}  // namespace dvr
-}  // namespace android
-
-// Entrypoints to simplify using the library when programmatically dynamicly
-// loading it.
-// Allows us to call this library without linking it, as, for instance,
-// when compiling GVR in Google3.
-// NOTE(segal): It's kind of a hack.
-
-extern "C" uint64_t dvrStartSensor(int type) {
-  android::dvr::SensorClient* service =
-      android::dvr::SensorClient::Create(type).release();
-  service->StartSensor();
-  return (uint64_t)service;
-}
-
-extern "C" void dvrStopSensor(uint64_t service) {
-  android::dvr::SensorClient* iss =
-      reinterpret_cast<android::dvr::SensorClient*>(service);
-  iss->StopSensor();
-  delete iss;
-}
-
-extern "C" int dvrPollSensor(uint64_t service, int max_count,
-                             sensors_event_t* events) {
-  return reinterpret_cast<android::dvr::SensorClient*>(service)->Poll(
-      events, max_count);
-}