Merge changes Iaa0846b8,Id9420941

* changes:
  Remove extra isCurrent calls.
  Move image creation out of latchBuffer().
diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp
index 5acc09d..e185cbe 100644
--- a/cmds/dumpstate/Android.bp
+++ b/cmds/dumpstate/Android.bp
@@ -57,10 +57,21 @@
         export_aidl_headers: true,
     },
     srcs: [
-        "binder/android/os/IDumpstate.aidl",
+        "binder/android/os/DumpstateOptions.cpp",
+        ":dumpstate_aidl",
+    ],
+    export_include_dirs: ["binder"],
+}
+
+filegroup {
+    name: "dumpstate_aidl",
+    srcs: [
         "binder/android/os/IDumpstateListener.aidl",
         "binder/android/os/IDumpstateToken.aidl",
+        //"binder/android/os/DumpstateOptions.aidl",
+        "binder/android/os/IDumpstate.aidl",
     ],
+    path: "binder",
 }
 
 cc_defaults {
diff --git a/cmds/dumpstate/DumpstateService.cpp b/cmds/dumpstate/DumpstateService.cpp
index 49a78e7..260ea4b 100644
--- a/cmds/dumpstate/DumpstateService.cpp
+++ b/cmds/dumpstate/DumpstateService.cpp
@@ -77,6 +77,13 @@
     return binder::Status::ok();
 }
 
+binder::Status DumpstateService::startBugreport(int, const sp<IDumpstateListener>&,
+                                                const DumpstateOptions&, int32_t* returned_id) {
+    // TODO: fork to handle the bugreport request and return the process id or a request id here.
+    *returned_id = -1;
+    return binder::Status::ok();
+}
+
 status_t DumpstateService::dump(int fd, const Vector<String16>&) {
     dprintf(fd, "id: %d\n", ds_.id_);
     dprintf(fd, "pid: %d\n", ds_.pid_);
diff --git a/cmds/dumpstate/DumpstateService.h b/cmds/dumpstate/DumpstateService.h
index 7bca24a..131aff3 100644
--- a/cmds/dumpstate/DumpstateService.h
+++ b/cmds/dumpstate/DumpstateService.h
@@ -41,6 +41,9 @@
                                bool getSectionDetails,
                                sp<IDumpstateToken>* returned_token) override;
 
+    binder::Status startBugreport(int fd, const sp<IDumpstateListener>& listener,
+                                  const DumpstateOptions& options, int32_t* returned_id) override;
+
   private:
     Dumpstate& ds_;
     std::mutex lock_;
diff --git a/cmds/dumpstate/binder/android/os/DumpstateOptions.aidl b/cmds/dumpstate/binder/android/os/DumpstateOptions.aidl
new file mode 100644
index 0000000..c1a7f15
--- /dev/null
+++ b/cmds/dumpstate/binder/android/os/DumpstateOptions.aidl
@@ -0,0 +1,23 @@
+/**
+ * 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.
+ */
+
+package android.os;
+
+/**
+  * Specifies arguments for IDumpstate.
+  * {@hide}
+  */
+parcelable DumpstateOptions cpp_header "android/os/DumpstateOptions.h";
diff --git a/cmds/dumpstate/binder/android/os/DumpstateOptions.cpp b/cmds/dumpstate/binder/android/os/DumpstateOptions.cpp
new file mode 100644
index 0000000..5654190
--- /dev/null
+++ b/cmds/dumpstate/binder/android/os/DumpstateOptions.cpp
@@ -0,0 +1,46 @@
+/**
+ * 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 <android/os/DumpstateOptions.h>
+
+#include <binder/IBinder.h>
+#include <binder/Parcel.h>
+
+namespace android {
+namespace os {
+
+status_t DumpstateOptions::readFromParcel(const ::android::Parcel* parcel) {
+    if (status_t err = parcel->readBool(&get_section_details)) {
+        return err;
+    }
+    if (status_t err = parcel->readUtf8FromUtf16(&name)) {
+        return err;
+    }
+    return android::OK;
+}
+
+status_t DumpstateOptions::writeToParcel(::android::Parcel* parcel) const {
+    if (status_t err = parcel->writeBool(get_section_details)) {
+        return err;
+    }
+    if (status_t err = parcel->writeUtf8AsUtf16(name)) {
+        return err;
+    }
+    return android::OK;
+}
+
+}  // namespace os
+}  // namespace android
diff --git a/cmds/dumpstate/binder/android/os/DumpstateOptions.h b/cmds/dumpstate/binder/android/os/DumpstateOptions.h
new file mode 100644
index 0000000..a748e3c
--- /dev/null
+++ b/cmds/dumpstate/binder/android/os/DumpstateOptions.h
@@ -0,0 +1,39 @@
+/**
+ * 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_OS_DUMPSTATE_OPTIONS_H_
+#define ANDROID_OS_DUMPSTATE_OPTIONS_H_
+
+#include <binder/Parcelable.h>
+
+namespace android {
+namespace os {
+
+struct DumpstateOptions : public android::Parcelable {
+    // If true the caller can get callbacks with per-section progress details.
+    bool get_section_details = false;
+
+    // Name of the caller.
+    std::string name;
+
+    status_t writeToParcel(android::Parcel* parcel) const override;
+    status_t readFromParcel(const android::Parcel* parcel) override;
+};
+
+}  // namespace os
+}  // namespace android
+
+#endif  // ANDROID_OS_DUMPSTATE_OPTIONS_H_
diff --git a/cmds/dumpstate/binder/android/os/IDumpstate.aidl b/cmds/dumpstate/binder/android/os/IDumpstate.aidl
index 9b11b96..68a4f21 100644
--- a/cmds/dumpstate/binder/android/os/IDumpstate.aidl
+++ b/cmds/dumpstate/binder/android/os/IDumpstate.aidl
@@ -18,6 +18,7 @@
 
 import android.os.IDumpstateListener;
 import android.os.IDumpstateToken;
+import android.os.DumpstateOptions;
 
 /**
   * Binder interface for the currently running dumpstate process.
@@ -25,6 +26,8 @@
   */
 interface IDumpstate {
 
+
+    // TODO: remove method once startBugReport is used by Shell.
     /*
      * Sets the listener for this dumpstate progress.
      *
@@ -35,4 +38,11 @@
      */
     IDumpstateToken setListener(@utf8InCpp String name, IDumpstateListener listener,
                                 boolean getSectionDetails);
+
+    /*
+     * Starts a bugreport in a child process.
+     *
+     * Returns an identifier of the bugreport process running in the background.
+     */
+    int startBugreport(int fd, IDumpstateListener listener, in DumpstateOptions options);
 }
diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp
index 73098f8..28c7658 100644
--- a/cmds/installd/otapreopt.cpp
+++ b/cmds/installd/otapreopt.cpp
@@ -361,12 +361,11 @@
         }
 
         std::string preopted_boot_art_path = StringPrintf("/system/framework/%s/boot.art", isa);
-        if (access(preopted_boot_art_path.c_str(), F_OK) == 0) {
-          return PatchoatBootImage(isa_path, isa);
-        } else {
+        if (access(preopted_boot_art_path.c_str(), F_OK) != 0) {
           // No preopted boot image. Try to compile.
           return Dex2oatBootImage(boot_classpath_, art_path, oat_path, isa);
         }
+        return true;
     }
 
     static bool CreatePath(const std::string& path) {
@@ -431,29 +430,6 @@
         CHECK_EQ(0, closedir(c_dir)) << "Unable to close directory.";
     }
 
-    bool PatchoatBootImage(const std::string& output_dir, const char* isa) const {
-        // This needs to be kept in sync with ART, see art/runtime/gc/space/image_space.cc.
-
-        std::vector<std::string> cmd;
-        cmd.push_back("/system/bin/patchoat");
-
-        cmd.push_back("--input-image-location=/system/framework/boot.art");
-        cmd.push_back(StringPrintf("--output-image-directory=%s", output_dir.c_str()));
-
-        cmd.push_back(StringPrintf("--instruction-set=%s", isa));
-
-        int32_t base_offset = ChooseRelocationOffsetDelta(art::GetImageMinBaseAddressDelta(),
-                                                          art::GetImageMaxBaseAddressDelta());
-        cmd.push_back(StringPrintf("--base-offset-delta=%d", base_offset));
-
-        std::string error_msg;
-        bool result = Exec(cmd, &error_msg);
-        if (!result) {
-            LOG(ERROR) << "Could not generate boot image: " << error_msg;
-        }
-        return result;
-    }
-
     bool Dex2oatBootImage(const std::string& boot_cp,
                           const std::string& art_path,
                           const std::string& oat_path,
diff --git a/include/input/DisplayViewport.h b/include/input/DisplayViewport.h
index 0f336dd..0de3bb7 100644
--- a/include/input/DisplayViewport.h
+++ b/include/input/DisplayViewport.h
@@ -17,11 +17,37 @@
 #ifndef _LIBINPUT_DISPLAY_VIEWPORT_H
 #define _LIBINPUT_DISPLAY_VIEWPORT_H
 
+#include <android-base/stringprintf.h>
 #include <ui/DisplayInfo.h>
 #include <input/Input.h>
 
+using android::base::StringPrintf;
+
 namespace android {
 
+/**
+ * Describes the different type of viewports supported by input flinger.
+ * Keep in sync with values in InputManagerService.java.
+ */
+enum class ViewportType : int32_t {
+    VIEWPORT_INTERNAL = 1,
+    VIEWPORT_EXTERNAL = 2,
+    VIEWPORT_VIRTUAL = 3,
+};
+
+static const char* viewportTypeToString(ViewportType type) {
+    switch(type) {
+        case ViewportType::VIEWPORT_INTERNAL:
+            return "INTERNAL";
+        case ViewportType::VIEWPORT_EXTERNAL:
+            return "EXTERNAL";
+        case ViewportType::VIEWPORT_VIRTUAL:
+            return "VIRTUAL";
+        default:
+            return "UNKNOWN";
+    }
+}
+
 /*
  * Describes how coordinates are mapped on a physical display.
  * See com.android.server.display.DisplayViewport.
@@ -40,12 +66,13 @@
     int32_t deviceWidth;
     int32_t deviceHeight;
     std::string uniqueId;
+    ViewportType type;
 
     DisplayViewport() :
             displayId(ADISPLAY_ID_NONE), orientation(DISPLAY_ORIENTATION_0),
             logicalLeft(0), logicalTop(0), logicalRight(0), logicalBottom(0),
             physicalLeft(0), physicalTop(0), physicalRight(0), physicalBottom(0),
-            deviceWidth(0), deviceHeight(0), uniqueId() {
+            deviceWidth(0), deviceHeight(0), uniqueId(), type(ViewportType::VIEWPORT_INTERNAL) {
     }
 
     bool operator==(const DisplayViewport& other) const {
@@ -61,7 +88,8 @@
                 && physicalBottom == other.physicalBottom
                 && deviceWidth == other.deviceWidth
                 && deviceHeight == other.deviceHeight
-                && uniqueId == other.uniqueId;
+                && uniqueId == other.uniqueId
+                && type == other.type;
     }
 
     bool operator!=(const DisplayViewport& other) const {
@@ -86,17 +114,22 @@
         deviceWidth = width;
         deviceHeight = height;
         uniqueId.clear();
+        type = ViewportType::VIEWPORT_INTERNAL;
     }
-};
 
-/**
- * Describes the different type of viewports supported by input flinger.
- * Keep in sync with values in InputManagerService.java.
- */
-enum class ViewportType : int32_t {
-    VIEWPORT_INTERNAL = 1,
-    VIEWPORT_EXTERNAL = 2,
-    VIEWPORT_VIRTUAL = 3,
+    std::string toString() const {
+        return StringPrintf("Viewport %s: displayId=%d, orientation=%d, "
+            "logicalFrame=[%d, %d, %d, %d], "
+            "physicalFrame=[%d, %d, %d, %d], "
+            "deviceSize=[%d, %d]",
+            viewportTypeToString(type),
+            displayId, orientation,
+            logicalLeft, logicalTop,
+            logicalRight, logicalBottom,
+            physicalLeft, physicalTop,
+            physicalRight, physicalBottom,
+            deviceWidth, deviceHeight);
+    }
 };
 
 } // namespace android
diff --git a/services/inputflinger/InputApplication.h b/include/input/InputApplication.h
similarity index 100%
rename from services/inputflinger/InputApplication.h
rename to include/input/InputApplication.h
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index 5fd86b4..4782c9b 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -37,6 +37,7 @@
 #include <utils/BitSet.h>
 
 namespace android {
+class Parcel;
 
 /*
  * Intermediate representation used to send input events and related signals.
@@ -143,6 +144,7 @@
     virtual ~InputChannel();
 
 public:
+    InputChannel() = default;
     InputChannel(const std::string& name, int fd);
 
     /* Creates a pair of input channels.
@@ -183,9 +185,14 @@
     /* Returns a new object that has a duplicate of this channel's fd. */
     sp<InputChannel> dup() const;
 
+    status_t write(Parcel& out) const;
+    status_t read(const Parcel& from);
+
 private:
+    void setFd(int fd);
+
     std::string mName;
-    int mFd;
+    int mFd = -1;
 };
 
 /*
diff --git a/services/inputflinger/InputWindow.h b/include/input/InputWindow.h
similarity index 97%
rename from services/inputflinger/InputWindow.h
rename to include/input/InputWindow.h
index c481853..7c284dd 100644
--- a/services/inputflinger/InputWindow.h
+++ b/include/input/InputWindow.h
@@ -27,7 +27,7 @@
 #include "InputApplication.h"
 
 namespace android {
-
+class Parcel;
 
 /*
  * Describes the properties of a window that can receive input.
@@ -151,6 +151,9 @@
     bool supportsSplitTouch() const;
 
     bool overlaps(const InputWindowInfo* other) const;
+
+    status_t write(Parcel& output) const;
+    static InputWindowInfo read(const Parcel& from);
 };
 
 
@@ -168,9 +171,7 @@
         return mInfo;
     }
 
-    inline sp<InputChannel> getInputChannel() const {
-        return mInfo ? mInfo->inputChannel : nullptr;
-    }
+    sp<InputChannel> getInputChannel() const;
 
     inline std::string getName() const {
         return mInfo ? mInfo->name : "<invalid>";
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index b2a304a..aedf6b0 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -120,6 +120,7 @@
         "liblog",
         "libcutils",
         "libutils",
+        "libbinderthreadstate",
     ],
 
     header_libs: [
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index b2217b5..f052bcb 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -17,6 +17,7 @@
 #define LOG_TAG "IPCThreadState"
 
 #include <binder/IPCThreadState.h>
+#include <binderthreadstate/IPCThreadStateBase.h>
 
 #include <binder/Binder.h>
 #include <binder/BpBinder.h>
@@ -742,6 +743,7 @@
     clearCaller();
     mIn.setDataCapacity(256);
     mOut.setDataCapacity(256);
+    mIPCThreadStateBase = IPCThreadStateBase::self();
 }
 
 IPCThreadState::~IPCThreadState()
@@ -1082,6 +1084,9 @@
                 "Not enough command data for brTRANSACTION");
             if (result != NO_ERROR) break;
 
+            //Record the fact that we're in a binder call.
+            mIPCThreadStateBase->pushCurrentState(
+                IPCThreadStateBase::CallState::BINDER);
             Parcel buffer;
             buffer.ipcSetDataReference(
                 reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
@@ -1129,6 +1134,7 @@
                 error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);
             }
 
+            mIPCThreadStateBase->popCurrentState();
             //ALOGI("<<<< TRANSACT from pid %d restore pid %d uid %d\n",
             //     mCallingPid, origPid, origUid);
 
@@ -1192,6 +1198,10 @@
     return result;
 }
 
+bool IPCThreadState::isServingCall() const {
+    return mIPCThreadStateBase->getCurrentBinderCallState() == IPCThreadStateBase::CallState::BINDER;
+}
+
 void IPCThreadState::threadDestructor(void *st)
 {
         IPCThreadState* const self = static_cast<IPCThreadState*>(st);
diff --git a/libs/binder/Status.cpp b/libs/binder/Status.cpp
index e318a7f..a3f8755 100644
--- a/libs/binder/Status.cpp
+++ b/libs/binder/Status.cpp
@@ -24,11 +24,17 @@
 }
 
 Status Status::fromExceptionCode(int32_t exceptionCode) {
+    if (exceptionCode == EX_TRANSACTION_FAILED) {
+        return Status(exceptionCode, FAILED_TRANSACTION);
+    }
     return Status(exceptionCode, OK);
 }
 
 Status Status::fromExceptionCode(int32_t exceptionCode,
                                  const String8& message) {
+    if (exceptionCode == EX_TRANSACTION_FAILED) {
+        return Status(exceptionCode, FAILED_TRANSACTION, message);
+    }
     return Status(exceptionCode, OK, message);
 }
 
@@ -136,7 +142,7 @@
     // Something really bad has happened, and we're not going to even
     // try returning rich error data.
     if (mException == EX_TRANSACTION_FAILED) {
-        return mErrorCode == OK ? FAILED_TRANSACTION : mErrorCode;
+        return mErrorCode;
     }
 
     status_t status = parcel->writeInt32(mException);
@@ -158,7 +164,7 @@
 
 void Status::setException(int32_t ex, const String8& message) {
     mException = ex;
-    mErrorCode = NO_ERROR;  // an exception, not a transaction failure.
+    mErrorCode = ex == EX_TRANSACTION_FAILED ? FAILED_TRANSACTION : NO_ERROR;
     mMessage.setTo(message);
 }
 
diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h
index dce3f38..40b51ad 100644
--- a/libs/binder/include/binder/IPCThreadState.h
+++ b/libs/binder/include/binder/IPCThreadState.h
@@ -29,6 +29,8 @@
 // ---------------------------------------------------------------------------
 namespace android {
 
+class IPCThreadStateBase;
+
 class IPCThreadState
 {
 public:
@@ -89,6 +91,33 @@
             // the maximum number of binder threads threads allowed for this process.
             void                blockUntilThreadAvailable();
 
+
+            // Is this thread currently serving a binder call. This method
+            // returns true if while traversing backwards from the function call
+            // stack for this thread, we encounter a function serving a binder
+            // call before encountering a hwbinder call / hitting the end of the
+            // call stack.
+            // Eg: If thread T1 went through the following call pattern
+            //     1) T1 receives and executes hwbinder call H1.
+            //     2) While handling H1, T1 makes binder call B1.
+            //     3) The handler of B1, calls into T1 with a callback B2.
+            // If isServingCall() is called during H1 before 3), this method
+            // will return false, else true.
+            //
+            //  ----
+            // | B2 | ---> While callback B2 is being handled, during 3).
+            //  ----
+            // | H1 | ---> While H1 is being handled.
+            //  ----
+            // Fig: Thread Call stack while handling B2
+            //
+            // This is since after 3), while traversing the thread call stack,
+            // we hit a binder call before a hwbinder call / end of stack. This
+            // method may be typically used to determine whether to use
+            // hardware::IPCThreadState methods or IPCThreadState methods to
+            // infer information about thread state.
+            bool                isServingCall() const;
+
 private:
                                 IPCThreadState();
                                 ~IPCThreadState();
@@ -128,6 +157,7 @@
             uid_t               mCallingUid;
             int32_t             mStrictModePolicy;
             int32_t             mLastTransactionBinderFlags;
+            IPCThreadStateBase  *mIPCThreadStateBase;
 };
 
 }; // namespace android
diff --git a/libs/binder/include/binder/ParcelFileDescriptor.h b/libs/binder/include/binder/ParcelFileDescriptor.h
index 455462b..ad950af 100644
--- a/libs/binder/include/binder/ParcelFileDescriptor.h
+++ b/libs/binder/include/binder/ParcelFileDescriptor.h
@@ -31,6 +31,7 @@
 public:
     ParcelFileDescriptor();
     explicit ParcelFileDescriptor(android::base::unique_fd fd);
+    explicit ParcelFileDescriptor(ParcelFileDescriptor&& other) : mFd(std::move(other.mFd)) { }
     ~ParcelFileDescriptor() override;
 
     int get() const { return mFd.get(); }
diff --git a/libs/binder/ndk/include_ndk/android/binder_auto_utils.h b/libs/binder/ndk/include_ndk/android/binder_auto_utils.h
new file mode 100644
index 0000000..cc0a29d
--- /dev/null
+++ b/libs/binder/ndk/include_ndk/android/binder_auto_utils.h
@@ -0,0 +1,241 @@
+/*
+ * 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.
+ */
+
+/**
+ * @addtogroup NdkBinder
+ * @{
+ */
+
+/**
+ * @file binder_auto_utils.h
+ * @brief These objects provide a more C++-like thin interface to the .
+ */
+
+#pragma once
+
+#include <android/binder_ibinder.h>
+#include <android/binder_parcel.h>
+#include <android/binder_status.h>
+
+#include <assert.h>
+
+#ifdef __cplusplus
+
+#include <cstddef>
+
+namespace ndk {
+
+/**
+ * Represents one strong pointer to an AIBinder object.
+ */
+class SpAIBinder {
+public:
+    /**
+     * Takes ownership of one strong refcount of binder.
+     */
+    explicit SpAIBinder(AIBinder* binder = nullptr) : mBinder(binder) {}
+
+    /**
+     * Convenience operator for implicitly constructing an SpAIBinder from nullptr. This is not
+     * explicit because it is not taking ownership of anything.
+     */
+    SpAIBinder(std::nullptr_t) : SpAIBinder() {}
+
+    /**
+     * This will delete the underlying object if it exists. See operator=.
+     */
+    SpAIBinder(const SpAIBinder& other) { *this = other; }
+
+    /**
+     * This deletes the underlying object if it exists. See set.
+     */
+    ~SpAIBinder() { set(nullptr); }
+
+    /**
+     * This takes ownership of a binder from another AIBinder object but it does not affect the
+     * ownership of that other object.
+     */
+    SpAIBinder& operator=(const SpAIBinder& other) {
+        AIBinder_incStrong(other.mBinder);
+        set(other.mBinder);
+        return *this;
+    }
+
+    /**
+     * Takes ownership of one strong refcount of binder
+     */
+    void set(AIBinder* binder) {
+        AIBinder* old = *const_cast<AIBinder* volatile*>(&mBinder);
+        if (old != nullptr) AIBinder_decStrong(old);
+        if (old != *const_cast<AIBinder* volatile*>(&mBinder)) {
+            __assert(__FILE__, __LINE__, "Race detected.");
+        }
+        mBinder = binder;
+    }
+
+    /**
+     * This returns the underlying binder object for transactions. If it is used to create another
+     * SpAIBinder object, it should first be incremented.
+     */
+    AIBinder* get() const { return mBinder; }
+
+    /**
+     * This allows the value in this class to be set from beneath it. If you call this method and
+     * then change the value of T*, you must take ownership of the value you are replacing and add
+     * ownership to the object that is put in here.
+     *
+     * Recommended use is like this:
+     *   SpAIBinder a;  // will be nullptr
+     *   SomeInitFunction(a.getR());  // value is initialized with refcount
+     *
+     * Other usecases are discouraged.
+     *
+     */
+    AIBinder** getR() { return &mBinder; }
+
+private:
+    AIBinder* mBinder = nullptr;
+};
+
+/**
+ * This baseclass owns a single object, used to make various classes RAII.
+ */
+template <typename T, void (*Destroy)(T*)>
+class ScopedAResource {
+public:
+    /**
+     * Takes ownership of t.
+     */
+    explicit ScopedAResource(T* t = nullptr) : mT(t) {}
+
+    /**
+     * This deletes the underlying object if it exists. See set.
+     */
+    ~ScopedAResource() { set(nullptr); }
+
+    /**
+     * Takes ownership of t.
+     */
+    void set(T* t) {
+        Destroy(mT);
+        mT = t;
+    }
+
+    /**
+     * This returns the underlying object to be modified but does not affect ownership.
+     */
+    T* get() { return mT; }
+
+    /**
+     * This returns the const underlying object but does not affect ownership.
+     */
+    const T* get() const { return mT; }
+
+    /**
+     * This allows the value in this class to be set from beneath it. If you call this method and
+     * then change the value of T*, you must take ownership of the value you are replacing and add
+     * ownership to the object that is put in here.
+     *
+     * Recommended use is like this:
+     *   ScopedAResource<T> a; // will be nullptr
+     *   SomeInitFunction(a.getR()); // value is initialized with refcount
+     *
+     * Other usecases are discouraged.
+     *
+     */
+    T** getR() { return &mT; }
+
+    // copy-constructing, or move/copy assignment is disallowed
+    ScopedAResource(const ScopedAResource&) = delete;
+    ScopedAResource& operator=(const ScopedAResource&) = delete;
+    ScopedAResource& operator=(ScopedAResource&&) = delete;
+
+    // move-constructing is okay
+    ScopedAResource(ScopedAResource&&) = default;
+
+private:
+    T* mT;
+};
+
+/**
+ * Convenience wrapper. See AParcel.
+ */
+class ScopedAParcel : public ScopedAResource<AParcel, AParcel_delete> {
+public:
+    /**
+     * Takes ownership of a.
+     */
+    explicit ScopedAParcel(AParcel* a = nullptr) : ScopedAResource(a) {}
+    ~ScopedAParcel() {}
+    ScopedAParcel(ScopedAParcel&&) = default;
+};
+
+/**
+ * Convenience wrapper. See AStatus.
+ */
+class ScopedAStatus : public ScopedAResource<AStatus, AStatus_delete> {
+public:
+    /**
+     * Takes ownership of a.
+     */
+    explicit ScopedAStatus(AStatus* a = nullptr) : ScopedAResource(a) {}
+    ~ScopedAStatus() {}
+    ScopedAStatus(ScopedAStatus&&) = default;
+
+    /**
+     * See AStatus_isOk.
+     */
+    bool isOk() { return get() != nullptr && AStatus_isOk(get()); }
+};
+
+/**
+ * Convenience wrapper. See AIBinder_DeathRecipient.
+ */
+class ScopedAIBinder_DeathRecipient
+      : public ScopedAResource<AIBinder_DeathRecipient, AIBinder_DeathRecipient_delete> {
+public:
+    /**
+     * Takes ownership of a.
+     */
+    explicit ScopedAIBinder_DeathRecipient(AIBinder_DeathRecipient* a = nullptr)
+          : ScopedAResource(a) {}
+    ~ScopedAIBinder_DeathRecipient() {}
+    ScopedAIBinder_DeathRecipient(ScopedAIBinder_DeathRecipient&&) = default;
+};
+
+/**
+ * Convenience wrapper. See AIBinder_Weak.
+ */
+class ScopedAIBinder_Weak : public ScopedAResource<AIBinder_Weak, AIBinder_Weak_delete> {
+public:
+    /**
+     * Takes ownership of a.
+     */
+    explicit ScopedAIBinder_Weak(AIBinder_Weak* a = nullptr) : ScopedAResource(a) {}
+    ~ScopedAIBinder_Weak() {}
+    ScopedAIBinder_Weak(ScopedAIBinder_Weak&&) = default;
+
+    /**
+     * See AIBinder_Weak_promote.
+     */
+    SpAIBinder promote() { return SpAIBinder(AIBinder_Weak_promote(get())); }
+};
+
+} // namespace ndk
+
+#endif // __cplusplus
+
+/** @} */
diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder.h b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
index f237e69..c222c16 100644
--- a/libs/binder/ndk/include_ndk/android/binder_ibinder.h
+++ b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
@@ -207,6 +207,8 @@
  * null. The exact cookie must also be used to unlink this transaction (see AIBinder_linkToDeath).
  * This function may return a binder transaction failure. The cookie can be used both for
  * identification and holding user data.
+ *
+ * If binder is local, this will return STATUS_INVALID_OPERATION.
  */
 binder_status_t AIBinder_linkToDeath(AIBinder* binder, AIBinder_DeathRecipient* recipient,
                                      void* cookie) __INTRODUCED_IN(29);
diff --git a/libs/binder/ndk/include_ndk/android/binder_interface_utils.h b/libs/binder/ndk/include_ndk/android/binder_interface_utils.h
new file mode 100644
index 0000000..1a9018a
--- /dev/null
+++ b/libs/binder/ndk/include_ndk/android/binder_interface_utils.h
@@ -0,0 +1,178 @@
+/*
+ * 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.
+ */
+
+/**
+ * @addtogroup NdkBinder
+ * @{
+ */
+
+/**
+ * @file binder_interface_utils.h
+ * @brief This provides common C++ classes for common operations and as base classes for C++
+ * interfaces.
+ */
+
+#pragma once
+
+#include <android/binder_auto_utils.h>
+#include <android/binder_ibinder.h>
+
+#include <assert.h>
+
+#ifdef __cplusplus
+
+#include <memory>
+#include <mutex>
+
+namespace ndk {
+
+/**
+ * analog using std::shared_ptr for internally held refcount
+ *
+ * ref must be called at least one time during the lifetime of this object. The recommended way to construct
+ * this object is with SharedRefBase::make.
+ */
+class SharedRefBase {
+public:
+    SharedRefBase() {}
+    virtual ~SharedRefBase() {
+        std::call_once(mFlagThis, [&]() {
+            __assert(__FILE__, __LINE__, "SharedRefBase: no ref created during lifetime");
+        });
+    }
+
+    /**
+     * A shared_ptr must be held to this object when this is called. This must be called once during
+     * the lifetime of this object.
+     */
+    std::shared_ptr<SharedRefBase> ref() {
+        std::shared_ptr<SharedRefBase> thiz = mThis.lock();
+
+        std::call_once(mFlagThis, [&]() { mThis = thiz = std::shared_ptr<SharedRefBase>(this); });
+
+        return thiz;
+    }
+
+    /**
+     * Convenience method for a ref (see above) which automatically casts to the desired child type.
+     */
+    template <typename CHILD>
+    std::shared_ptr<CHILD> ref() {
+        return std::static_pointer_cast<CHILD>(ref());
+    }
+
+    /**
+     * Convenience method for making an object directly with a reference.
+     */
+    template<class T, class... Args>
+    static std::shared_ptr<T> make(Args&&... args) {
+        T* t = new T(std::forward<Args>(args)...);
+        return t->template ref<T>();
+    }
+
+private:
+    std::once_flag mFlagThis;
+    std::weak_ptr<SharedRefBase> mThis;
+};
+
+/**
+ * wrapper analog to IInterface
+ */
+class ICInterface : public SharedRefBase {
+public:
+    ICInterface() {}
+    virtual ~ICInterface() {}
+
+    /**
+     * This either returns the single existing implementation or creates a new implementation.
+     */
+    virtual SpAIBinder asBinder() = 0;
+
+    /**
+     * Returns whether this interface is in a remote process. If it cannot be determined locally,
+     * this will be checked using AIBinder_isRemote.
+     */
+    virtual bool isRemote() = 0;
+};
+
+/**
+ * implementation of IInterface for server (n = native)
+ */
+template <typename INTERFACE>
+class BnCInterface : public INTERFACE {
+public:
+    BnCInterface() {}
+    virtual ~BnCInterface() {}
+
+    SpAIBinder asBinder() override;
+
+    bool isRemote() override { return true; }
+
+protected:
+    /**
+     * This function should only be called by asBinder. Otherwise, there is a possibility of
+     * multiple AIBinder* objects being created for the same instance of an object.
+     */
+    virtual SpAIBinder createBinder() = 0;
+
+private:
+    std::mutex mMutex; // for asBinder
+    ScopedAIBinder_Weak mWeakBinder;
+};
+
+/**
+ * implementation of IInterface for client (p = proxy)
+ */
+template <typename INTERFACE>
+class BpCInterface : public INTERFACE {
+public:
+    BpCInterface(const SpAIBinder& binder) : mBinder(binder) {}
+    virtual ~BpCInterface() {}
+
+    SpAIBinder asBinder() override;
+
+    bool isRemote() override { return AIBinder_isRemote(mBinder.get()); }
+
+private:
+    SpAIBinder mBinder;
+};
+
+template <typename INTERFACE>
+SpAIBinder BnCInterface<INTERFACE>::asBinder() {
+    std::lock_guard<std::mutex> l(mMutex);
+
+    SpAIBinder binder;
+    if (mWeakBinder.get() != nullptr) {
+        binder.set(AIBinder_Weak_promote(mWeakBinder.get()));
+    }
+    if (binder.get() == nullptr) {
+        binder = createBinder();
+        mWeakBinder.set(AIBinder_Weak_new(binder.get()));
+    }
+
+    return binder;
+}
+
+template <typename INTERFACE>
+SpAIBinder BpCInterface<INTERFACE>::asBinder() {
+    return mBinder;
+}
+
+} // namespace ndk
+
+#endif // __cplusplus
+
+/** @} */
diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel.h b/libs/binder/ndk/include_ndk/android/binder_parcel.h
index a3800da..0e97b50 100644
--- a/libs/binder/ndk/include_ndk/android/binder_parcel.h
+++ b/libs/binder/ndk/include_ndk/android/binder_parcel.h
@@ -88,6 +88,43 @@
 binder_status_t AParcel_readStatusHeader(const AParcel* parcel, AStatus** status)
         __INTRODUCED_IN(29);
 
+/**
+ * Writes string value to the next location in a non-null parcel.
+ */
+binder_status_t AParcel_writeString(AParcel* parcel, const char* string, size_t length)
+        __INTRODUCED_IN(29);
+
+/**
+ * This is called to allocate a buffer
+ *
+ * The length here includes the space required to insert a '\0' for a properly formed c-str. If the
+ * buffer returned from this function is retStr, it will be filled by AParcel_readString with the
+ * data from the remote process, and it will be filled such that retStr[length] == '\0'.
+ *
+ * If allocation fails, null should be returned.
+ */
+typedef void* (*AParcel_string_reallocator)(void* stringData, size_t length);
+
+/**
+ * This is called to get the buffer from a stringData object.
+ */
+typedef char* (*AParcel_string_getter)(void* stringData);
+
+/**
+ * Reads and allocates string value from the next location in a non-null parcel.
+ *
+ * Data is passed to the string allocator once the string size is known. This data should be used to
+ * point to some kind of string data. For instance, it could be a char*, and the string allocator
+ * could be realloc. Then the getter would simply be a cast to char*. In more complicated cases,
+ * stringData could be a structure containing additional string data.
+ *
+ * If this function returns a success, the buffer returned by allocator when passed stringData will
+ * contain a null-terminated c-str read from the binder.
+ */
+binder_status_t AParcel_readString(const AParcel* parcel, AParcel_string_reallocator reallocator,
+                                   AParcel_string_getter getter, void** stringData)
+        __INTRODUCED_IN(29);
+
 // @START
 /**
  * Writes int32_t value to the next location in a non-null parcel.
diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h b/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h
new file mode 100644
index 0000000..d3e6cae
--- /dev/null
+++ b/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ */
+
+/**
+ * @addtogroup NdkBinder
+ * @{
+ */
+
+/**
+ * @file binder_parcel_utils.h
+ * @brief A collection of helper wrappers for AParcel.
+ */
+
+#pragma once
+
+#include <android/binder_parcel.h>
+
+#ifdef __cplusplus
+
+#include <string>
+
+namespace ndk {
+
+/**
+ * Takes a std::string and reallocates it to the specified length. For use with AParcel_readString.
+ * See use below in AParcel_readString.
+ */
+static inline void* AParcel_std_string_reallocator(void* stringData, size_t length) {
+    std::string* str = static_cast<std::string*>(stringData);
+    str->resize(length - 1);
+    return stringData;
+}
+
+/**
+ * Takes a std::string and returns the inner char*.
+ */
+static inline char* AParcel_std_string_getter(void* stringData) {
+    std::string* str = static_cast<std::string*>(stringData);
+    return &(*str)[0];
+}
+
+/**
+ * Convenience API for writing a std::string.
+ */
+static inline binder_status_t AParcel_writeString(AParcel* parcel, const std::string& str) {
+    return AParcel_writeString(parcel, str.c_str(), str.size());
+}
+
+/**
+ * Convenience API for reading a std::string.
+ */
+static inline binder_status_t AParcel_readString(const AParcel* parcel, std::string* str) {
+    void* stringData = static_cast<void*>(str);
+    return AParcel_readString(parcel, AParcel_std_string_reallocator, AParcel_std_string_getter,
+                              &stringData);
+}
+
+} // namespace ndk
+
+#endif // __cplusplus
+
+/** @} */
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index 4f486c9..2a1bff1 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -32,6 +32,7 @@
     AParcel_readInt64;
     AParcel_readNullableStrongBinder;
     AParcel_readStatusHeader;
+    AParcel_readString;
     AParcel_readStrongBinder;
     AParcel_readUint32;
     AParcel_readUint64;
@@ -43,6 +44,7 @@
     AParcel_writeInt32;
     AParcel_writeInt64;
     AParcel_writeStatusHeader;
+    AParcel_writeString;
     AParcel_writeStrongBinder;
     AParcel_writeUint32;
     AParcel_writeUint64;
diff --git a/libs/binder/ndk/parcel.cpp b/libs/binder/ndk/parcel.cpp
index 385e898..3e03e90 100644
--- a/libs/binder/ndk/parcel.cpp
+++ b/libs/binder/ndk/parcel.cpp
@@ -20,7 +20,11 @@
 #include "ibinder_internal.h"
 #include "status_internal.h"
 
+#include <limits>
+
+#include <android-base/logging.h>
 #include <binder/Parcel.h>
+#include <utils/Unicode.h>
 
 using ::android::IBinder;
 using ::android::Parcel;
@@ -69,6 +73,67 @@
     return ret;
 }
 
+binder_status_t AParcel_writeString(AParcel* parcel, const char* string, size_t length) {
+    const uint8_t* str8 = (uint8_t*)string;
+
+    const ssize_t len16 = utf8_to_utf16_length(str8, length);
+
+    if (len16 < 0 || len16 >= std::numeric_limits<int32_t>::max()) {
+        LOG(WARNING) << __func__ << ": Invalid string length: " << len16;
+        return STATUS_BAD_VALUE;
+    }
+
+    status_t err = parcel->get()->writeInt32(len16);
+    if (err) {
+        return PruneStatusT(err);
+    }
+
+    void* str16 = parcel->get()->writeInplace((len16 + 1) * sizeof(char16_t));
+    if (str16 == nullptr) {
+        return STATUS_NO_MEMORY;
+    }
+
+    utf8_to_utf16(str8, length, (char16_t*)str16, (size_t)len16 + 1);
+
+    return STATUS_OK;
+}
+
+binder_status_t AParcel_readString(const AParcel* parcel, AParcel_string_reallocator reallocator,
+                                   AParcel_string_getter getter, void** stringData) {
+    size_t len16;
+    const char16_t* str16 = parcel->get()->readString16Inplace(&len16);
+
+    if (str16 == nullptr) {
+        LOG(WARNING) << __func__ << ": Failed to read string in place.";
+        return STATUS_UNEXPECTED_NULL;
+    }
+
+    ssize_t len8;
+
+    if (len16 == 0) {
+        len8 = 1;
+    } else {
+        len8 = utf16_to_utf8_length(str16, len16) + 1;
+    }
+
+    if (len8 <= 0 || len8 >= std::numeric_limits<int32_t>::max()) {
+        LOG(WARNING) << __func__ << ": Invalid string length: " << len8;
+        return STATUS_BAD_VALUE;
+    }
+
+    *stringData = reallocator(*stringData, len8);
+    char* str8 = getter(*stringData);
+
+    if (str8 == nullptr) {
+        LOG(WARNING) << __func__ << ": AParcel_string_allocator failed to allocate.";
+        return STATUS_NO_MEMORY;
+    }
+
+    utf16_to_utf8(str16, len16, str8, len8);
+
+    return STATUS_OK;
+}
+
 // See gen_parcel_helper.py. These auto-generated read/write methods use the same types for
 // libbinder and this library.
 // @START
diff --git a/libs/binder/ndk/status.cpp b/libs/binder/ndk/status.cpp
index e0ae469..1f75b0b 100644
--- a/libs/binder/ndk/status.cpp
+++ b/libs/binder/ndk/status.cpp
@@ -27,11 +27,11 @@
 }
 
 AStatus* AStatus_fromExceptionCode(binder_exception_t exception) {
-    return new AStatus(Status::fromExceptionCode(exception));
+    return new AStatus(Status::fromExceptionCode(PruneException(exception)));
 }
 
 AStatus* AStatus_fromExceptionCodeWithMessage(binder_exception_t exception, const char* message) {
-    return new AStatus(Status::fromExceptionCode(exception, message));
+    return new AStatus(Status::fromExceptionCode(PruneException(exception), message));
 }
 
 AStatus* AStatus_fromServiceSpecificError(int32_t serviceSpecific) {
@@ -43,7 +43,7 @@
 }
 
 AStatus* AStatus_fromStatus(binder_status_t status) {
-    return new AStatus(Status::fromStatusT(status));
+    return new AStatus(Status::fromStatusT(PruneStatusT(status)));
 }
 
 bool AStatus_isOk(const AStatus* status) {
diff --git a/libs/binder/ndk/test/main_client.cpp b/libs/binder/ndk/test/main_client.cpp
index 3fc096a..22bf1e5 100644
--- a/libs/binder/ndk/test/main_client.cpp
+++ b/libs/binder/ndk/test/main_client.cpp
@@ -131,3 +131,6 @@
     EXPECT_EQ(STATUS_OK, foo->addService(kInstanceName2));
     EXPECT_EQ(IFoo::getService(kInstanceName1), IFoo::getService(kInstanceName2));
 }
+
+#include <android/binder_auto_utils.h>
+#include <android/binder_interface_utils.h>
diff --git a/libs/binderthreadstate/Android.bp b/libs/binderthreadstate/Android.bp
new file mode 100644
index 0000000..7106cbb
--- /dev/null
+++ b/libs/binderthreadstate/Android.bp
@@ -0,0 +1,44 @@
+// 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: "libbinderthreadstate",
+    recovery_available: true,
+    vendor_available: false,
+    vndk: {
+        enabled: true,
+        support_system_process: true,
+    },
+    srcs: [
+        "IPCThreadStateBase.cpp",
+    ],
+
+    shared_libs: [
+        "libbase",
+        "liblog",
+        "libcutils",
+        "libutils",
+    ],
+
+    export_include_dirs: ["include"],
+
+    sanitize: {
+        misc_undefined: ["integer"],
+    },
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+}
diff --git a/libs/binderthreadstate/IPCThreadStateBase.cpp b/libs/binderthreadstate/IPCThreadStateBase.cpp
new file mode 100644
index 0000000..fede151
--- /dev/null
+++ b/libs/binderthreadstate/IPCThreadStateBase.cpp
@@ -0,0 +1,89 @@
+/*
+ * 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 "IPCThreadStateBase"
+
+#include <binderthreadstate/IPCThreadStateBase.h>
+#include <android-base/macros.h>
+
+#include <utils/Log.h>
+
+#include <errno.h>
+#include <inttypes.h>
+#include <pthread.h>
+
+namespace android {
+
+static pthread_mutex_t gTLSMutex = PTHREAD_MUTEX_INITIALIZER;
+static bool gHaveTLS = false;
+static pthread_key_t gTLS = 0;
+
+IPCThreadStateBase::IPCThreadStateBase() {
+    pthread_setspecific(gTLS, this);
+}
+
+IPCThreadStateBase* IPCThreadStateBase::self()
+{
+    if (gHaveTLS) {
+restart:
+        const pthread_key_t k = gTLS;
+        IPCThreadStateBase* st = (IPCThreadStateBase*)pthread_getspecific(k);
+        if (st) return st;
+        return new IPCThreadStateBase;
+    }
+
+    pthread_mutex_lock(&gTLSMutex);
+    if (!gHaveTLS) {
+        int key_create_value = pthread_key_create(&gTLS, threadDestructor);
+        if (key_create_value != 0) {
+            pthread_mutex_unlock(&gTLSMutex);
+            ALOGW("IPCThreadStateBase::self() unable to create TLS key, expect a crash: %s\n",
+                    strerror(key_create_value));
+            return nullptr;
+        }
+        gHaveTLS = true;
+    }
+    pthread_mutex_unlock(&gTLSMutex);
+    goto restart;
+}
+
+void IPCThreadStateBase::pushCurrentState(CallState callState) {
+    mCallStateStack.emplace(callState);
+}
+
+IPCThreadStateBase::CallState IPCThreadStateBase::popCurrentState() {
+    ALOG_ASSERT(mCallStateStack.size > 0);
+    CallState val = mCallStateStack.top();
+    mCallStateStack.pop();
+    return val;
+}
+
+IPCThreadStateBase::CallState IPCThreadStateBase::getCurrentBinderCallState() {
+    if (mCallStateStack.size() > 0) {
+        return mCallStateStack.top();
+    }
+    return CallState::NONE;
+}
+
+void IPCThreadStateBase::threadDestructor(void *st)
+{
+    IPCThreadStateBase* const self = static_cast<IPCThreadStateBase*>(st);
+    if (self) {
+        delete self;
+    }
+}
+
+}; // namespace android
diff --git a/libs/binderthreadstate/include/binderthreadstate/IPCThreadStateBase.h b/libs/binderthreadstate/include/binderthreadstate/IPCThreadStateBase.h
new file mode 100644
index 0000000..6fdcc84
--- /dev/null
+++ b/libs/binderthreadstate/include/binderthreadstate/IPCThreadStateBase.h
@@ -0,0 +1,44 @@
+/*
+ * 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 BINDER_THREADSTATE_IPC_THREADSTATE_BASE_H
+#define BINDER_THREADSTATE_IPC_THREADSTATE_BASE_H
+
+#include <stack>
+namespace android {
+
+class IPCThreadStateBase {
+public:
+    enum CallState {
+        HWBINDER,
+        BINDER,
+        NONE,
+    };
+    static IPCThreadStateBase* self();
+    void pushCurrentState(CallState callState);
+    CallState popCurrentState();
+    CallState getCurrentBinderCallState();
+
+private:
+    IPCThreadStateBase();
+    static void threadDestructor(void *st);
+
+    std::stack<CallState> mCallStateStack;
+};
+
+}; // namespace android
+
+#endif // BINDER_THREADSTATE_IPC_THREADSTATE_BASE_H
diff --git a/libs/gui/BufferHubProducer.cpp b/libs/gui/BufferHubProducer.cpp
index 06d597c..3dac037 100644
--- a/libs/gui/BufferHubProducer.cpp
+++ b/libs/gui/BufferHubProducer.cpp
@@ -18,8 +18,8 @@
 #include <gui/BufferHubProducer.h>
 #include <inttypes.h>
 #include <log/log.h>
-#include <private/dvr/detached_buffer.h>
 #include <system/window.h>
+#include <ui/BufferHubBuffer.h>
 #include <ui/DetachedBufferHandle.h>
 
 namespace android {
@@ -400,14 +400,14 @@
         ALOGE("attachBuffer: DetachedBufferHandle cannot be NULL.");
         return BAD_VALUE;
     }
-    auto detached_buffer = DetachedBuffer::Import(std::move(detached_handle->handle()));
+    auto detached_buffer = BufferHubBuffer::Import(std::move(detached_handle->handle()));
     if (detached_buffer == nullptr) {
-        ALOGE("attachBuffer: DetachedBuffer cannot be NULL.");
+        ALOGE("attachBuffer: BufferHubBuffer cannot be NULL.");
         return BAD_VALUE;
     }
     auto status_or_handle = detached_buffer->Promote();
     if (!status_or_handle.ok()) {
-        ALOGE("attachBuffer: Failed to promote a DetachedBuffer into a BufferProducer, error=%d.",
+        ALOGE("attachBuffer: Failed to promote a BufferHubBuffer into a BufferProducer, error=%d.",
               status_or_handle.error());
         return BAD_VALUE;
     }
diff --git a/libs/gui/FrameTimestamps.cpp b/libs/gui/FrameTimestamps.cpp
index a379ad6..85ae433 100644
--- a/libs/gui/FrameTimestamps.cpp
+++ b/libs/gui/FrameTimestamps.cpp
@@ -621,7 +621,7 @@
 // ============================================================================
 
 FrameEventHistoryDelta& FrameEventHistoryDelta::operator=(
-        FrameEventHistoryDelta&& src) {
+        FrameEventHistoryDelta&& src) noexcept {
     mCompositorTiming = src.mCompositorTiming;
 
     if (CC_UNLIKELY(!mDeltas.empty())) {
diff --git a/libs/gui/include/gui/FrameTimestamps.h b/libs/gui/include/gui/FrameTimestamps.h
index 9716be4..e06e40f 100644
--- a/libs/gui/include/gui/FrameTimestamps.h
+++ b/libs/gui/include/gui/FrameTimestamps.h
@@ -311,7 +311,7 @@
 
     // Movable.
     FrameEventHistoryDelta(FrameEventHistoryDelta&& src) = default;
-    FrameEventHistoryDelta& operator=(FrameEventHistoryDelta&& src);
+    FrameEventHistoryDelta& operator=(FrameEventHistoryDelta&& src) noexcept;
     // Not copyable.
     FrameEventHistoryDelta(const FrameEventHistoryDelta& src) = delete;
     FrameEventHistoryDelta& operator=(
diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp
index 02064c6..7ecadf8 100644
--- a/libs/gui/tests/Android.bp
+++ b/libs/gui/tests/Android.bp
@@ -44,6 +44,7 @@
         "libgui",
         "libhidlbase",
         "libhidltransport",
+        "libinput",
         "libui",
         "libutils",
         "libnativewindow"
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index a2d6a8a..72558a6 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -47,11 +47,14 @@
                 "InputTransport.cpp",
                 "VelocityControl.cpp",
                 "VelocityTracker.cpp",
+                "InputApplication.cpp",
+                "InputWindow.cpp"
             ],
 
             shared_libs: [
                 "libutils",
                 "libbinder",
+                "libui"
             ],
 
             sanitize: {
diff --git a/services/inputflinger/InputApplication.cpp b/libs/input/InputApplication.cpp
similarity index 96%
rename from services/inputflinger/InputApplication.cpp
rename to libs/input/InputApplication.cpp
index c56dfe6..a0d1668 100644
--- a/services/inputflinger/InputApplication.cpp
+++ b/libs/input/InputApplication.cpp
@@ -16,7 +16,7 @@
 
 #define LOG_TAG "InputApplication"
 
-#include "InputApplication.h"
+#include <input/InputApplication.h>
 
 #include <android/log.h>
 
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index 770d483..32444f9 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -30,6 +30,7 @@
 #include <cutils/properties.h>
 #include <log/log.h>
 
+#include <binder/Parcel.h>
 #include <input/InputTransport.h>
 
 namespace android {
@@ -100,15 +101,13 @@
 // --- InputChannel ---
 
 InputChannel::InputChannel(const std::string& name, int fd) :
-        mName(name), mFd(fd) {
+        mName(name) {
 #if DEBUG_CHANNEL_LIFECYCLE
     ALOGD("Input channel constructed: name='%s', fd=%d",
             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.c_str(), errno);
+    setFd(fd);
 }
 
 InputChannel::~InputChannel() {
@@ -120,6 +119,18 @@
     ::close(mFd);
 }
 
+void InputChannel::setFd(int fd) {
+    if (mFd > 0) {
+        ::close(mFd);
+    }
+    mFd = fd;
+    if (mFd > 0) {
+        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.c_str(), errno);
+    }
+}
+
 status_t InputChannel::openInputChannelPair(const std::string& name,
         sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {
     int sockets[2];
@@ -230,6 +241,31 @@
 }
 
 
+status_t InputChannel::write(Parcel& out) const {
+    status_t s = out.writeString8(String8(getName().c_str()));
+
+    if (s != OK) {
+        return s;
+    }
+
+    s = out.writeDupFileDescriptor(getFd());
+
+    return s;
+}
+
+status_t InputChannel::read(const Parcel& from) {
+    mName = from.readString8();
+
+    int rawFd = from.readFileDescriptor();
+    setFd(::dup(rawFd));
+
+    if (mFd < 0) {
+        return BAD_VALUE;
+    }
+
+    return OK;
+}
+
 // --- InputPublisher ---
 
 InputPublisher::InputPublisher(const sp<InputChannel>& channel) :
diff --git a/libs/input/InputWindow.cpp b/libs/input/InputWindow.cpp
new file mode 100644
index 0000000..f94faba
--- /dev/null
+++ b/libs/input/InputWindow.cpp
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2011 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 "InputWindow"
+#define LOG_NDEBUG 0
+
+#include <binder/Parcel.h>
+#include <input/InputWindow.h>
+#include <input/InputTransport.h>
+
+#include <log/log.h>
+
+#include <ui/Rect.h>
+#include <ui/Region.h>
+
+namespace android {
+
+// --- InputWindowInfo ---
+void InputWindowInfo::addTouchableRegion(const Rect& region) {
+    touchableRegion.orSelf(region);
+}
+
+bool InputWindowInfo::touchableRegionContainsPoint(int32_t x, int32_t y) const {
+    return touchableRegion.contains(x,y);
+}
+
+bool InputWindowInfo::frameContainsPoint(int32_t x, int32_t y) const {
+    return x >= frameLeft && x < frameRight
+            && y >= frameTop && y < frameBottom;
+}
+
+bool InputWindowInfo::isTrustedOverlay() const {
+    return layoutParamsType == TYPE_INPUT_METHOD
+            || layoutParamsType == TYPE_INPUT_METHOD_DIALOG
+            || layoutParamsType == TYPE_MAGNIFICATION_OVERLAY
+            || layoutParamsType == TYPE_STATUS_BAR
+            || layoutParamsType == TYPE_NAVIGATION_BAR
+            || layoutParamsType == TYPE_NAVIGATION_BAR_PANEL
+            || layoutParamsType == TYPE_SECURE_SYSTEM_OVERLAY
+            || layoutParamsType == TYPE_DOCK_DIVIDER
+            || layoutParamsType == TYPE_ACCESSIBILITY_OVERLAY
+            || layoutParamsType == TYPE_INPUT_CONSUMER;
+}
+
+bool InputWindowInfo::supportsSplitTouch() const {
+    return layoutParamsFlags & FLAG_SPLIT_TOUCH;
+}
+
+bool InputWindowInfo::overlaps(const InputWindowInfo* other) const {
+    return frameLeft < other->frameRight && frameRight > other->frameLeft
+            && frameTop < other->frameBottom && frameBottom > other->frameTop;
+}
+
+status_t InputWindowInfo::write(Parcel& output) const {
+    if (inputChannel == nullptr) {
+        output.writeInt32(0);
+        return OK;
+    }
+    output.writeInt32(1);
+    status_t s = inputChannel->write(output);
+    if (s != OK) return s;
+
+    output.writeString8(String8(name.c_str()));
+    output.writeInt32(layoutParamsFlags);
+    output.writeInt32(layoutParamsType);
+    output.writeInt64(dispatchingTimeout);
+    output.writeInt32(frameLeft);
+    output.writeInt32(frameTop);
+    output.writeInt32(frameRight);
+    output.writeInt32(frameBottom);
+    output.writeFloat(scaleFactor);
+    output.writeBool(visible);
+    output.writeBool(canReceiveKeys);
+    output.writeBool(hasFocus);
+    output.writeBool(hasWallpaper);
+    output.writeBool(paused);
+    output.writeInt32(layer);
+    output.writeInt32(ownerPid);
+    output.writeInt32(ownerUid);
+    output.writeInt32(inputFeatures);
+    output.writeInt32(displayId);
+    output.write(touchableRegion);
+
+    return OK;
+}
+
+InputWindowInfo InputWindowInfo::read(const Parcel& from) {
+    InputWindowInfo ret;
+
+    if (from.readInt32() == 0) {
+        return ret;
+
+    }
+    sp<InputChannel> inputChannel = new InputChannel();
+    status_t s = inputChannel->read(from);
+    if (s != OK) {
+        return ret;
+    }
+
+    ret.inputChannel = inputChannel;
+    ret.name = from.readString8().c_str();
+    ret.layoutParamsFlags = from.readInt32();
+    ret.layoutParamsType = from.readInt32();
+    ret.dispatchingTimeout = from.readInt64();
+    ret.frameLeft = from.readInt32();
+    ret.frameTop = from.readInt32();
+    ret.frameRight = from.readInt32();
+    ret.frameBottom = from.readInt32();
+    ret.scaleFactor = from.readFloat();
+    ret.visible = from.readBool();
+    ret.canReceiveKeys = from.readBool();
+    ret.hasFocus = from.readBool();
+    ret.hasWallpaper = from.readBool();
+    ret.paused = from.readBool();
+    ret.layer = from.readInt32();
+    ret.ownerPid = from.readInt32();
+    ret.ownerUid = from.readInt32();
+    ret.inputFeatures = from.readInt32();
+    ret.displayId = from.readInt32();
+    from.read(ret.touchableRegion);
+
+    return ret;
+}
+
+// --- InputWindowHandle ---
+
+InputWindowHandle::InputWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle) :
+    inputApplicationHandle(inputApplicationHandle), mInfo(nullptr) {
+}
+
+InputWindowHandle::~InputWindowHandle() {
+    delete mInfo;
+}
+
+void InputWindowHandle::releaseInfo() {
+    if (mInfo) {
+        delete mInfo;
+        mInfo = nullptr;
+    }
+}
+
+sp<InputChannel> InputWindowHandle::getInputChannel() const {
+    return mInfo ? mInfo->inputChannel : nullptr;
+}
+
+} // namespace android
diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp
index f06119f..fdd945e 100644
--- a/libs/input/tests/Android.bp
+++ b/libs/input/tests/Android.bp
@@ -6,6 +6,7 @@
         "InputEvent_test.cpp",
         "InputPublisherAndConsumer_test.cpp",
         "VelocityTracker_test.cpp",
+        "InputWindow_test.cpp"
     ],
     cflags: [
         "-Wall",
@@ -34,4 +35,12 @@
         "-Wall",
         "-Werror",
     ],
+    shared_libs: [
+        "libinput",
+        "libcutils",
+        "libutils",
+        "libbinder",
+        "libui",
+        "libbase",
+    ]
 }
diff --git a/libs/input/tests/InputWindow_test.cpp b/libs/input/tests/InputWindow_test.cpp
new file mode 100644
index 0000000..39ad26e
--- /dev/null
+++ b/libs/input/tests/InputWindow_test.cpp
@@ -0,0 +1,93 @@
+/*
+ * 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 <gtest/gtest.h>
+
+#include <binder/Parcel.h>
+
+#include <input/InputWindow.h>
+#include <input/InputTransport.h>
+
+namespace android {
+namespace test {
+
+TEST(InputWindowInfo, ParcellingWithoutChannel) {
+    InputWindowInfo i;
+    i.inputChannel = nullptr;
+
+    Parcel p;
+    ASSERT_EQ(OK, i.write(p));
+    p.setDataPosition(0);
+    InputWindowInfo i2 = InputWindowInfo::read(p);
+    ASSERT_TRUE(i2.inputChannel == nullptr);
+}
+
+TEST(InputWindowInfo, Parcelling) {
+    sp<InputChannel> channel, junkChannel;
+    status_t result = InputChannel::openInputChannelPair("name", channel, junkChannel);
+    ASSERT_EQ(OK, result) << "openInputChannelPair should have returned valid channels";
+
+    InputWindowInfo i;
+    i.inputChannel = channel;
+    i.name = "Foobar";
+    i.layoutParamsFlags = 7;
+    i.layoutParamsType = 39;
+    i.dispatchingTimeout = 12;
+    i.frameLeft = 93;
+    i.frameTop = 34;
+    i.frameRight = 16;
+    i.frameBottom = 19;
+    i.scaleFactor = 0.3;
+    i.visible = false;
+    i.canReceiveKeys = false;
+    i.hasFocus = false;
+    i.hasWallpaper = false;
+    i.paused = false;
+    i.layer = 7;
+    i.ownerPid = 19;
+    i.ownerUid = 24;
+    i.inputFeatures = 29;
+    i.displayId = 34;
+
+    Parcel p;
+    i.write(p);
+
+    p.setDataPosition(0);
+    InputWindowInfo i2 = InputWindowInfo::read(p);
+    ASSERT_EQ(i.inputChannel->getName(), i2.inputChannel->getName());
+    ASSERT_EQ(i.name, i2.name);
+    ASSERT_EQ(i.layoutParamsFlags, i2.layoutParamsFlags);
+    ASSERT_EQ(i.layoutParamsType, i2.layoutParamsType);
+    ASSERT_EQ(i.dispatchingTimeout, i2.dispatchingTimeout);
+    ASSERT_EQ(i.frameLeft, i2.frameLeft);
+    ASSERT_EQ(i.frameTop, i2.frameTop);
+    ASSERT_EQ(i.frameRight, i2.frameRight);
+    ASSERT_EQ(i.frameBottom, i2.frameBottom);
+    ASSERT_EQ(i.scaleFactor, i2.scaleFactor);
+    ASSERT_EQ(i.visible, i2.visible);
+    ASSERT_EQ(i.canReceiveKeys, i2.canReceiveKeys);
+    ASSERT_EQ(i.hasFocus, i2.hasFocus);
+    ASSERT_EQ(i.hasWallpaper, i2.hasWallpaper);
+    ASSERT_EQ(i.paused, i2.paused);
+    ASSERT_EQ(i.layer, i2.layer);
+    ASSERT_EQ(i.ownerPid, i2.ownerPid);
+    ASSERT_EQ(i.ownerUid, i2.ownerUid);
+    ASSERT_EQ(i.inputFeatures, i2.inputFeatures);
+    ASSERT_EQ(i.displayId, i2.displayId);
+}
+
+} // namespace test
+} // namespace android
diff --git a/libs/input/tests/VelocityTracker_test.cpp b/libs/input/tests/VelocityTracker_test.cpp
index 5242a18..af97c34 100644
--- a/libs/input/tests/VelocityTracker_test.cpp
+++ b/libs/input/tests/VelocityTracker_test.cpp
@@ -16,6 +16,7 @@
 
 #define LOG_TAG "VelocityTracker_test"
 
+#include <array>
 #include <math.h>
 
 #include <android-base/stringprintf.h>
@@ -34,29 +35,35 @@
 // here EV = expected value, tol = VELOCITY_TOLERANCE
 constexpr float VELOCITY_TOLERANCE = 0.2;
 
+// estimate coefficients must be within 0.001% of the target value
+constexpr float COEFFICIENT_TOLERANCE = 0.00001;
+
 // --- 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);
-    }
+/*
+ * Similar to EXPECT_NEAR, but ensures that the difference between the two float values
+ * is at most a certain fraction of the target value.
+ * If fraction is zero, require exact match.
+ */
+static void EXPECT_NEAR_BY_FRACTION(float actual, float target, float fraction) {
+    float tolerance = fabsf(target * fraction);
 
-    // 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 (target == 0 && fraction != 0) {
+        // If target is zero, this would force actual == target, which is too harsh.
+        // Relax this requirement a little. The value is determined empirically from the
+        // coefficients computed by the quadratic least squares algorithms.
+        tolerance = 1E-6;
     }
-    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);
+    EXPECT_NEAR(actual, target, tolerance);
+}
+
+static void checkVelocity(float Vactual, float Vtarget) {
+    EXPECT_NEAR_BY_FRACTION(Vactual, Vtarget, VELOCITY_TOLERANCE);
+}
+
+static void checkCoefficient(float actual, float target) {
+    EXPECT_NEAR_BY_FRACTION(actual, target, COEFFICIENT_TOLERANCE);
 }
 
 void failWithMessage(std::string message) {
@@ -125,6 +132,19 @@
     delete event;
 }
 
+static void computeAndCheckQuadraticEstimate(const Position* positions, size_t numSamples,
+        const std::array<float, 3>& coefficients) {
+    VelocityTracker vt("lsq2");
+    MotionEvent* event = createSimpleMotionEvent(positions, numSamples);
+    vt.addMovement(event);
+    VelocityTracker::Estimator estimator;
+    EXPECT_TRUE(vt.getEstimator(0, &estimator));
+    for (size_t i = 0; i< coefficients.size(); i++) {
+        checkCoefficient(estimator.xCoeff[i], coefficients[i]);
+        checkCoefficient(estimator.yCoeff[i], coefficients[i]);
+    }
+}
+
 /*
  * ================== VelocityTracker tests generated manually =====================================
  */
@@ -662,5 +682,114 @@
     computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 28354.796875); // lsq2
 }
 
+/*
+ * Special care must be taken when constructing tests for LeastSquaresVelocityTrackerStrategy
+ * getEstimator function. In particular:
+ * - inside the function, time gets converted from nanoseconds to seconds
+ *   before being used in the fit.
+ * - any values that are older than 100 ms are being discarded.
+ * - the newest time gets subtracted from all of the other times before being used in the fit.
+ * So these tests have to be designed with those limitations in mind.
+ *
+ * General approach for the tests below:
+ * We only used timestamps in milliseconds, 0 ms, 1 ms, and 2 ms, to be sure that
+ * we are well within the HORIZON range.
+ * When specifying the expected values of the coefficients, we treat the x values as if
+ * they were in ms. Then, to adjust for the time units, the coefficients get progressively
+ * multiplied by powers of 1E3.
+ * For example:
+ * data: t(ms), x
+ *        1 ms, 1
+ *        2 ms, 4
+ *        3 ms, 9
+ * The coefficients are (0, 0, 1).
+ * In the test, we would convert these coefficients to (0*(1E3)^0, 0*(1E3)^1, 1*(1E3)^2).
+ */
+TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategyEstimator_Constant) {
+    Position values[] = {
+        { 0000000, 1, 1 }, // 0 s
+        { 1000000, 1, 1 }, // 0.001 s
+        { 2000000, 1, 1 }, // 0.002 s
+    };
+    // The data used for the fit will be as follows:
+    // time(s), position
+    // -0.002, 1
+    // -0.001, 1
+    // -0.000, 1
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckQuadraticEstimate(values, count, std::array<float, 3>({1, 0, 0}));
+}
+
+/*
+ * Straight line y = x :: the constant and quadratic coefficients are zero.
+ */
+TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategyEstimator_Linear) {
+    Position values[] = {
+        { 0000000, -2, -2 },
+        { 1000000, -1, -1 },
+        { 2000000, -0, -0 },
+    };
+    // The data used for the fit will be as follows:
+    // time(s), position
+    // -0.002, -2
+    // -0.001, -1
+    // -0.000,  0
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckQuadraticEstimate(values, count, std::array<float, 3>({0, 1E3, 0}));
+}
+
+/*
+ * Parabola
+ */
+TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategyEstimator_Parabolic) {
+    Position values[] = {
+        { 0000000, 1, 1 },
+        { 1000000, 4, 4 },
+        { 2000000, 8, 8 },
+    };
+    // The data used for the fit will be as follows:
+    // time(s), position
+    // -0.002, 1
+    // -0.001, 4
+    // -0.000, 8
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckQuadraticEstimate(values, count, std::array<float, 3>({8, 4.5E3, 0.5E6}));
+}
+
+/*
+ * Parabola
+ */
+TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategyEstimator_Parabolic2) {
+    Position values[] = {
+        { 0000000, 1, 1 },
+        { 1000000, 4, 4 },
+        { 2000000, 9, 9 },
+    };
+    // The data used for the fit will be as follows:
+    // time(s), position
+    // -0.002, 1
+    // -0.001, 4
+    // -0.000, 9
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckQuadraticEstimate(values, count, std::array<float, 3>({9, 6E3, 1E6}));
+}
+
+/*
+ * Parabola :: y = x^2 :: the constant and linear coefficients are zero.
+ */
+TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategyEstimator_Parabolic3) {
+    Position values[] = {
+        { 0000000, 4, 4 },
+        { 1000000, 1, 1 },
+        { 2000000, 0, 0 },
+    };
+    // The data used for the fit will be as follows:
+    // time(s), position
+    // -0.002, 4
+    // -0.001, 1
+    // -0.000, 0
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckQuadraticEstimate(values, count, std::array<float, 3>({0, 0E3, 1E6}));
+}
 
 } // namespace android
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index 1605050..24b1986 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -54,6 +54,8 @@
 
     srcs: [
         "ColorSpace.cpp",
+        "BufferHubBuffer.cpp",
+        "BufferHubMetadata.cpp",
         "DebugUtils.cpp",
         "Fence.cpp",
         "FenceTime.cpp",
@@ -91,6 +93,7 @@
         "libutils",
         "libutilscallstack",
         "liblog",
+        "libpdx_default_transport",  // TODO(b/112338294): Remove this once BufferHub moved to use Binder.
     ],
 
     export_shared_lib_headers: [
@@ -103,8 +106,27 @@
         "libmath",
     ],
 
+    // bufferhub is not used when building libgui for vendors
+    target: {
+        vendor: {
+            exclude_srcs: [
+                "BufferHubBuffer.cpp",
+                "BufferHubMetadata.cpp",
+            ],
+            exclude_header_libs: [
+                "libbufferhub_headers",
+                "libdvr_headers",
+            ],
+            exclude_shared_libs: [
+                "libpdx_default_transport",
+            ],
+        },
+    },
+
     header_libs: [
         "libbase_headers",
+        "libbufferhub_headers",
+        "libdvr_headers",
         "libnativebase_headers",
         "libhardware_headers",
         "libui_headers",
diff --git a/libs/ui/BufferHubBuffer.cpp b/libs/ui/BufferHubBuffer.cpp
new file mode 100644
index 0000000..606386c
--- /dev/null
+++ b/libs/ui/BufferHubBuffer.cpp
@@ -0,0 +1,211 @@
+/*
+ * 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.
+ */
+
+// We would eliminate the clang warnings introduced by libdpx.
+// TODO(b/112338294): Remove those once BufferHub moved to use Binder
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wdouble-promotion"
+#pragma clang diagnostic ignored "-Wgnu-case-range"
+#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
+#pragma clang diagnostic ignored "-Winconsistent-missing-destructor-override"
+#pragma clang diagnostic ignored "-Wnested-anon-types"
+#pragma clang diagnostic ignored "-Wpacked"
+#pragma clang diagnostic ignored "-Wshadow"
+#pragma clang diagnostic ignored "-Wsign-conversion"
+#pragma clang diagnostic ignored "-Wswitch-enum"
+#pragma clang diagnostic ignored "-Wundefined-func-template"
+#pragma clang diagnostic ignored "-Wunused-template"
+#pragma clang diagnostic ignored "-Wweak-vtables"
+#include <pdx/default_transport/client_channel.h>
+#include <pdx/default_transport/client_channel_factory.h>
+#include <pdx/file_handle.h>
+#include <private/dvr/bufferhub_rpc.h>
+#pragma clang diagnostic pop
+
+#include <ui/BufferHubBuffer.h>
+#include <ui/DetachedBufferHandle.h>
+
+#include <poll.h>
+
+using android::dvr::BufferHubMetadata;
+using android::dvr::BufferTraits;
+using android::dvr::DetachedBufferRPC;
+using android::dvr::NativeHandleWrapper;
+
+// TODO(b/112338294): Remove PDX dependencies from libui.
+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 {
+
+// TODO(b/112338294): Remove this string literal after refactoring BufferHub
+// to use Binder.
+static constexpr char kBufferHubClientPath[] = "system/buffer_hub/client";
+
+} // namespace
+
+BufferHubClient::BufferHubClient() : Client(ClientChannelFactory::Create(kBufferHubClientPath)) {}
+
+BufferHubClient::BufferHubClient(LocalChannelHandle mChannelHandle)
+      : Client(ClientChannel::Create(std::move(mChannelHandle))) {}
+
+BufferHubClient::~BufferHubClient() {}
+
+bool BufferHubClient::IsValid() const {
+  return IsConnected() && GetChannelHandle().valid();
+}
+
+LocalChannelHandle BufferHubClient::TakeChannelHandle() {
+    if (IsConnected()) {
+        return std::move(GetChannelHandle());
+    } else {
+        return {};
+    }
+}
+
+BufferHubBuffer::BufferHubBuffer(uint32_t width, uint32_t height, uint32_t layerCount,
+                                 uint32_t format, uint64_t usage, size_t mUserMetadataSize) {
+    ATRACE_CALL();
+    ALOGD("BufferHubBuffer::BufferHubBuffer: width=%u height=%u layerCount=%u, format=%u "
+          "usage=%" PRIx64 " mUserMetadataSize=%zu",
+          width, height, layerCount, format, usage, mUserMetadataSize);
+
+    auto status =
+            mClient.InvokeRemoteMethod<DetachedBufferRPC::Create>(width, height, layerCount, format,
+                                                                  usage, mUserMetadataSize);
+    if (!status) {
+        ALOGE("BufferHubBuffer::BufferHubBuffer: Failed to create detached buffer: %s",
+              status.GetErrorMessage().c_str());
+        mClient.Close(-status.error());
+    }
+
+    const int ret = ImportGraphicBuffer();
+    if (ret < 0) {
+        ALOGE("BufferHubBuffer::BufferHubBuffer: Failed to import buffer: %s", strerror(-ret));
+        mClient.Close(ret);
+    }
+}
+
+BufferHubBuffer::BufferHubBuffer(LocalChannelHandle mChannelHandle)
+      : mClient(std::move(mChannelHandle)) {
+    const int ret = ImportGraphicBuffer();
+    if (ret < 0) {
+        ALOGE("BufferHubBuffer::BufferHubBuffer: Failed to import buffer: %s", strerror(-ret));
+        mClient.Close(ret);
+    }
+}
+
+int BufferHubBuffer::ImportGraphicBuffer() {
+    ATRACE_CALL();
+
+    auto status = mClient.InvokeRemoteMethod<DetachedBufferRPC::Import>();
+    if (!status) {
+        ALOGE("BufferHubBuffer::BufferHubBuffer: Failed to import GraphicBuffer: %s",
+              status.GetErrorMessage().c_str());
+        return -status.error();
+    }
+
+    BufferTraits<LocalHandle> bufferTraits = status.take();
+    if (bufferTraits.id() < 0) {
+        ALOGE("BufferHubBuffer::BufferHubBuffer: Received an invalid id!");
+        return -EIO;
+    }
+
+    // Stash the buffer id to replace the value in mId.
+    const int bufferId = bufferTraits.id();
+
+    // Import the metadata.
+    mMetadata = BufferHubMetadata::Import(bufferTraits.take_metadata_handle());
+
+    if (!mMetadata.IsValid()) {
+        ALOGE("BufferHubBuffer::ImportGraphicBuffer: invalid metadata.");
+        return -ENOMEM;
+    }
+
+    if (mMetadata.metadata_size() != bufferTraits.metadata_size()) {
+        ALOGE("BufferHubBuffer::ImportGraphicBuffer: metadata buffer too small: "
+              "%zu, expected: %" PRIu64 ".",
+              mMetadata.metadata_size(), bufferTraits.metadata_size());
+        return -ENOMEM;
+    }
+
+    size_t metadataSize = static_cast<size_t>(bufferTraits.metadata_size());
+    if (metadataSize < dvr::BufferHubDefs::kMetadataHeaderSize) {
+        ALOGE("BufferHubBuffer::ImportGraphicBuffer: metadata too small: %zu", metadataSize);
+        return -EINVAL;
+    }
+
+    // Import the buffer: We only need to hold on the native_handle_t here so that
+    // GraphicBuffer instance can be created in future.
+    mBufferHandle = bufferTraits.take_buffer_handle();
+
+    // If all imports succeed, replace the previous buffer and id.
+    mId = bufferId;
+    mBfferStateBit = bufferTraits.buffer_state_bit();
+
+    // TODO(b/112012161) Set up shared fences.
+    ALOGD("BufferHubBuffer::ImportGraphicBuffer: id=%d, buffer_state=%" PRIx64 ".", id(),
+          mMetadata.metadata_header()->buffer_state.load(std::memory_order_acquire));
+    return 0;
+}
+
+int BufferHubBuffer::Poll(int timeoutMs) {
+    ATRACE_CALL();
+
+    pollfd p = {mClient.event_fd(), POLLIN, 0};
+    return poll(&p, 1, timeoutMs);
+}
+
+Status<LocalChannelHandle> BufferHubBuffer::Promote() {
+    ATRACE_CALL();
+
+    // TODO(b/112338294) remove after migrate producer buffer to binder
+    ALOGW("BufferHubBuffer::Promote: not supported operation during migration");
+    return {};
+
+    ALOGD("BufferHubBuffer::Promote: id=%d.", mId);
+
+    auto statusOrHandle = mClient.InvokeRemoteMethod<DetachedBufferRPC::Promote>();
+    if (statusOrHandle.ok()) {
+        // Invalidate the buffer.
+        mBufferHandle = {};
+    } else {
+        ALOGE("BufferHubBuffer::Promote: Failed to promote buffer (id=%d): %s.", mId,
+              statusOrHandle.GetErrorMessage().c_str());
+    }
+    return statusOrHandle;
+}
+
+Status<LocalChannelHandle> BufferHubBuffer::Duplicate() {
+    ATRACE_CALL();
+    ALOGD("BufferHubBuffer::Duplicate: id=%d.", mId);
+
+    auto statusOrHandle = mClient.InvokeRemoteMethod<DetachedBufferRPC::Duplicate>();
+
+    if (!statusOrHandle.ok()) {
+        ALOGE("BufferHubBuffer::Duplicate: Failed to duplicate buffer (id=%d): %s.", mId,
+              statusOrHandle.GetErrorMessage().c_str());
+    }
+    return statusOrHandle;
+}
+
+} // namespace android
diff --git a/libs/ui/BufferHubMetadata.cpp b/libs/ui/BufferHubMetadata.cpp
new file mode 100644
index 0000000..b0c4510
--- /dev/null
+++ b/libs/ui/BufferHubMetadata.cpp
@@ -0,0 +1,105 @@
+/*
+ * 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 <errno.h>
+#include <sys/mman.h>
+
+#include <cutils/ashmem.h>
+#include <log/log.h>
+#include <ui/BufferHubMetadata.h>
+
+namespace android {
+namespace dvr {
+
+namespace {
+
+static const int kAshmemProt = PROT_READ | PROT_WRITE;
+
+} // namespace
+
+using BufferHubDefs::kMetadataHeaderSize;
+using BufferHubDefs::MetadataHeader;
+
+/* static */
+BufferHubMetadata BufferHubMetadata::Create(size_t userMetadataSize) {
+    // The size the of metadata buffer is used as the "width" parameter during allocation. Thus it
+    // cannot overflow uint32_t.
+    if (userMetadataSize >= (std::numeric_limits<uint32_t>::max() - kMetadataHeaderSize)) {
+        ALOGE("BufferHubMetadata::Create: metadata size too big: %zu.", userMetadataSize);
+        return {};
+    }
+
+    const size_t metadataSize = userMetadataSize + kMetadataHeaderSize;
+    int fd = ashmem_create_region(/*name=*/"BufferHubMetadata", metadataSize);
+    if (fd < 0) {
+        ALOGE("BufferHubMetadata::Create: failed to create ashmem region.");
+        return {};
+    }
+
+    // Hand over the ownership of the fd to a pdx::LocalHandle immediately after the successful
+    // return of ashmem_create_region. The ashmemHandle is going to own the fd and to prevent fd
+    // leaks during error handling.
+    pdx::LocalHandle ashmemHandle{fd};
+
+    if (ashmem_set_prot_region(ashmemHandle.Get(), kAshmemProt) != 0) {
+        ALOGE("BufferHubMetadata::Create: failed to set protect region.");
+        return {};
+    }
+
+    return BufferHubMetadata::Import(std::move(ashmemHandle));
+}
+
+/* static */
+BufferHubMetadata BufferHubMetadata::Import(pdx::LocalHandle ashmemHandle) {
+    if (!ashmem_valid(ashmemHandle.Get())) {
+        ALOGE("BufferHubMetadata::Import: invalid ashmem fd.");
+        return {};
+    }
+
+    size_t metadataSize = static_cast<size_t>(ashmem_get_size_region(ashmemHandle.Get()));
+    size_t userMetadataSize = metadataSize - kMetadataHeaderSize;
+
+    // Note that here the buffer state is mapped from shared memory as an atomic object. The
+    // std::atomic's constructor will not be called so that the original value stored in the memory
+    // region can be preserved.
+    auto metadataHeader = static_cast<MetadataHeader*>(mmap(nullptr, metadataSize, kAshmemProt,
+                                                            MAP_SHARED, ashmemHandle.Get(),
+                                                            /*offset=*/0));
+    if (metadataHeader == nullptr) {
+        ALOGE("BufferHubMetadata::Import: failed to map region.");
+        return {};
+    }
+
+    return BufferHubMetadata(userMetadataSize, std::move(ashmemHandle), metadataHeader);
+}
+
+BufferHubMetadata::BufferHubMetadata(size_t userMetadataSize, pdx::LocalHandle ashmemHandle,
+                                     MetadataHeader* metadataHeader)
+      : mUserMetadataSize(userMetadataSize),
+        mAshmemHandle(std::move(ashmemHandle)),
+        mMetadataHeader(metadataHeader) {}
+
+BufferHubMetadata::~BufferHubMetadata() {
+    if (mMetadataHeader != nullptr) {
+        int ret = munmap(mMetadataHeader, metadata_size());
+        ALOGE_IF(ret != 0,
+                 "BufferHubMetadata::~BufferHubMetadata: failed to unmap ashmem, error=%d.", errno);
+        mMetadataHeader = nullptr;
+    }
+}
+
+} // namespace dvr
+} // namespace android
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index 0382479..c50d1d0 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -376,6 +376,10 @@
 
 status_t GraphicBuffer::unflatten(
         void const*& buffer, size_t& size, int const*& fds, size_t& count) {
+    if (size < 12 * sizeof(int)) {
+        android_errorWriteLog(0x534e4554, "114223584");
+        return NO_MEMORY;
+    }
 
     int const* buf = static_cast<int const*>(buffer);
 
diff --git a/libs/ui/HdrCapabilities.cpp b/libs/ui/HdrCapabilities.cpp
index a36911d..a5b3e89 100644
--- a/libs/ui/HdrCapabilities.cpp
+++ b/libs/ui/HdrCapabilities.cpp
@@ -24,8 +24,8 @@
 #endif
 
 HdrCapabilities::~HdrCapabilities() = default;
-HdrCapabilities::HdrCapabilities(HdrCapabilities&& other) = default;
-HdrCapabilities& HdrCapabilities::operator=(HdrCapabilities&& other) = default;
+HdrCapabilities::HdrCapabilities(HdrCapabilities&& other) noexcept = default;
+HdrCapabilities& HdrCapabilities::operator=(HdrCapabilities&& other) noexcept = default;
 
 size_t HdrCapabilities::getFlattenedSize() const {
     return  sizeof(mMaxLuminance) +
diff --git a/libs/ui/include/ui/BufferHubBuffer.h b/libs/ui/include/ui/BufferHubBuffer.h
new file mode 100644
index 0000000..e8ae244
--- /dev/null
+++ b/libs/ui/include/ui/BufferHubBuffer.h
@@ -0,0 +1,149 @@
+/*
+ * 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_BUFFER_HUB_BUFFER_H_
+#define ANDROID_BUFFER_HUB_BUFFER_H_
+
+// We would eliminate the clang warnings introduced by libdpx.
+// TODO(b/112338294): Remove those once BufferHub moved to use Binder
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wdouble-promotion"
+#pragma clang diagnostic ignored "-Wgnu-case-range"
+#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
+#pragma clang diagnostic ignored "-Winconsistent-missing-destructor-override"
+#pragma clang diagnostic ignored "-Wnested-anon-types"
+#pragma clang diagnostic ignored "-Wpacked"
+#pragma clang diagnostic ignored "-Wshadow"
+#pragma clang diagnostic ignored "-Wsign-conversion"
+#pragma clang diagnostic ignored "-Wswitch-enum"
+#pragma clang diagnostic ignored "-Wundefined-func-template"
+#pragma clang diagnostic ignored "-Wunused-template"
+#pragma clang diagnostic ignored "-Wweak-vtables"
+#include <pdx/client.h>
+#include <private/dvr/buffer_hub_defs.h>
+#include <private/dvr/native_handle_wrapper.h>
+#pragma clang diagnostic pop
+
+#include <ui/BufferHubMetadata.h>
+
+namespace android {
+
+class BufferHubClient : public pdx::Client {
+public:
+    BufferHubClient();
+    virtual ~BufferHubClient();
+    explicit BufferHubClient(pdx::LocalChannelHandle mChannelHandle);
+
+    bool IsValid() const;
+    pdx::LocalChannelHandle TakeChannelHandle();
+
+    using pdx::Client::Close;
+    using pdx::Client::event_fd;
+    using pdx::Client::GetChannel;
+    using pdx::Client::InvokeRemoteMethod;
+};
+
+class BufferHubBuffer {
+public:
+    // Allocates a standalone BufferHubBuffer not associated with any producer consumer set.
+    static std::unique_ptr<BufferHubBuffer> Create(uint32_t width, uint32_t height,
+                                                   uint32_t layerCount, uint32_t format,
+                                                   uint64_t usage, size_t mUserMetadataSize) {
+        return std::unique_ptr<BufferHubBuffer>(
+                new BufferHubBuffer(width, height, layerCount, format, usage, mUserMetadataSize));
+    }
+
+    // Imports the given channel handle to a BufferHubBuffer, taking ownership.
+    static std::unique_ptr<BufferHubBuffer> Import(pdx::LocalChannelHandle mChannelHandle) {
+        return std::unique_ptr<BufferHubBuffer>(new BufferHubBuffer(std::move(mChannelHandle)));
+    }
+
+    BufferHubBuffer(const BufferHubBuffer&) = delete;
+    void operator=(const BufferHubBuffer&) = delete;
+
+    // Gets ID of the buffer client. All BufferHubBuffer clients derived from the same buffer in
+    // bufferhubd share the same buffer id.
+    int id() const { return mId; }
+
+    const native_handle_t* DuplicateHandle() { return mBufferHandle.DuplicateHandle(); }
+
+    // Returns the current value of MetadataHeader::buffer_state.
+    uint64_t buffer_state() {
+        return mMetadata.metadata_header()->buffer_state.load(std::memory_order_acquire);
+    }
+
+    // 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 mBfferStateBit; }
+
+    size_t user_metadata_size() const { return mMetadata.user_metadata_size(); }
+
+    // Returns true if the buffer holds an open PDX channels towards bufferhubd.
+    bool IsConnected() const { return mClient.IsValid(); }
+
+    // Returns true if the buffer holds an valid native buffer handle that's availble for the client
+    // to read from and/or write into.
+    bool IsValid() const { return mBufferHandle.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 = mClient.GetChannel()) {
+            return channel->GetEventMask(events);
+        } else {
+            return pdx::ErrorStatus(EINVAL);
+        }
+    }
+
+    // Polls the fd for |timeoutMs| milliseconds (-1 for infinity).
+    int Poll(int timeoutMs);
+
+    // Promotes a BufferHubBuffer to become a ProducerBuffer. Once promoted the BufferHubBuffer
+    // channel will be closed automatically on successful IPC return. Further IPCs towards this
+    // channel will return error.
+    pdx::Status<pdx::LocalChannelHandle> Promote();
+
+    // Creates a BufferHubBuffer client from an existing one. The new client will
+    // share the same underlying gralloc buffer and ashmem region for metadata.
+    pdx::Status<pdx::LocalChannelHandle> Duplicate();
+
+private:
+    BufferHubBuffer(uint32_t width, uint32_t height, uint32_t layerCount, uint32_t format,
+                    uint64_t usage, size_t mUserMetadataSize);
+
+    BufferHubBuffer(pdx::LocalChannelHandle mChannelHandle);
+
+    int ImportGraphicBuffer();
+
+    // Global id for the buffer that is consistent across processes.
+    int mId;
+    uint64_t mBfferStateBit;
+
+    // Wrapps the gralloc buffer handle of this buffer.
+    dvr::NativeHandleWrapper<pdx::LocalHandle> mBufferHandle;
+
+    // An ashmem-based metadata object. The same shared memory are mapped to the
+    // bufferhubd daemon and all buffer clients.
+    dvr::BufferHubMetadata mMetadata;
+
+    // PDX backend.
+    BufferHubClient mClient;
+};
+
+} // namespace android
+
+#endif // ANDROID_BUFFER_HUB_BUFFER_H_
diff --git a/libs/ui/include/ui/BufferHubMetadata.h b/libs/ui/include/ui/BufferHubMetadata.h
new file mode 100644
index 0000000..46adc6a
--- /dev/null
+++ b/libs/ui/include/ui/BufferHubMetadata.h
@@ -0,0 +1,106 @@
+/*
+ * 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_BUFFER_HUB_METADATA_H_
+#define ANDROID_BUFFER_HUB_METADATA_H_
+
+// We would eliminate the clang warnings introduced by libdpx.
+// TODO(b/112338294): Remove those once BufferHub moved to use Binder
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wdouble-promotion"
+#pragma clang diagnostic ignored "-Wgnu-case-range"
+#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
+#pragma clang diagnostic ignored "-Winconsistent-missing-destructor-override"
+#pragma clang diagnostic ignored "-Wnested-anon-types"
+#pragma clang diagnostic ignored "-Wpacked"
+#pragma clang diagnostic ignored "-Wshadow"
+#pragma clang diagnostic ignored "-Wsign-conversion"
+#pragma clang diagnostic ignored "-Wswitch-enum"
+#pragma clang diagnostic ignored "-Wundefined-func-template"
+#pragma clang diagnostic ignored "-Wunused-template"
+#pragma clang diagnostic ignored "-Wweak-vtables"
+#include <pdx/file_handle.h>
+#include <private/dvr/buffer_hub_defs.h>
+#pragma clang diagnostic pop
+
+namespace android {
+namespace dvr {
+
+class BufferHubMetadata {
+public:
+    // Creates a new BufferHubMetadata backed by an ashmem region.
+    //
+    // @param userMetadataSize Size in bytes of the user defined metadata. The entire metadata
+    //        shared memory region to be allocated is the size of canonical
+    //        BufferHubDefs::MetadataHeader plus userMetadataSize.
+    static BufferHubMetadata Create(size_t userMetadataSize);
+
+    // Imports an existing BufferHubMetadata from an ashmem FD.
+    //
+    // TODO(b/112338294): Refactor BufferHub to use Binder as its internal IPC backend instead of
+    // UDS.
+    //
+    // @param ashmemHandle Ashmem file handle representing an ashmem region.
+    static BufferHubMetadata Import(pdx::LocalHandle ashmemHandle);
+
+    BufferHubMetadata() = default;
+
+    BufferHubMetadata(BufferHubMetadata&& other) { *this = std::move(other); }
+
+    ~BufferHubMetadata();
+
+    BufferHubMetadata& operator=(BufferHubMetadata&& other) {
+        if (this != &other) {
+            mUserMetadataSize = other.mUserMetadataSize;
+            other.mUserMetadataSize = 0;
+
+            mAshmemHandle = std::move(other.mAshmemHandle);
+
+            // The old raw mMetadataHeader pointer must be cleared, otherwise the destructor will
+            // automatically mummap() the shared memory.
+            mMetadataHeader = other.mMetadataHeader;
+            other.mMetadataHeader = nullptr;
+        }
+        return *this;
+    }
+
+    // Returns true if the metadata is valid, i.e. the metadata has a valid ashmem fd and the ashmem
+    // has been mapped into virtual address space.
+    bool IsValid() const { return mAshmemHandle.IsValid() && mMetadataHeader != nullptr; }
+
+    size_t user_metadata_size() const { return mUserMetadataSize; }
+    size_t metadata_size() const { return mUserMetadataSize + BufferHubDefs::kMetadataHeaderSize; }
+
+    const pdx::LocalHandle& ashmem_handle() const { return mAshmemHandle; }
+    BufferHubDefs::MetadataHeader* metadata_header() { return mMetadataHeader; }
+
+private:
+    BufferHubMetadata(size_t userMetadataSize, pdx::LocalHandle ashmemHandle,
+                      BufferHubDefs::MetadataHeader* metadataHeader);
+
+    BufferHubMetadata(const BufferHubMetadata&) = delete;
+    void operator=(const BufferHubMetadata&) = delete;
+
+    size_t mUserMetadataSize = 0;
+    pdx::LocalHandle mAshmemHandle;
+    BufferHubDefs::MetadataHeader* mMetadataHeader = nullptr;
+};
+
+} // namespace dvr
+} // namespace android
+
+#endif // ANDROID_BUFFER_HUB_METADATA_H_
diff --git a/libs/ui/include/ui/HdrCapabilities.h b/libs/ui/include/ui/HdrCapabilities.h
index 4e98c28..65ac26c 100644
--- a/libs/ui/include/ui/HdrCapabilities.h
+++ b/libs/ui/include/ui/HdrCapabilities.h
@@ -37,8 +37,8 @@
         mMinLuminance(minLuminance) {}
 
     // Make this move-constructable and move-assignable
-    HdrCapabilities(HdrCapabilities&& other);
-    HdrCapabilities& operator=(HdrCapabilities&& other);
+    HdrCapabilities(HdrCapabilities&& other) noexcept;
+    HdrCapabilities& operator=(HdrCapabilities&& other) noexcept;
 
     HdrCapabilities()
       : mSupportedHdrTypes(),
diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp
index aef6428..6e73960 100644
--- a/libs/ui/tests/Android.bp
+++ b/libs/ui/tests/Android.bp
@@ -34,3 +34,11 @@
     srcs: ["GraphicBuffer_test.cpp"],
     cflags: ["-Wall", "-Werror"],
 }
+
+cc_test {
+    name: "BufferHubMetadata_test",
+    header_libs: ["libbufferhub_headers", "libdvr_headers"],
+    shared_libs: ["libpdx_default_transport", "libui", "libutils"],
+    srcs: ["BufferHubMetadata_test.cpp"],
+    cflags: ["-Wall", "-Werror"],
+}
diff --git a/libs/ui/tests/BufferHubMetadata_test.cpp b/libs/ui/tests/BufferHubMetadata_test.cpp
new file mode 100644
index 0000000..4209392
--- /dev/null
+++ b/libs/ui/tests/BufferHubMetadata_test.cpp
@@ -0,0 +1,105 @@
+/*
+ * 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 <gtest/gtest.h>
+#include <ui/BufferHubMetadata.h>
+
+using android::dvr::BufferHubDefs::IsBufferGained;
+
+namespace android {
+namespace dvr {
+
+constexpr size_t kEmptyUserMetadataSize = 0;
+
+class BufferHubMetadataTest : public ::testing::Test {};
+
+TEST_F(BufferHubMetadataTest, Create_UserMetdataSizeTooBig) {
+  BufferHubMetadata m1 =
+      BufferHubMetadata::Create(std::numeric_limits<uint32_t>::max());
+  EXPECT_FALSE(m1.IsValid());
+}
+
+TEST_F(BufferHubMetadataTest, Create_Success) {
+  BufferHubMetadata m1 = BufferHubMetadata::Create(kEmptyUserMetadataSize);
+  EXPECT_TRUE(m1.IsValid());
+  EXPECT_NE(m1.metadata_header(), nullptr);
+}
+
+TEST_F(BufferHubMetadataTest, Import_Success) {
+  BufferHubMetadata m1 = BufferHubMetadata::Create(kEmptyUserMetadataSize);
+  EXPECT_TRUE(m1.IsValid());
+  EXPECT_NE(m1.metadata_header(), nullptr);
+
+  pdx::LocalHandle h2 = m1.ashmem_handle().Duplicate();
+  EXPECT_TRUE(h2.IsValid());
+
+  BufferHubMetadata m2 = BufferHubMetadata::Import(std::move(h2));
+  EXPECT_FALSE(h2.IsValid());
+  EXPECT_TRUE(m1.IsValid());
+  BufferHubDefs::MetadataHeader* mh1 = m1.metadata_header();
+  EXPECT_NE(mh1, nullptr);
+
+  // TODO(b/111976433): Update this test once BufferHub state machine gets
+  // updated. In the old model, buffer starts in the gained state (i.e.
+  // valued 0). In the new model, buffer states in the released state.
+  EXPECT_TRUE(IsBufferGained(mh1->fence_state.load()));
+
+  EXPECT_TRUE(m2.IsValid());
+  BufferHubDefs::MetadataHeader* mh2 = m2.metadata_header();
+  EXPECT_NE(mh2, nullptr);
+
+  // TODO(b/111976433): Update this test once BufferHub state machine gets
+  // updated. In the old model, buffer starts in the gained state (i.e.
+  // valued 0). In the new model, buffer states in the released state.
+  EXPECT_TRUE(IsBufferGained(mh2->fence_state.load()));
+}
+
+TEST_F(BufferHubMetadataTest, MoveMetadataInvalidatesOldOne) {
+  BufferHubMetadata m1 = BufferHubMetadata::Create(sizeof(int));
+  EXPECT_TRUE(m1.IsValid());
+  EXPECT_NE(m1.metadata_header(), nullptr);
+  EXPECT_TRUE(m1.ashmem_handle().IsValid());
+  EXPECT_EQ(m1.user_metadata_size(), sizeof(int));
+
+  BufferHubMetadata m2 = std::move(m1);
+
+  // After the move, the metadata header (a raw pointer) should be reset in the
+  // older buffer.
+  EXPECT_EQ(m1.metadata_header(), nullptr);
+  EXPECT_NE(m2.metadata_header(), nullptr);
+
+  EXPECT_FALSE(m1.ashmem_handle().IsValid());
+  EXPECT_TRUE(m2.ashmem_handle().IsValid());
+
+  EXPECT_EQ(m1.user_metadata_size(), 0U);
+  EXPECT_EQ(m2.user_metadata_size(), sizeof(int));
+
+  BufferHubMetadata m3{std::move(m2)};
+
+  // After the move, the metadata header (a raw pointer) should be reset in the
+  // older buffer.
+  EXPECT_EQ(m2.metadata_header(), nullptr);
+  EXPECT_NE(m3.metadata_header(), nullptr);
+
+  EXPECT_FALSE(m2.ashmem_handle().IsValid());
+  EXPECT_TRUE(m3.ashmem_handle().IsValid());
+
+  EXPECT_EQ(m2.user_metadata_size(), 0U);
+  EXPECT_EQ(m3.user_metadata_size(), sizeof(int));
+}
+
+}  // namespace dvr
+}  // namespace android
diff --git a/libs/vr/libbufferhub/Android.bp b/libs/vr/libbufferhub/Android.bp
index edc9131..ba5cfcd 100644
--- a/libs/vr/libbufferhub/Android.bp
+++ b/libs/vr/libbufferhub/Android.bp
@@ -12,20 +12,20 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+cc_library_headers {
+    name: "libbufferhub_headers",
+    export_include_dirs: ["include"],
+    vendor_available: true,  // TODO(b/112338314): Does shouldn't be available to vendor.
+}
+
 sourceFiles = [
     "buffer_hub_base.cpp",
-    "buffer_hub_client.cpp",
     "buffer_hub_rpc.cpp",
     "consumer_buffer.cpp",
-    "detached_buffer.cpp",
     "ion_buffer.cpp",
     "producer_buffer.cpp",
 ]
 
-localIncludeFiles = [
-    "include",
-]
-
 sharedLibraries = [
     "libbase",
     "libbinder",
@@ -39,6 +39,7 @@
 ]
 
 headerLibraries = [
+    "libbufferhub_headers",
     "libdvr_headers",
     "libnativebase_headers",
 ]
@@ -52,13 +53,16 @@
         "-Wall",
         "-Werror",
     ],
-    export_include_dirs: localIncludeFiles,
     shared_libs: sharedLibraries,
     header_libs: headerLibraries,
     name: "libbufferhub",
     export_header_lib_headers: [
+        "libbufferhub_headers",
         "libnativebase_headers",
     ],
+
+    // TODO(b/117568153): Temporarily opt out using libcrt.
+    no_libcrt: true,
 }
 
 cc_test {
@@ -67,5 +71,7 @@
     shared_libs: sharedLibraries,
     header_libs: headerLibraries,
     name: "buffer_hub-test",
-}
 
+    // TODO(b/117568153): Temporarily opt out using libcrt.
+    no_libcrt: true,
+}
diff --git a/libs/vr/libbufferhub/buffer_hub-test.cpp b/libs/vr/libbufferhub/buffer_hub-test.cpp
index 11b2211..b477f1a 100644
--- a/libs/vr/libbufferhub/buffer_hub-test.cpp
+++ b/libs/vr/libbufferhub/buffer_hub-test.cpp
@@ -2,9 +2,9 @@
 #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/BufferHubBuffer.h>
 #include <ui/DetachedBufferHandle.h>
 
 #include <mutex>
@@ -19,11 +19,11 @@
     return result;                            \
   })()
 
+using android::BufferHubBuffer;
 using android::GraphicBuffer;
 using android::sp;
-using android::dvr::BufferConsumer;
-using android::dvr::BufferProducer;
-using android::dvr::DetachedBuffer;
+using android::dvr::ConsumerBuffer;
+using android::dvr::ProducerBuffer;
 using android::dvr::BufferHubDefs::IsBufferAcquired;
 using android::dvr::BufferHubDefs::IsBufferGained;
 using android::dvr::BufferHubDefs::IsBufferPosted;
@@ -41,22 +41,21 @@
 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(
+  std::unique_ptr<ProducerBuffer> p = ProducerBuffer::Create(
       kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
   ASSERT_TRUE(p.get() != nullptr);
-  std::unique_ptr<BufferConsumer> c =
-      BufferConsumer::Import(p->CreateConsumer());
+  std::unique_ptr<ConsumerBuffer> c =
+      ConsumerBuffer::Import(p->CreateConsumer());
   ASSERT_TRUE(c.get() != nullptr);
   // Check that consumers can spawn other consumers.
-  std::unique_ptr<BufferConsumer> c2 =
-      BufferConsumer::Import(c->CreateConsumer());
+  std::unique_ptr<ConsumerBuffer> c2 =
+      ConsumerBuffer::Import(c->CreateConsumer());
   ASSERT_TRUE(c2.get() != nullptr);
 
   // Producer state mask is unique, i.e. 1.
@@ -79,22 +78,19 @@
   EXPECT_EQ(0, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
   EXPECT_EQ(0, RETRY_EINTR(c2->Poll(kPollTimeoutMs)));
 
-  EXPECT_EQ(0, p->Post(LocalHandle(), kContext));
+  EXPECT_EQ(0, p->Post(LocalHandle()));
 
   // 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, c->Acquire(&fence));
   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, c2->Acquire(&fence));
   EXPECT_EQ(0, RETRY_EINTR(c2->Poll(kPollTimeoutMs)));
   EXPECT_EQ(0, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
 
@@ -110,11 +106,11 @@
 }
 
 TEST_F(LibBufferHubTest, TestEpoll) {
-  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+  std::unique_ptr<ProducerBuffer> p = ProducerBuffer::Create(
       kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
   ASSERT_TRUE(p.get() != nullptr);
-  std::unique_ptr<BufferConsumer> c =
-      BufferConsumer::Import(p->CreateConsumer());
+  std::unique_ptr<ConsumerBuffer> c =
+      ConsumerBuffer::Import(p->CreateConsumer());
   ASSERT_TRUE(c.get() != nullptr);
 
   LocalHandle epoll_fd{epoll_create1(EPOLL_CLOEXEC)};
@@ -147,7 +143,7 @@
   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));
+  EXPECT_EQ(0, p->Post({}));
   ASSERT_EQ(1, epoll_wait(epoll_fd.Get(), events.data(), events.size(),
                           kPollTimeoutMs));
   ASSERT_TRUE(events[0].events & EPOLLIN);
@@ -177,15 +173,15 @@
 }
 
 TEST_F(LibBufferHubTest, TestStateMask) {
-  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+  std::unique_ptr<ProducerBuffer> p = ProducerBuffer::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;
+  std::array<std::unique_ptr<ConsumerBuffer>, kMaxConsumerCount> cs;
   for (size_t i = 0; i < kMaxConsumerCount; i++) {
-    cs[i] = BufferConsumer::Import(p->CreateConsumer());
+    cs[i] = ConsumerBuffer::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);
@@ -201,7 +197,7 @@
   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());
+    cs[i] = ConsumerBuffer::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);
@@ -211,11 +207,11 @@
 }
 
 TEST_F(LibBufferHubTest, TestStateTransitions) {
-  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+  std::unique_ptr<ProducerBuffer> p = ProducerBuffer::Create(
       kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
   ASSERT_TRUE(p.get() != nullptr);
-  std::unique_ptr<BufferConsumer> c =
-      BufferConsumer::Import(p->CreateConsumer());
+  std::unique_ptr<ConsumerBuffer> c =
+      ConsumerBuffer::Import(p->CreateConsumer());
   ASSERT_TRUE(c.get() != nullptr);
 
   uint64_t context;
@@ -229,10 +225,10 @@
   EXPECT_EQ(-EALREADY, p->Gain(&fence));
 
   // Post in gained state should succeed.
-  EXPECT_EQ(0, p->Post(LocalHandle(), kContext));
+  EXPECT_EQ(0, p->Post(LocalHandle()));
 
   // Post, release, and gain in posted state should fail.
-  EXPECT_EQ(-EBUSY, p->Post(LocalHandle(), kContext));
+  EXPECT_EQ(-EBUSY, p->Post(LocalHandle()));
   EXPECT_EQ(-EBUSY, c->Release(LocalHandle()));
   EXPECT_EQ(-EBUSY, p->Gain(&fence));
 
@@ -241,7 +237,7 @@
 
   // 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->Post(LocalHandle()));
   EXPECT_EQ(-EBUSY, p->Gain(&fence));
 
   // Release in acquired state should succeed.
@@ -251,7 +247,7 @@
   // 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));
+  EXPECT_EQ(-EBUSY, p->Post(LocalHandle()));
 
   // Gain in released state should succeed.
   EXPECT_EQ(0, p->Gain(&fence));
@@ -263,11 +259,11 @@
 }
 
 TEST_F(LibBufferHubTest, TestAsyncStateTransitions) {
-  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+  std::unique_ptr<ProducerBuffer> p = ProducerBuffer::Create(
       kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
   ASSERT_TRUE(p.get() != nullptr);
-  std::unique_ptr<BufferConsumer> c =
-      BufferConsumer::Import(p->CreateConsumer());
+  std::unique_ptr<ConsumerBuffer> c =
+      ConsumerBuffer::Import(p->CreateConsumer());
   ASSERT_TRUE(c.get() != nullptr);
 
   DvrNativeBufferMetadata metadata;
@@ -334,7 +330,7 @@
 }
 
 TEST_F(LibBufferHubTest, TestZeroConsumer) {
-  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+  std::unique_ptr<ProducerBuffer> p = ProducerBuffer::Create(
       kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
   ASSERT_TRUE(p.get() != nullptr);
 
@@ -350,21 +346,21 @@
   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());
+  std::unique_ptr<ConsumerBuffer> c =
+      ConsumerBuffer::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(
+  std::unique_ptr<ProducerBuffer> p = ProducerBuffer::Create(
       kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
   ASSERT_TRUE(p.get() != nullptr);
 
-  std::array<std::unique_ptr<BufferConsumer>, kMaxConsumerCount> cs;
+  std::array<std::unique_ptr<ConsumerBuffer>, kMaxConsumerCount> cs;
   for (size_t i = 0; i < kMaxConsumerCount; i++) {
-    cs[i] = BufferConsumer::Import(p->CreateConsumer());
+    cs[i] = ConsumerBuffer::Import(p->CreateConsumer());
     ASSERT_TRUE(cs[i].get() != nullptr);
     EXPECT_TRUE(IsBufferGained(cs[i]->buffer_state()));
   }
@@ -400,13 +396,13 @@
 }
 
 TEST_F(LibBufferHubTest, TestCreateConsumerWhenBufferGained) {
-  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+  std::unique_ptr<ProducerBuffer> p = ProducerBuffer::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());
+  std::unique_ptr<ConsumerBuffer> c =
+      ConsumerBuffer::Import(p->CreateConsumer());
   ASSERT_TRUE(c.get() != nullptr);
   EXPECT_TRUE(IsBufferGained(c->buffer_state()));
 
@@ -422,7 +418,7 @@
 }
 
 TEST_F(LibBufferHubTest, TestCreateConsumerWhenBufferPosted) {
-  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+  std::unique_ptr<ProducerBuffer> p = ProducerBuffer::Create(
       kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
   ASSERT_TRUE(p.get() != nullptr);
   EXPECT_TRUE(IsBufferGained(p->buffer_state()));
@@ -435,8 +431,8 @@
   EXPECT_TRUE(IsBufferPosted(p->buffer_state()));
 
   // Newly created consumer should be automatically sigalled.
-  std::unique_ptr<BufferConsumer> c =
-      BufferConsumer::Import(p->CreateConsumer());
+  std::unique_ptr<ConsumerBuffer> c =
+      ConsumerBuffer::Import(p->CreateConsumer());
   ASSERT_TRUE(c.get() != nullptr);
   EXPECT_TRUE(IsBufferPosted(c->buffer_state()));
   EXPECT_EQ(0, c->AcquireAsync(&metadata, &invalid_fence));
@@ -444,12 +440,12 @@
 }
 
 TEST_F(LibBufferHubTest, TestCreateConsumerWhenBufferReleased) {
-  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+  std::unique_ptr<ProducerBuffer> p = ProducerBuffer::Create(
       kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
   ASSERT_TRUE(p.get() != nullptr);
 
-  std::unique_ptr<BufferConsumer> c1 =
-      BufferConsumer::Import(p->CreateConsumer());
+  std::unique_ptr<ConsumerBuffer> c1 =
+      ConsumerBuffer::Import(p->CreateConsumer());
   ASSERT_TRUE(c1.get() != nullptr);
 
   DvrNativeBufferMetadata metadata;
@@ -470,8 +466,8 @@
 
   // Create another consumer immediately after the release, should not make the
   // buffer un-released.
-  std::unique_ptr<BufferConsumer> c2 =
-      BufferConsumer::Import(p->CreateConsumer());
+  std::unique_ptr<ConsumerBuffer> c2 =
+      ConsumerBuffer::Import(p->CreateConsumer());
   ASSERT_TRUE(c2.get() != nullptr);
 
   EXPECT_TRUE(IsBufferReleased(p->buffer_state()));
@@ -484,23 +480,20 @@
     int64_t field1;
     int64_t field2;
   };
-  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+  std::unique_ptr<ProducerBuffer> p = ProducerBuffer::Create(
       kWidth, kHeight, kFormat, kUsage, sizeof(Metadata));
   ASSERT_TRUE(p.get() != nullptr);
-  std::unique_ptr<BufferConsumer> c =
-      BufferConsumer::Import(p->CreateConsumer());
+  std::unique_ptr<ConsumerBuffer> c =
+      ConsumerBuffer::Import(p->CreateConsumer());
   ASSERT_TRUE(c.get() != nullptr);
-
   Metadata m = {1, 3};
-  EXPECT_EQ(0, p->Post(LocalHandle(), m));
+  EXPECT_EQ(0, p->Post(LocalHandle(), &m, sizeof(Metadata)));
   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)));
 }
@@ -515,23 +508,22 @@
     int64_t field2;
     int64_t field3;
   };
-  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+  std::unique_ptr<ProducerBuffer> p = ProducerBuffer::Create(
       kWidth, kHeight, kFormat, kUsage, sizeof(Metadata));
   ASSERT_TRUE(p.get() != nullptr);
-  std::unique_ptr<BufferConsumer> c =
-      BufferConsumer::Import(p->CreateConsumer());
+  std::unique_ptr<ConsumerBuffer> c =
+      ConsumerBuffer::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_NE(0, p->Post(LocalHandle(), &evil_meta, sizeof(OverSizedMetadata)));
   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));
+  EXPECT_EQ(0, p->Post(LocalHandle()));
 }
 
 TEST_F(LibBufferHubTest, TestAcquireWithWrongMetaSize) {
@@ -544,15 +536,15 @@
     int64_t field2;
     int64_t field3;
   };
-  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+  std::unique_ptr<ProducerBuffer> p = ProducerBuffer::Create(
       kWidth, kHeight, kFormat, kUsage, sizeof(Metadata));
   ASSERT_TRUE(p.get() != nullptr);
-  std::unique_ptr<BufferConsumer> c =
-      BufferConsumer::Import(p->CreateConsumer());
+  std::unique_ptr<ConsumerBuffer> c =
+      ConsumerBuffer::Import(p->CreateConsumer());
   ASSERT_TRUE(c.get() != nullptr);
 
   Metadata m = {1, 3};
-  EXPECT_EQ(0, p->Post(LocalHandle(), m));
+  EXPECT_EQ(0, p->Post(LocalHandle(), &m, sizeof(m)));
 
   LocalHandle fence;
   int64_t sequence;
@@ -569,26 +561,26 @@
 }
 
 TEST_F(LibBufferHubTest, TestAcquireWithNoMeta) {
-  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+  std::unique_ptr<ProducerBuffer> p = ProducerBuffer::Create(
       kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
   ASSERT_TRUE(p.get() != nullptr);
-  std::unique_ptr<BufferConsumer> c =
-      BufferConsumer::Import(p->CreateConsumer());
+  std::unique_ptr<ConsumerBuffer> c =
+      ConsumerBuffer::Import(p->CreateConsumer());
   ASSERT_TRUE(c.get() != nullptr);
 
   int64_t sequence = 3;
-  EXPECT_EQ(0, p->Post(LocalHandle(), sequence));
+  EXPECT_EQ(0, p->Post(LocalHandle(), &sequence, sizeof(sequence)));
 
   LocalHandle fence;
   EXPECT_EQ(0, c->Acquire(&fence));
 }
 
 TEST_F(LibBufferHubTest, TestWithNoMeta) {
-  std::unique_ptr<BufferProducer> p =
-      BufferProducer::Create(kWidth, kHeight, kFormat, kUsage);
+  std::unique_ptr<ProducerBuffer> p =
+      ProducerBuffer::Create(kWidth, kHeight, kFormat, kUsage);
   ASSERT_TRUE(p.get() != nullptr);
-  std::unique_ptr<BufferConsumer> c =
-      BufferConsumer::Import(p->CreateConsumer());
+  std::unique_ptr<ConsumerBuffer> c =
+      ConsumerBuffer::Import(p->CreateConsumer());
   ASSERT_TRUE(c.get() != nullptr);
 
   LocalHandle fence;
@@ -598,15 +590,15 @@
 }
 
 TEST_F(LibBufferHubTest, TestFailureToPostMetaFromABufferWithoutMeta) {
-  std::unique_ptr<BufferProducer> p =
-      BufferProducer::Create(kWidth, kHeight, kFormat, kUsage);
+  std::unique_ptr<ProducerBuffer> p =
+      ProducerBuffer::Create(kWidth, kHeight, kFormat, kUsage);
   ASSERT_TRUE(p.get() != nullptr);
-  std::unique_ptr<BufferConsumer> c =
-      BufferConsumer::Import(p->CreateConsumer());
+  std::unique_ptr<ConsumerBuffer> c =
+      ConsumerBuffer::Import(p->CreateConsumer());
   ASSERT_TRUE(c.get() != nullptr);
 
   int64_t sequence = 3;
-  EXPECT_NE(0, p->Post(LocalHandle(), sequence));
+  EXPECT_NE(0, p->Post(LocalHandle(), &sequence, sizeof(sequence)));
 }
 
 namespace {
@@ -619,11 +611,11 @@
 }  // namespace
 
 TEST_F(LibBufferHubTest, TestAcquireFence) {
-  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+  std::unique_ptr<ProducerBuffer> p = ProducerBuffer::Create(
       kWidth, kHeight, kFormat, kUsage, /*metadata_size=*/0);
   ASSERT_TRUE(p.get() != nullptr);
-  std::unique_ptr<BufferConsumer> c =
-      BufferConsumer::Import(p->CreateConsumer());
+  std::unique_ptr<ConsumerBuffer> c =
+      ConsumerBuffer::Import(p->CreateConsumer());
   ASSERT_TRUE(c.get() != nullptr);
 
   DvrNativeBufferMetadata meta;
@@ -680,11 +672,11 @@
 }
 
 TEST_F(LibBufferHubTest, TestOrphanedAcquire) {
-  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+  std::unique_ptr<ProducerBuffer> p = ProducerBuffer::Create(
       kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
   ASSERT_TRUE(p.get() != nullptr);
-  std::unique_ptr<BufferConsumer> c1 =
-      BufferConsumer::Import(p->CreateConsumer());
+  std::unique_ptr<ConsumerBuffer> c1 =
+      ConsumerBuffer::Import(p->CreateConsumer());
   ASSERT_TRUE(c1.get() != nullptr);
   const uint64_t consumer_state_bit1 = c1->buffer_state_bit();
 
@@ -699,8 +691,8 @@
   c1 = nullptr;
   EXPECT_GE(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
 
-  std::unique_ptr<BufferConsumer> c2 =
-      BufferConsumer::Import(p->CreateConsumer());
+  std::unique_ptr<ConsumerBuffer> c2 =
+      ConsumerBuffer::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);
@@ -715,8 +707,8 @@
   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());
+  std::unique_ptr<ConsumerBuffer> c3 =
+      ConsumerBuffer::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);
@@ -729,10 +721,13 @@
 }
 
 TEST_F(LibBufferHubTest, TestDetachBufferFromProducer) {
-  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+  // TODO(b/112338294) rewrite test after migration
+  return;
+
+  std::unique_ptr<ProducerBuffer> p = ProducerBuffer::Create(
       kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
-  std::unique_ptr<BufferConsumer> c =
-      BufferConsumer::Import(p->CreateConsumer());
+  std::unique_ptr<ConsumerBuffer> c =
+      ConsumerBuffer::Import(p->CreateConsumer());
   ASSERT_TRUE(p.get() != nullptr);
   ASSERT_TRUE(c.get() != nullptr);
 
@@ -789,8 +784,9 @@
   // 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));
+  // Detached buffer handle can be use to construct a new BufferHubBuffer
+  // object.
+  auto d = BufferHubBuffer::Import(std::move(handle));
   EXPECT_FALSE(handle.valid());
   EXPECT_TRUE(d->IsConnected());
   EXPECT_TRUE(d->IsValid());
@@ -798,17 +794,17 @@
   EXPECT_EQ(d->id(), p_id);
 }
 
-TEST_F(LibBufferHubTest, TestCreateDetachedBufferFails) {
+TEST_F(LibBufferHubTest, TestCreateBufferHubBufferFails) {
   // 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);
+  auto b1 = BufferHubBuffer::Create(kWidth, /*height=2*/ 2, kLayerCount,
+                                    /*format=*/HAL_PIXEL_FORMAT_BLOB, kUsage,
+                                    kUserMetadataSize);
 
   EXPECT_FALSE(b1->IsConnected());
   EXPECT_FALSE(b1->IsValid());
 
   // Buffer Creation will fail: user metadata size too large.
-  auto b2 = DetachedBuffer::Create(
+  auto b2 = BufferHubBuffer::Create(
       kWidth, kHeight, kLayerCount, kFormat, kUsage,
       /*user_metadata_size=*/std::numeric_limits<size_t>::max());
 
@@ -816,7 +812,7 @@
   EXPECT_FALSE(b2->IsValid());
 
   // Buffer Creation will fail: user metadata size too large.
-  auto b3 = DetachedBuffer::Create(
+  auto b3 = BufferHubBuffer::Create(
       kWidth, kHeight, kLayerCount, kFormat, kUsage,
       /*user_metadata_size=*/std::numeric_limits<size_t>::max() -
           kMetadataHeaderSize);
@@ -825,17 +821,20 @@
   EXPECT_FALSE(b3->IsValid());
 }
 
-TEST_F(LibBufferHubTest, TestCreateDetachedBuffer) {
-  auto b1 = DetachedBuffer::Create(kWidth, kHeight, kLayerCount, kFormat,
-                                   kUsage, kUserMetadataSize);
+TEST_F(LibBufferHubTest, TestCreateBufferHubBuffer) {
+  auto b1 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat,
+                                    kUsage, kUserMetadataSize);
   EXPECT_TRUE(b1->IsConnected());
   EXPECT_TRUE(b1->IsValid());
   EXPECT_NE(b1->id(), 0);
 }
 
-TEST_F(LibBufferHubTest, TestPromoteDetachedBuffer) {
-  auto b1 = DetachedBuffer::Create(kWidth, kHeight, kLayerCount, kFormat,
-                                   kUsage, kUserMetadataSize);
+TEST_F(LibBufferHubTest, TestPromoteBufferHubBuffer) {
+  // TODO(b/112338294) rewrite test after migration
+  return;
+
+  auto b1 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat,
+                                    kUsage, kUserMetadataSize);
   int b1_id = b1->id();
   EXPECT_TRUE(b1->IsValid());
 
@@ -856,7 +855,7 @@
   LocalChannelHandle h1 = status_or_handle.take();
   EXPECT_TRUE(h1.valid());
 
-  std::unique_ptr<BufferProducer> p1 = BufferProducer::Import(std::move(h1));
+  std::unique_ptr<ProducerBuffer> p1 = ProducerBuffer::Import(std::move(h1));
   EXPECT_FALSE(h1.valid());
   ASSERT_TRUE(p1 != nullptr);
   int p1_id = p1->id();
@@ -867,7 +866,10 @@
 }
 
 TEST_F(LibBufferHubTest, TestDetachThenPromote) {
-  std::unique_ptr<BufferProducer> p1 = BufferProducer::Create(
+  // TODO(b/112338294) rewrite test after migration
+  return;
+
+  std::unique_ptr<ProducerBuffer> p1 = ProducerBuffer::Create(
       kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
   ASSERT_TRUE(p1.get() != nullptr);
   int p1_id = p1->id();
@@ -878,8 +880,9 @@
   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));
+  // Detached buffer handle can be use to construct a new BufferHubBuffer
+  // object.
+  auto b1 = BufferHubBuffer::Import(std::move(h1));
   EXPECT_FALSE(h1.valid());
   EXPECT_TRUE(b1->IsValid());
   int b1_id = b1->id();
@@ -896,7 +899,7 @@
   LocalChannelHandle h2 = status_or_handle.take();
   EXPECT_TRUE(h2.valid());
 
-  std::unique_ptr<BufferProducer> p2 = BufferProducer::Import(std::move(h2));
+  std::unique_ptr<ProducerBuffer> p2 = ProducerBuffer::Import(std::move(h2));
   EXPECT_FALSE(h2.valid());
   ASSERT_TRUE(p2 != nullptr);
   int p2_id = p2->id();
@@ -906,11 +909,12 @@
   EXPECT_TRUE(IsBufferGained(p2->buffer_state()));
 }
 
-TEST_F(LibBufferHubTest, TestDuplicateDetachedBuffer) {
-  auto b1 = DetachedBuffer::Create(kWidth, kHeight, kLayerCount, kFormat,
-                                   kUsage, kUserMetadataSize);
+TEST_F(LibBufferHubTest, TestDuplicateBufferHubBuffer) {
+  auto b1 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat,
+                                    kUsage, kUserMetadataSize);
   int b1_id = b1->id();
   EXPECT_TRUE(b1->IsValid());
+  EXPECT_EQ(b1->user_metadata_size(), kUserMetadataSize);
 
   auto status_or_handle = b1->Duplicate();
   EXPECT_TRUE(status_or_handle);
@@ -923,9 +927,12 @@
   LocalChannelHandle h2 = status_or_handle.take();
   EXPECT_TRUE(h2.valid());
 
-  std::unique_ptr<DetachedBuffer> b2 = DetachedBuffer::Import(std::move(h2));
+  std::unique_ptr<BufferHubBuffer> b2 = BufferHubBuffer::Import(std::move(h2));
   EXPECT_FALSE(h2.valid());
   ASSERT_TRUE(b2 != nullptr);
+  EXPECT_TRUE(b2->IsValid());
+  EXPECT_EQ(b2->user_metadata_size(), kUserMetadataSize);
+
   int b2_id = b2->id();
 
   // These two buffer instances are based on the same physical buffer under the
@@ -942,6 +949,9 @@
   EXPECT_TRUE(IsBufferGained(b1->buffer_state()));
   EXPECT_TRUE(IsBufferGained(b2->buffer_state()));
 
+  // TODO(b/112338294) rewrite test after migration
+  return;
+
   // Promote the detached buffer should fail as b1 is no longer the exclusive
   // owner of the buffer..
   status_or_handle = b1->Promote();
diff --git a/libs/vr/libbufferhub/buffer_hub_base.cpp b/libs/vr/libbufferhub/buffer_hub_base.cpp
index b2bcda7..bc6aece 100644
--- a/libs/vr/libbufferhub/buffer_hub_base.cpp
+++ b/libs/vr/libbufferhub/buffer_hub_base.cpp
@@ -116,9 +116,10 @@
   cid_ = buffer_desc.buffer_cid();
   buffer_state_bit_ = buffer_desc.buffer_state_bit();
 
-  // Note that here the buffer state is mapped from shared memory as an atomic
-  // object. The std::atomic's constructor will not be called so that the
-  // original value stored in the memory region will be preserved.
+  // Note that here the buffer_state, fence_state and active_clients_bit_mask
+  // are mapped from shared memory as an atomic object. The std::atomic's
+  // constructor will not be called so that the original value stored in the
+  // memory region will be preserved.
   buffer_state_ = &metadata_header_->buffer_state;
   ALOGD_IF(TRACE,
            "BufferHubBase::ImportBuffer: id=%d, buffer_state=%" PRIx64 ".",
@@ -127,6 +128,12 @@
   ALOGD_IF(TRACE,
            "BufferHubBase::ImportBuffer: id=%d, fence_state=%" PRIx64 ".", id(),
            fence_state_->load());
+  active_clients_bit_mask_ = &metadata_header_->active_clients_bit_mask;
+  ALOGD_IF(
+      TRACE,
+      "BufferHubBase::ImportBuffer: id=%d, active_clients_bit_mask=%" PRIx64
+      ".",
+      id(), active_clients_bit_mask_->load());
 
   return 0;
 }
@@ -209,10 +216,6 @@
   return ret;
 }
 
-int BufferHubBase::GetBlobReadOnlyPointer(size_t size, void** addr) {
-  return GetBlobReadWritePointer(size, addr);
-}
-
 void BufferHubBase::GetBlobFds(int* fds, size_t* fds_count,
                                size_t max_fds_count) const {
   size_t numFds = static_cast<size_t>(native_handle()->numFds);
diff --git a/libs/vr/libbufferhub/buffer_hub_client.cpp b/libs/vr/libbufferhub/buffer_hub_client.cpp
deleted file mode 100644
index 3f20024..0000000
--- a/libs/vr/libbufferhub/buffer_hub_client.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-#include <mutex>
-
-#include <log/log.h>
-#include <pdx/default_transport/client_channel.h>
-#include <pdx/default_transport/client_channel_factory.h>
-#include <private/dvr/buffer_hub_client.h>
-#include <utils/Trace.h>
-
-using android::pdx::LocalChannelHandle;
-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 {};
-  }
-}
-
-}  // namespace dvr
-}  // namespace android
diff --git a/libs/vr/libbufferhub/consumer_buffer.cpp b/libs/vr/libbufferhub/consumer_buffer.cpp
index 4e8c36b..c9d8554 100644
--- a/libs/vr/libbufferhub/consumer_buffer.cpp
+++ b/libs/vr/libbufferhub/consumer_buffer.cpp
@@ -174,10 +174,5 @@
 
 int ConsumerBuffer::Discard() { return Release(LocalHandle()); }
 
-int ConsumerBuffer::SetIgnore(bool ignore) {
-  return ReturnStatusOrError(
-      InvokeRemoteMethod<BufferHubRPC::ConsumerSetIgnore>(ignore));
-}
-
 }  // namespace dvr
 }  // namespace android
diff --git a/libs/vr/libbufferhub/detached_buffer.cpp b/libs/vr/libbufferhub/detached_buffer.cpp
deleted file mode 100644
index 7716cfa..0000000
--- a/libs/vr/libbufferhub/detached_buffer.cpp
+++ /dev/null
@@ -1,166 +0,0 @@
-#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::ImportGraphicBuffer");
-
-  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;
-  }
-
-  // Import the metadata.
-  IonBuffer metadata_buffer;
-  if (const int ret = buffer_desc.ImportMetadata(&metadata_buffer)) {
-    ALOGE("Failed to import metadata buffer, error=%d", ret);
-    return ret;
-  }
-  size_t metadata_buf_size = metadata_buffer.width();
-  if (metadata_buf_size < BufferHubDefs::kMetadataHeaderSize) {
-    ALOGE("DetachedBuffer::ImportGraphicBuffer: metadata buffer too small: %zu",
-          metadata_buf_size);
-    return -EINVAL;
-  }
-
-  // If all imports succeed, replace the previous buffer and id.
-  id_ = buffer_id;
-  buffer_ = std::move(ion_buffer);
-  metadata_buffer_ = std::move(metadata_buffer);
-  user_metadata_size_ = metadata_buf_size - BufferHubDefs::kMetadataHeaderSize;
-
-  void* metadata_ptr = nullptr;
-  if (const int ret =
-          metadata_buffer_.Lock(BufferHubDefs::kMetadataUsage, /*x=*/0,
-                                /*y=*/0, metadata_buf_size,
-                                /*height=*/1, &metadata_ptr)) {
-    ALOGE("DetachedBuffer::ImportGraphicBuffer: Failed to lock metadata.");
-    return ret;
-  }
-
-  // TODO(b/112012161) Set up shared fences.
-
-  // Note that here the buffer state is mapped from shared memory as an atomic
-  // object. The std::atomic's constructor will not be called so that the
-  // original value stored in the memory region can be preserved.
-  metadata_header_ = static_cast<BufferHubDefs::MetadataHeader*>(metadata_ptr);
-  if (user_metadata_size_) {
-    user_metadata_ptr_ = static_cast<void*>(metadata_header_ + 1);
-  } else {
-    user_metadata_ptr_ = nullptr;
-  }
-
-  id_ = buffer_desc.id();
-  buffer_state_bit_ = buffer_desc.buffer_state_bit();
-
-  ALOGD_IF(TRACE,
-           "DetachedBuffer::ImportGraphicBuffer: id=%d, buffer_state=%" PRIx64
-           ".",
-           id(), metadata_header_->buffer_state.load());
-  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;
-}
-
-Status<LocalChannelHandle> DetachedBuffer::Duplicate() {
-  ATRACE_NAME("DetachedBuffer::Duplicate");
-  ALOGD_IF(TRACE, "DetachedBuffer::Duplicate: id=%d.", id_);
-
-  auto status_or_handle =
-      client_.InvokeRemoteMethod<DetachedBufferRPC::Duplicate>();
-
-  if (!status_or_handle.ok()) {
-    ALOGE("DetachedBuffer::Duplicate: Failed to duplicate buffer (id=%d): %s.",
-          id_, status_or_handle.GetErrorMessage().c_str());
-  }
-  return status_or_handle;
-}
-
-}  // namespace dvr
-}  // namespace android
diff --git a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h
index 24db241..282be46 100644
--- a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h
+++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h
@@ -39,11 +39,6 @@
   // after calling this method.
   int GetBlobReadWritePointer(size_t size, void** addr);
 
-  // Gets a blob buffer that was created with ProducerBuffer::CreateBlob.
-  // Locking and Unlocking is handled internally. There's no need to Unlock
-  // after calling this method.
-  int GetBlobReadOnlyPointer(size_t size, void** addr);
-
   // Returns a dup'd file descriptor for accessing the blob shared memory. The
   // caller takes ownership of the file descriptor and must close it or pass on
   // ownership. Some GPU API extensions can take file descriptors to bind shared
@@ -139,6 +134,7 @@
   void* user_metadata_ptr_{nullptr};
   std::atomic<uint64_t>* buffer_state_{nullptr};
   std::atomic<uint64_t>* fence_state_{nullptr};
+  std::atomic<uint64_t>* active_clients_bit_mask_{nullptr};
 
   LocalHandle shared_acquire_fence_;
   LocalHandle shared_release_fence_;
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 7b317d1..1daeed9 100644
--- a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h
+++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h
@@ -1,30 +1,10 @@
 #ifndef ANDROID_DVR_BUFFER_HUB_CLIENT_H_
 #define ANDROID_DVR_BUFFER_HUB_CLIENT_H_
 
-#include <pdx/channel_handle.h>
-#include <pdx/client.h>
+// TODO(b/116855254): This header is completely deprecated and replaced by
+// consumer_buffer.h and producer_buffer.h. Remove this file once all references
+// to it has been removed.
 #include <private/dvr/consumer_buffer.h>
 #include <private/dvr/producer_buffer.h>
 
-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;
-};
-
-}  // namespace dvr
-}  // namespace android
-
 #endif  // ANDROID_DVR_BUFFER_HUB_CLIENT_H_
diff --git a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h
index 8b2bf91..6d28d41 100644
--- a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h
+++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h
@@ -3,6 +3,11 @@
 
 #include <dvr/dvr_api.h>
 #include <hardware/gralloc.h>
+#include <pdx/channel_handle.h>
+#include <pdx/file_handle.h>
+#include <pdx/rpc/remote_method.h>
+#include <pdx/rpc/serializable.h>
+#include <private/dvr/native_handle_wrapper.h>
 
 #include <atomic>
 
@@ -70,6 +75,7 @@
   // and vendor HAL).
   std::atomic<uint64_t> buffer_state;
   std::atomic<uint64_t> fence_state;
+  std::atomic<uint64_t> active_clients_bit_mask;
   uint64_t queue_index;
 
   // Public data format, which should be updated with caution. See more details
@@ -77,13 +83,142 @@
   DvrNativeBufferMetadata metadata;
 };
 
-static_assert(sizeof(MetadataHeader) == 128, "Unexpected MetadataHeader size");
+static_assert(sizeof(MetadataHeader) == 136, "Unexpected MetadataHeader size");
 static constexpr size_t kMetadataHeaderSize = sizeof(MetadataHeader);
 
 }  // namespace BufferHubDefs
 
+template <typename FileHandleType>
+class BufferTraits {
+ public:
+  BufferTraits() = default;
+  BufferTraits(const native_handle_t* buffer_handle,
+               const FileHandleType& metadata_handle, int id,
+               uint64_t buffer_state_bit, uint64_t metadata_size,
+               uint32_t width, uint32_t height, uint32_t layer_count,
+               uint32_t format, uint64_t usage, uint32_t stride,
+               const FileHandleType& acquire_fence_fd,
+               const FileHandleType& release_fence_fd)
+      : id_(id),
+        buffer_state_bit_(buffer_state_bit),
+        metadata_size_(metadata_size),
+        width_(width),
+        height_(height),
+        layer_count_(layer_count),
+        format_(format),
+        usage_(usage),
+        stride_(stride),
+        buffer_handle_(buffer_handle),
+        metadata_handle_(metadata_handle.Borrow()),
+        acquire_fence_fd_(acquire_fence_fd.Borrow()),
+        release_fence_fd_(release_fence_fd.Borrow()) {}
+
+  BufferTraits(BufferTraits&& other) = default;
+  BufferTraits& operator=(BufferTraits&& other) = default;
+
+  // ID of the buffer client. All BufferHubBuffer clients derived from the same
+  // buffer in bufferhubd share the same buffer id.
+  int id() const { return id_; }
+
+  // State mask of the buffer client. Each BufferHubBuffer client backed by the
+  // same buffer channel has uniqued state bit among its siblings. For a
+  // producer buffer the bit must be kProducerStateBit; for a consumer the bit
+  // must be one of the kConsumerStateMask.
+  uint64_t buffer_state_bit() const { return buffer_state_bit_; }
+  uint64_t metadata_size() const { return metadata_size_; }
+
+  uint32_t width() { return width_; }
+  uint32_t height() { return height_; }
+  uint32_t layer_count() { return layer_count_; }
+  uint32_t format() { return format_; }
+  uint64_t usage() { return usage_; }
+  uint32_t stride() { return stride_; }
+
+  const NativeHandleWrapper<FileHandleType>& buffer_handle() const {
+    return buffer_handle_;
+  }
+
+  NativeHandleWrapper<FileHandleType> take_buffer_handle() {
+    return std::move(buffer_handle_);
+  }
+  FileHandleType take_metadata_handle() { return std::move(metadata_handle_); }
+  FileHandleType take_acquire_fence() { return std::move(acquire_fence_fd_); }
+  FileHandleType take_release_fence() { return std::move(release_fence_fd_); }
+
+ private:
+  // BufferHub specific traits.
+  int id_ = -1;
+  uint64_t buffer_state_bit_;
+  uint64_t metadata_size_;
+
+  // Traits for a GraphicBuffer.
+  uint32_t width_;
+  uint32_t height_;
+  uint32_t layer_count_;
+  uint32_t format_;
+  uint64_t usage_;
+  uint32_t stride_;
+
+  // Native handle for the graphic buffer.
+  NativeHandleWrapper<FileHandleType> buffer_handle_;
+
+  // File handle of an ashmem that holds buffer metadata.
+  FileHandleType metadata_handle_;
+
+  // Pamameters for shared fences.
+  FileHandleType acquire_fence_fd_;
+  FileHandleType release_fence_fd_;
+
+  PDX_SERIALIZABLE_MEMBERS(BufferTraits<FileHandleType>, id_, buffer_state_bit_,
+                           metadata_size_, stride_, width_, height_,
+                           layer_count_, format_, usage_, buffer_handle_,
+                           metadata_handle_, acquire_fence_fd_,
+                           release_fence_fd_);
+
+  BufferTraits(const BufferTraits&) = delete;
+  void operator=(const BufferTraits&) = delete;
+};
+
+struct DetachedBufferRPC {
+ private:
+  enum {
+    kOpDetachedBufferBase = 1000,
+
+    // Allocates a standalone DetachedBuffer not associated with any producer
+    // consumer set.
+    kOpCreate,
+
+    // Imports the given channel handle to a DetachedBuffer, taking ownership.
+    kOpImport,
+
+    // 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.
+    kOpPromote,
+
+    // Creates a DetachedBuffer client from an existing one. The new client will
+    // share the same underlying gralloc buffer and ashmem region for metadata.
+    kOpDuplicate,
+  };
+
+  // Aliases.
+  using LocalChannelHandle = pdx::LocalChannelHandle;
+  using LocalHandle = pdx::LocalHandle;
+  using Void = pdx::rpc::Void;
+
+ 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, BufferTraits<LocalHandle>(Void));
+  PDX_REMOTE_METHOD(Promote, kOpPromote, LocalChannelHandle(Void));
+  PDX_REMOTE_METHOD(Duplicate, kOpDuplicate, LocalChannelHandle(Void));
+
+  PDX_REMOTE_API(API, Create, Import, Promote, Duplicate);
+};
+
 }  // namespace dvr
 }  // namespace android
 
-
 #endif  // ANDROID_DVR_BUFFER_HUB_DEFS_H_
diff --git a/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h b/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
index 225914a..7330aa1 100644
--- a/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
+++ b/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
@@ -38,8 +38,8 @@
       opaque_ints_.push_back(buffer.handle()->data[fd_count + i]);
     }
   }
-  NativeBufferHandle(NativeBufferHandle&& other) = default;
-  NativeBufferHandle& operator=(NativeBufferHandle&& other) = default;
+  NativeBufferHandle(NativeBufferHandle&& other) noexcept = default;
+  NativeBufferHandle& operator=(NativeBufferHandle&& other) noexcept = default;
 
   // Imports the native handle into the given IonBuffer instance.
   int Import(IonBuffer* buffer) {
@@ -110,8 +110,8 @@
         acquire_fence_fd_(acquire_fence_fd.Borrow()),
         release_fence_fd_(release_fence_fd.Borrow()) {}
 
-  BufferDescription(BufferDescription&& other) = default;
-  BufferDescription& operator=(BufferDescription&& other) = default;
+  BufferDescription(BufferDescription&& other) noexcept = default;
+  BufferDescription& operator=(BufferDescription&& other) noexcept = default;
 
   // ID of the buffer client. All BufferHub clients derived from the same buffer
   // in bufferhubd share the same buffer id.
@@ -161,8 +161,8 @@
   FenceHandle() = default;
   explicit FenceHandle(int fence) : fence_{fence} {}
   explicit FenceHandle(FileHandleType&& fence) : fence_{std::move(fence)} {}
-  FenceHandle(FenceHandle&&) = default;
-  FenceHandle& operator=(FenceHandle&&) = default;
+  FenceHandle(FenceHandle&&) noexcept = default;
+  FenceHandle& operator=(FenceHandle&&) noexcept = default;
 
   explicit operator bool() const { return fence_.IsValid(); }
 
@@ -314,11 +314,8 @@
     kOpProducerGain,
     kOpConsumerAcquire,
     kOpConsumerRelease,
-    kOpConsumerSetIgnore,
     kOpProducerBufferDetach,
     kOpConsumerBufferDetach,
-    kOpDetachedBufferCreate,
-    kOpDetachedBufferPromote,
     kOpCreateProducerQueue,
     kOpCreateConsumerQueue,
     kOpGetQueueInfo,
@@ -327,7 +324,6 @@
     kOpProducerQueueRemoveBuffer,
     kOpConsumerQueueImportBuffers,
     // TODO(b/77153033): Separate all those RPC operations into subclasses.
-    kOpDetachedBufferBase = 1000,
   };
 
   // Aliases.
@@ -348,7 +344,6 @@
   PDX_REMOTE_METHOD(ConsumerAcquire, kOpConsumerAcquire, LocalFence(Void));
   PDX_REMOTE_METHOD(ConsumerRelease, kOpConsumerRelease,
                     void(LocalFence release_fence));
-  PDX_REMOTE_METHOD(ConsumerSetIgnore, kOpConsumerSetIgnore, void(bool ignore));
   PDX_REMOTE_METHOD(ProducerBufferDetach, kOpProducerBufferDetach,
                     LocalChannelHandle(Void));
 
@@ -381,27 +376,6 @@
                     std::vector<std::pair<LocalChannelHandle, size_t>>(Void));
 };
 
-struct DetachedBufferRPC final : public BufferHubRPC {
- private:
-  enum {
-    kOpCreate = kOpDetachedBufferBase,
-    kOpImport,
-    kOpPromote,
-    kOpDuplicate,
-  };
-
- 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_METHOD(Duplicate, kOpDuplicate, LocalChannelHandle(Void));
-
-  PDX_REMOTE_API(API, Create, Import, Promote, Duplicate);
-};
-
 }  // namespace dvr
 }  // namespace android
 
diff --git a/libs/vr/libbufferhub/include/private/dvr/consumer_buffer.h b/libs/vr/libbufferhub/include/private/dvr/consumer_buffer.h
index 089eff8..2044c53 100644
--- a/libs/vr/libbufferhub/include/private/dvr/consumer_buffer.h
+++ b/libs/vr/libbufferhub/include/private/dvr/consumer_buffer.h
@@ -76,13 +76,6 @@
   // negative unix error code.
   int Discard();
 
-  // When set, this consumer is no longer notified when this buffer is
-  // available. The system behaves as if Discard() is immediately called
-  // whenever the buffer is posted. If ignore is set to true while a buffer is
-  // pending, it will act as if Discard() was also called.
-  // This returns zero or a negative unix error code.
-  int SetIgnore(bool ignore);
-
  private:
   friend BASE;
 
diff --git a/libs/vr/libbufferhub/include/private/dvr/detached_buffer.h b/libs/vr/libbufferhub/include/private/dvr/detached_buffer.h
deleted file mode 100644
index e795f3b..0000000
--- a/libs/vr/libbufferhub/include/private/dvr/detached_buffer.h
+++ /dev/null
@@ -1,98 +0,0 @@
-#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;
-
-  // Gets ID of the buffer client. All DetachedBuffer clients derived from the
-  // same buffer in bufferhubd share the same buffer id.
-  int id() const { return id_; }
-
-  // Returns the current value of MetadataHeader::buffer_state.
-  uint64_t buffer_state() { return metadata_header_->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_; }
-
-  // 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();
-
-  // Creates a DetachedBuffer from an existing one.
-  pdx::Status<pdx::LocalChannelHandle> Duplicate();
-
- 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_;
-  uint64_t buffer_state_bit_;
-
-  // The concrete Ion buffers.
-  IonBuffer buffer_;
-  IonBuffer metadata_buffer_;
-
-  // buffer metadata.
-  size_t user_metadata_size_ = 0;
-  BufferHubDefs::MetadataHeader* metadata_header_ = nullptr;
-  void* user_metadata_ptr_ = nullptr;
-
-  // PDX backend.
-  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 f6bc547..860f08a 100644
--- a/libs/vr/libbufferhub/include/private/dvr/ion_buffer.h
+++ b/libs/vr/libbufferhub/include/private/dvr/ion_buffer.h
@@ -20,8 +20,8 @@
             uint64_t usage);
   ~IonBuffer();
 
-  IonBuffer(IonBuffer&& other);
-  IonBuffer& operator=(IonBuffer&& other);
+  IonBuffer(IonBuffer&& other) noexcept;
+  IonBuffer& operator=(IonBuffer&& other) noexcept;
 
   // Returns check this IonBuffer holds a valid Gralloc buffer.
   bool IsValid() const { return buffer_ && buffer_->initCheck() == NO_ERROR; }
diff --git a/libs/vr/libbufferhub/include/private/dvr/native_handle_wrapper.h b/libs/vr/libbufferhub/include/private/dvr/native_handle_wrapper.h
new file mode 100644
index 0000000..3086982
--- /dev/null
+++ b/libs/vr/libbufferhub/include/private/dvr/native_handle_wrapper.h
@@ -0,0 +1,100 @@
+#ifndef ANDROID_DVR_NATIVE_HANDLE_WRAPPER_H_
+#define ANDROID_DVR_NATIVE_HANDLE_WRAPPER_H_
+
+#include <cutils/native_handle.h>
+
+#include <vector>
+
+namespace android {
+namespace dvr {
+
+// A PDX-friendly wrapper to maintain the life cycle of a native_handle_t
+// object.
+//
+// See https://source.android.com/devices/architecture/hidl/types#handle_t for
+// more information about native_handle_t.
+template <typename FileHandleType>
+class NativeHandleWrapper {
+ public:
+  NativeHandleWrapper() = default;
+  NativeHandleWrapper(NativeHandleWrapper&& other) = default;
+  NativeHandleWrapper& operator=(NativeHandleWrapper&& other) = default;
+
+  // Create a new NativeHandleWrapper by duplicating the handle.
+  explicit NativeHandleWrapper(const native_handle_t* handle) {
+    const int fd_count = handle->numFds;
+    const int int_count = handle->numInts;
+
+    // Populate the fd and int vectors: native_handle->data[] is an array of fds
+    // followed by an array of opaque ints.
+    for (int i = 0; i < fd_count; i++) {
+      fds_.emplace_back(FileHandleType::AsDuplicate(handle->data[i]));
+    }
+    for (int i = 0; i < int_count; i++) {
+      ints_.push_back(handle->data[fd_count + i]);
+    }
+  }
+
+  size_t int_count() const { return ints_.size(); }
+  size_t fd_count() const { return fds_.size(); }
+  bool IsValid() const { return ints_.size() != 0 || fds_.size() != 0; }
+
+  // Duplicate a native handle from the wrapper.
+  const native_handle_t* DuplicateHandle() const {
+    if (!IsValid()) {
+      return nullptr;
+    }
+
+    // numFds + numInts ints.
+    std::vector<FileHandleType> fds;
+    for (const auto& fd : fds_) {
+      if (!fd.IsValid()) {
+        return nullptr;
+      }
+      fds.emplace_back(fd.Duplicate());
+    }
+
+    return FromFdsAndInts(std::move(fds), ints_);
+  }
+
+  // Takes the native handle out of the wrapper.
+  const native_handle_t* TakeHandle() {
+    if (!IsValid()) {
+      return nullptr;
+    }
+
+    return FromFdsAndInts(std::move(fds_), std::move(ints_));
+  }
+
+ private:
+  NativeHandleWrapper(const NativeHandleWrapper&) = delete;
+  void operator=(const NativeHandleWrapper&) = delete;
+
+  static const native_handle_t* FromFdsAndInts(std::vector<FileHandleType> fds,
+                                               std::vector<int> ints) {
+    native_handle_t* handle = native_handle_create(fds.size(), ints.size());
+    if (!handle) {
+      ALOGE("NativeHandleWrapper::TakeHandle: Failed to create new handle.");
+      return nullptr;
+    }
+
+    // numFds + numInts ints.
+    for (int i = 0; i < handle->numFds; i++) {
+      handle->data[i] = fds[i].Release();
+    }
+    memcpy(&handle->data[handle->numFds], ints.data(),
+           sizeof(int) * handle->numInts);
+
+    return handle;
+  }
+
+  std::vector<int> ints_;
+  std::vector<FileHandleType> fds_;
+
+  PDX_SERIALIZABLE_MEMBERS(NativeHandleWrapper<FileHandleType>, ints_, fds_);
+};
+
+}  // namespace dvr
+}  // namespace android
+
+#endif  // ANDROID_DVR_NATIVE_HANDLE_WRAPPER_H_
diff --git a/libs/vr/libbufferhub/include/private/dvr/producer_buffer.h b/libs/vr/libbufferhub/include/private/dvr/producer_buffer.h
index b5e1c5b..d2d4d1e 100644
--- a/libs/vr/libbufferhub/include/private/dvr/producer_buffer.h
+++ b/libs/vr/libbufferhub/include/private/dvr/producer_buffer.h
@@ -50,12 +50,6 @@
     return Post(ready_fence, nullptr, 0);
   }
 
-  template <typename Meta, typename = typename std::enable_if<
-                               !std::is_void<Meta>::value>::type>
-  int Post(const LocalHandle& ready_fence, const Meta& meta) {
-    return Post(ready_fence, &meta, sizeof(meta));
-  }
-
   // Attempt to re-gain the buffer for writing. If |release_fence| is valid, it
   // must be waited on before using the buffer. If it is not valid then the
   // buffer is free for immediate use. This call will only succeed if the buffer
diff --git a/libs/vr/libbufferhub/ion_buffer.cpp b/libs/vr/libbufferhub/ion_buffer.cpp
index cbaa24a..1295531 100644
--- a/libs/vr/libbufferhub/ion_buffer.cpp
+++ b/libs/vr/libbufferhub/ion_buffer.cpp
@@ -49,11 +49,11 @@
   FreeHandle();
 }
 
-IonBuffer::IonBuffer(IonBuffer&& other) : IonBuffer() {
+IonBuffer::IonBuffer(IonBuffer&& other) noexcept : IonBuffer() {
   *this = std::move(other);
 }
 
-IonBuffer& IonBuffer::operator=(IonBuffer&& other) {
+IonBuffer& IonBuffer::operator=(IonBuffer&& other) noexcept {
   ALOGD_IF(TRACE, "IonBuffer::operator=: handle_=%p other.handle_=%p", handle(),
            other.handle());
 
diff --git a/libs/vr/libbufferhub/producer_buffer.cpp b/libs/vr/libbufferhub/producer_buffer.cpp
index c4f1a3b..7b6f77a 100644
--- a/libs/vr/libbufferhub/producer_buffer.cpp
+++ b/libs/vr/libbufferhub/producer_buffer.cpp
@@ -222,6 +222,10 @@
 }
 
 Status<LocalChannelHandle> ProducerBuffer::Detach() {
+  // TODO(b/112338294) remove after migrate producer buffer to binder
+  ALOGW("ProducerBuffer::Detach: not supported operation during migration");
+  return {};
+
   uint64_t buffer_state = buffer_state_->load();
   if (!BufferHubDefs::IsBufferGained(buffer_state)) {
     // Can only detach a ProducerBuffer when it's in gained state.
diff --git a/libs/vr/libbufferhubqueue/Android.bp b/libs/vr/libbufferhubqueue/Android.bp
index 9f72c05..20894e3 100644
--- a/libs/vr/libbufferhubqueue/Android.bp
+++ b/libs/vr/libbufferhubqueue/Android.bp
@@ -59,6 +59,9 @@
     static_libs: staticLibraries,
     shared_libs: sharedLibraries,
     header_libs: headerLibraries,
+
+    // TODO(b/117568153): Temporarily opt out using libcrt.
+    no_libcrt: true,
 }
 
 subdirs = ["benchmarks", "tests"]
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
index 4dea9b2..ad3f56b 100644
--- a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_parcelable.h
+++ b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_parcelable.h
@@ -28,8 +28,8 @@
  public:
   BufferHubQueueParcelable() = default;
 
-  BufferHubQueueParcelable(BufferHubQueueParcelable&& other) = default;
-  BufferHubQueueParcelable& operator=(BufferHubQueueParcelable&& other) {
+  BufferHubQueueParcelable(BufferHubQueueParcelable&& other) noexcept = default;
+  BufferHubQueueParcelable& operator=(BufferHubQueueParcelable&& other) noexcept {
     channel_parcelable_ = std::move(other.channel_parcelable_);
     return *this;
   }
diff --git a/libs/vr/libdvr/tests/Android.bp b/libs/vr/libdvr/tests/Android.bp
index 3260447..357dffe 100644
--- a/libs/vr/libdvr/tests/Android.bp
+++ b/libs/vr/libdvr/tests/Android.bp
@@ -49,6 +49,9 @@
         "-g",
     ],
     name: "dvr_api-test",
+
+    // TODO(b/117568153): Temporarily opt out using libcrt.
+    no_libcrt: true,
 }
 
 cc_test {
diff --git a/libs/vr/libdvrcommon/include/private/dvr/ring_buffer.h b/libs/vr/libdvrcommon/include/private/dvr/ring_buffer.h
index 44485a7..1824241 100644
--- a/libs/vr/libdvrcommon/include/private/dvr/ring_buffer.h
+++ b/libs/vr/libdvrcommon/include/private/dvr/ring_buffer.h
@@ -23,9 +23,9 @@
   explicit RingBuffer(size_t capacity) { Reset(capacity); }
 
   RingBuffer(const RingBuffer& other) = default;
-  RingBuffer(RingBuffer&& other) = default;
+  RingBuffer(RingBuffer&& other) noexcept = default;
   RingBuffer& operator=(const RingBuffer& other) = default;
-  RingBuffer& operator=(RingBuffer&& other) = default;
+  RingBuffer& operator=(RingBuffer&& other) noexcept = default;
 
   void Append(const T& val) {
     if (IsFull())
diff --git a/libs/vr/libpdx/private/pdx/channel_handle.h b/libs/vr/libpdx/private/pdx/channel_handle.h
index 1e62d25..daa08f4 100644
--- a/libs/vr/libpdx/private/pdx/channel_handle.h
+++ b/libs/vr/libpdx/private/pdx/channel_handle.h
@@ -50,14 +50,14 @@
  public:
   ChannelHandle() = default;
   using ChannelHandleBase::ChannelHandleBase;
-  ChannelHandle(ChannelHandle&& other) : ChannelHandleBase{other.value_} {
+  ChannelHandle(ChannelHandle&& other) noexcept : ChannelHandleBase{other.value_} {
     other.value_ = kEmptyHandle;
   }
   ~ChannelHandle() = default;
 
   ChannelHandle Duplicate() const { return ChannelHandle{value_}; }
 
-  ChannelHandle& operator=(ChannelHandle&& other) {
+  ChannelHandle& operator=(ChannelHandle&& other) noexcept {
     value_ = other.value_;
     other.value_ = kEmptyHandle;
     return *this;
@@ -74,13 +74,13 @@
   ChannelHandle(const ChannelHandle&) = delete;
   ChannelHandle& operator=(const ChannelHandle&) = delete;
 
-  ChannelHandle(ChannelHandle&& other)
+  ChannelHandle(ChannelHandle&& other) noexcept
       : ChannelHandleBase{other.value_}, manager_{other.manager_} {
     other.manager_ = nullptr;
     other.value_ = kEmptyHandle;
   }
 
-  ChannelHandle& operator=(ChannelHandle&& other) {
+  ChannelHandle& operator=(ChannelHandle&& other) noexcept {
     value_ = other.value_;
     manager_ = other.manager_;
     other.value_ = kEmptyHandle;
diff --git a/libs/vr/libpdx/private/pdx/file_handle.h b/libs/vr/libpdx/private/pdx/file_handle.h
index b3c3ad7..fed1529 100644
--- a/libs/vr/libpdx/private/pdx/file_handle.h
+++ b/libs/vr/libpdx/private/pdx/file_handle.h
@@ -43,7 +43,7 @@
 
   // Move constructor that assumes ownership of the file descriptor, leaving the
   // other FileHandle object empty.
-  FileHandle(FileHandle&& other) {
+  FileHandle(FileHandle&& other) noexcept {
     fd_ = other.fd_;
     other.fd_ = kEmptyFileHandle;
   }
@@ -62,7 +62,7 @@
 
   // Move assignment operator that assumes ownership of the underlying file
   // descriptor, leaving the other FileHandle object empty.
-  FileHandle& operator=(FileHandle&& other) {
+  FileHandle& operator=(FileHandle&& other) noexcept {
     if (this != &other) {
       Reset(other.fd_);
       other.fd_ = kEmptyFileHandle;
diff --git a/libs/vr/libpdx/private/pdx/rpc/array_wrapper.h b/libs/vr/libpdx/private/pdx/rpc/array_wrapper.h
index 93d87f3..d835c57 100644
--- a/libs/vr/libpdx/private/pdx/rpc/array_wrapper.h
+++ b/libs/vr/libpdx/private/pdx/rpc/array_wrapper.h
@@ -39,7 +39,7 @@
 
   ArrayWrapper(const ArrayWrapper& other) { *this = other; }
 
-  ArrayWrapper(ArrayWrapper&& other) { *this = std::move(other); }
+  ArrayWrapper(ArrayWrapper&& other) noexcept { *this = std::move(other); }
 
   ArrayWrapper& operator=(const ArrayWrapper& other) {
     if (&other == this) {
@@ -53,7 +53,7 @@
     return *this;
   }
 
-  ArrayWrapper& operator=(ArrayWrapper&& other) {
+  ArrayWrapper& operator=(ArrayWrapper&& other) noexcept {
     if (&other == this) {
       return *this;
     } else {
diff --git a/libs/vr/libpdx/private/pdx/rpc/buffer_wrapper.h b/libs/vr/libpdx/private/pdx/rpc/buffer_wrapper.h
index aa86531..0421220 100644
--- a/libs/vr/libpdx/private/pdx/rpc/buffer_wrapper.h
+++ b/libs/vr/libpdx/private/pdx/rpc/buffer_wrapper.h
@@ -39,7 +39,7 @@
 
   BufferWrapper(const BufferWrapper& other) { *this = other; }
 
-  BufferWrapper(BufferWrapper&& other) { *this = std::move(other); }
+  BufferWrapper(BufferWrapper&& other) noexcept { *this = std::move(other); }
 
   BufferWrapper& operator=(const BufferWrapper& other) {
     if (&other == this) {
@@ -53,7 +53,7 @@
     return *this;
   }
 
-  BufferWrapper& operator=(BufferWrapper&& other) {
+  BufferWrapper& operator=(BufferWrapper&& other) noexcept {
     if (&other == this) {
       return *this;
     } else {
@@ -117,9 +117,9 @@
   BufferWrapper(BufferType&& buffer, const Allocator& allocator)
       : buffer_(std::move(buffer), allocator) {}
   BufferWrapper(const BufferWrapper&) = default;
-  BufferWrapper(BufferWrapper&&) = default;
+  BufferWrapper(BufferWrapper&&) noexcept = default;
   BufferWrapper& operator=(const BufferWrapper&) = default;
-  BufferWrapper& operator=(BufferWrapper&&) = default;
+  BufferWrapper& operator=(BufferWrapper&&) noexcept = default;
 
   pointer data() { return buffer_.data(); }
   const_pointer data() const { return buffer_.data(); }
diff --git a/libs/vr/libpdx/private/pdx/rpc/pointer_wrapper.h b/libs/vr/libpdx/private/pdx/rpc/pointer_wrapper.h
index d496719..1cb85de 100644
--- a/libs/vr/libpdx/private/pdx/rpc/pointer_wrapper.h
+++ b/libs/vr/libpdx/private/pdx/rpc/pointer_wrapper.h
@@ -15,9 +15,9 @@
 
   PointerWrapper(T* pointer) : pointer_(pointer) {}
   PointerWrapper(const PointerWrapper&) = default;
-  PointerWrapper(PointerWrapper&&) = default;
+  PointerWrapper(PointerWrapper&&) noexcept = default;
   PointerWrapper& operator=(const PointerWrapper&) = default;
-  PointerWrapper& operator=(PointerWrapper&&) = default;
+  PointerWrapper& operator=(PointerWrapper&&) noexcept = default;
 
   T& Dereference() { return *pointer_; }
   const T& Dereference() const { return *pointer_; }
diff --git a/libs/vr/libpdx/private/pdx/rpc/string_wrapper.h b/libs/vr/libpdx/private/pdx/rpc/string_wrapper.h
index 19fc4c1..2d0a4ea 100644
--- a/libs/vr/libpdx/private/pdx/rpc/string_wrapper.h
+++ b/libs/vr/libpdx/private/pdx/rpc/string_wrapper.h
@@ -44,7 +44,7 @@
 
   StringWrapper(const StringWrapper& other) { *this = other; }
 
-  StringWrapper(StringWrapper&& other) { *this = std::move(other); }
+  StringWrapper(StringWrapper&& other) noexcept { *this = std::move(other); }
 
   StringWrapper& operator=(const StringWrapper& other) {
     if (&other == this) {
@@ -58,7 +58,7 @@
     return *this;
   }
 
-  StringWrapper& operator=(StringWrapper&& other) {
+  StringWrapper& operator=(StringWrapper&& other) noexcept {
     if (&other == this) {
       return *this;
     } else {
diff --git a/libs/vr/libpdx/private/pdx/rpc/variant.h b/libs/vr/libpdx/private/pdx/rpc/variant.h
index 0a4802e..a1292b0 100644
--- a/libs/vr/libpdx/private/pdx/rpc/variant.h
+++ b/libs/vr/libpdx/private/pdx/rpc/variant.h
@@ -447,7 +447,7 @@
 
   Variant(const Variant& other)
       : index_{other.index_}, value_{other.value_, other.index_} {}
-  Variant(Variant&& other)
+  Variant(Variant&& other) noexcept
       : index_{other.index_}, value_{std::move(other.value_), other.index_} {}
 
 // Recent Clang versions has a regression that produces bogus
@@ -472,7 +472,7 @@
     other.Visit([this](const auto& value) { *this = value; });
     return *this;
   }
-  Variant& operator=(Variant&& other) {
+  Variant& operator=(Variant&& other) noexcept {
     other.Visit([this](auto&& value) { *this = std::move(value); });
     return *this;
   }
diff --git a/libs/vr/libpdx/private/pdx/service.h b/libs/vr/libpdx/private/pdx/service.h
index 15fa327..d38b174 100644
--- a/libs/vr/libpdx/private/pdx/service.h
+++ b/libs/vr/libpdx/private/pdx/service.h
@@ -101,8 +101,8 @@
   /*
    * Message objects support move construction and assignment.
    */
-  Message(Message&& other);
-  Message& operator=(Message&& other);
+  Message(Message&& other) noexcept;
+  Message& operator=(Message&& other) noexcept;
 
   /*
    * Read/write payload, in either single buffer or iovec form.
diff --git a/libs/vr/libpdx/private/pdx/status.h b/libs/vr/libpdx/private/pdx/status.h
index 067fe25..7e51a52 100644
--- a/libs/vr/libpdx/private/pdx/status.h
+++ b/libs/vr/libpdx/private/pdx/status.h
@@ -41,14 +41,14 @@
   // Copy/move constructors. Move constructor leaves |other| object in empty
   // state.
   Status(const Status& other) = default;
-  Status(Status&& other)
+  Status(Status&& other) noexcept
       : value_{std::move(other.value_)}, error_{other.error_} {
     other.error_ = -1;
   }
 
   // Assignment operators.
   Status& operator=(const Status& other) = default;
-  Status& operator=(Status&& other) {
+  Status& operator=(Status&& other) noexcept {
     error_ = other.error_;
     value_ = std::move(other.value_);
     other.error_ = -1;
diff --git a/libs/vr/libpdx/private/pdx/utility.h b/libs/vr/libpdx/private/pdx/utility.h
index 08fcaea..c9a0c21 100644
--- a/libs/vr/libpdx/private/pdx/utility.h
+++ b/libs/vr/libpdx/private/pdx/utility.h
@@ -33,7 +33,7 @@
     return *this;
   }
 
-  ByteBuffer& operator=(ByteBuffer&& other) {
+  ByteBuffer& operator=(ByteBuffer&& other) noexcept {
     std::swap(data_, other.data_);
     std::swap(size_, other.size_);
     std::swap(capacity_, other.capacity_);
diff --git a/libs/vr/libpdx/service.cpp b/libs/vr/libpdx/service.cpp
index 1d3b62a..68b8dd7 100644
--- a/libs/vr/libpdx/service.cpp
+++ b/libs/vr/libpdx/service.cpp
@@ -31,9 +31,9 @@
 
 // C++11 specifies the move semantics for shared_ptr but not weak_ptr. This
 // means we have to manually implement the desired move semantics for Message.
-Message::Message(Message&& other) { *this = std::move(other); }
+Message::Message(Message&& other) noexcept { *this = std::move(other); }
 
-Message& Message::operator=(Message&& other) {
+Message& Message::operator=(Message&& other) noexcept {
   Destroy();
   auto base = reinterpret_cast<std::uint8_t*>(&info_);
   std::fill(&base[0], &base[sizeof(info_)], 0);
diff --git a/libs/vr/libvrflinger/acquired_buffer.cpp b/libs/vr/libvrflinger/acquired_buffer.cpp
index 9614c6d..5d873d1 100644
--- a/libs/vr/libvrflinger/acquired_buffer.cpp
+++ b/libs/vr/libvrflinger/acquired_buffer.cpp
@@ -31,13 +31,13 @@
   }
 }
 
-AcquiredBuffer::AcquiredBuffer(AcquiredBuffer&& other) {
+AcquiredBuffer::AcquiredBuffer(AcquiredBuffer&& other) noexcept {
   *this = std::move(other);
 }
 
 AcquiredBuffer::~AcquiredBuffer() { Release(LocalHandle(kEmptyFence)); }
 
-AcquiredBuffer& AcquiredBuffer::operator=(AcquiredBuffer&& other) {
+AcquiredBuffer& AcquiredBuffer::operator=(AcquiredBuffer&& other) noexcept {
   if (this != &other) {
     Release();
 
diff --git a/libs/vr/libvrflinger/acquired_buffer.h b/libs/vr/libvrflinger/acquired_buffer.h
index 32e912a..1a200aa 100644
--- a/libs/vr/libvrflinger/acquired_buffer.h
+++ b/libs/vr/libvrflinger/acquired_buffer.h
@@ -31,7 +31,7 @@
   AcquiredBuffer(const std::shared_ptr<BufferConsumer>& buffer, int* error);
 
   // Move constructor. Behaves similarly to the move assignment operator below.
-  AcquiredBuffer(AcquiredBuffer&& other);
+  AcquiredBuffer(AcquiredBuffer&& other) noexcept;
 
   ~AcquiredBuffer();
 
@@ -39,7 +39,7 @@
   // |other| into this instance after RELEASING the current BufferConsumer and
   // closing the acquire fence. After the move |other| is left in the empty
   // state.
-  AcquiredBuffer& operator=(AcquiredBuffer&& other);
+  AcquiredBuffer& operator=(AcquiredBuffer&& other) noexcept;
 
   // Accessors for the underlying BufferConsumer, the acquire fence, and the
   // use-case specific sequence value from the acquisition (see
diff --git a/libs/vr/libvrflinger/hardware_composer.cpp b/libs/vr/libvrflinger/hardware_composer.cpp
index e98d592..5f6455c 100644
--- a/libs/vr/libvrflinger/hardware_composer.cpp
+++ b/libs/vr/libvrflinger/hardware_composer.cpp
@@ -1338,9 +1338,9 @@
 
 Layer::~Layer() { Reset(); }
 
-Layer::Layer(Layer&& other) { *this = std::move(other); }
+Layer::Layer(Layer&& other) noexcept { *this = std::move(other); }
 
-Layer& Layer::operator=(Layer&& other) {
+Layer& Layer::operator=(Layer&& other) noexcept {
   if (this != &other) {
     Reset();
     using std::swap;
diff --git a/libs/vr/libvrflinger/hardware_composer.h b/libs/vr/libvrflinger/hardware_composer.h
index 80fa7ac..94a2337 100644
--- a/libs/vr/libvrflinger/hardware_composer.h
+++ b/libs/vr/libvrflinger/hardware_composer.h
@@ -87,8 +87,8 @@
         const std::shared_ptr<IonBuffer>& buffer, HWC::BlendMode blending,
         HWC::Composition composition_type, size_t z_order);
 
-  Layer(Layer&&);
-  Layer& operator=(Layer&&);
+  Layer(Layer&&) noexcept;
+  Layer& operator=(Layer&&) noexcept;
 
   ~Layer();
 
diff --git a/libs/vr/libvrflinger/tests/vrflinger_test.cpp b/libs/vr/libvrflinger/tests/vrflinger_test.cpp
index e1c7adb..1d5740f 100644
--- a/libs/vr/libvrflinger/tests/vrflinger_test.cpp
+++ b/libs/vr/libvrflinger/tests/vrflinger_test.cpp
@@ -218,10 +218,7 @@
 
     ASSERT_GE(buffer.get()->Unlock(), 0);
 
-    ASSERT_GE(buffer.get()->Post(/*ready_fence=*/pdx::LocalHandle(),
-                                 /*meta=*/nullptr,
-                                 /*user_metadata_size=*/0),
-              0);
+    ASSERT_GE(buffer.get()->Post(/*ready_fence=*/pdx::LocalHandle()), 0);
 
     ASSERT_EQ(
         surface_flinger_connection->WaitForVrFlinger(/*wait_active=*/true),
diff --git a/libs/vr/libvrsensor/pose_client.cpp b/libs/vr/libvrsensor/pose_client.cpp
index 4acc085..710d75a 100644
--- a/libs/vr/libvrsensor/pose_client.cpp
+++ b/libs/vr/libvrsensor/pose_client.cpp
@@ -228,7 +228,7 @@
     }
     constexpr size_t size = DvrVsyncPoseBuffer::kSize * sizeof(DvrPoseAsync);
     void* addr = nullptr;
-    int ret = buffer->GetBlobReadOnlyPointer(size, &addr);
+    int ret = buffer->GetBlobReadWritePointer(size, &addr);
     if (ret < 0 || !addr) {
       ALOGE("Pose failed to map ring buffer: ret:%d, addr:%p", ret, addr);
       return -EIO;
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index 1421a48..87f0fe1 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -273,6 +273,7 @@
 
 void Loader::init_api(void* dso,
         char const * const * api,
+        char const * const * ref_api,
         __eglMustCastToProperFunctionPointerType* curr,
         getProcAddressType getProcAddress)
 {
@@ -282,6 +283,15 @@
     char scrap[SIZE];
     while (*api) {
         char const * name = *api;
+        if (ref_api) {
+            char const * ref_name = *ref_api;
+            if (std::strcmp(name, ref_name) != 0) {
+                *curr++ = nullptr;
+                ref_api++;
+                continue;
+            }
+        }
+
         __eglMustCastToProperFunctionPointerType f =
             (__eglMustCastToProperFunctionPointerType)dlsym(dso, name);
         if (f == nullptr) {
@@ -326,6 +336,7 @@
         }
         *curr++ = f;
         api++;
+        if (ref_api) ref_api++;
     }
 }
 
@@ -529,7 +540,7 @@
         property_get("ro.product.model", model, "UNSET");
         ANGLEPreference app_preference = getAnglePref(android_getAngleAppPref());
 
-        so = load_angle_from_namespace("GLESv2", ns);
+        so = load_angle_from_namespace("feature_support", ns);
         if (so) {
             ALOGV("Temporarily loaded ANGLE's opt-in/out logic from namespace");
             fpANGLEUseForApplication fp =
@@ -538,6 +549,8 @@
                 use_angle = (fp)(app_name_str.c_str(), manufacturer, model, developer_option,
                                  app_preference);
                 ALOGV("Result of opt-in/out logic is %s", use_angle ? "true" : "false");
+            } else {
+                ALOGW("Cannot find ANGLEUseForApplication in library");
             }
 
             ALOGV("Close temporarily-loaded ANGLE opt-in/out logic");
@@ -648,14 +661,14 @@
     }
 
     if (mask & GLESv1_CM) {
-        init_api(dso, gl_names,
+        init_api(dso, gl_names_1, gl_names,
             (__eglMustCastToProperFunctionPointerType*)
                 &cnx->hooks[egl_connection_t::GLESv1_INDEX]->gl,
             getProcAddress);
     }
 
     if (mask & GLESv2) {
-      init_api(dso, gl_names,
+        init_api(dso, gl_names, nullptr,
             (__eglMustCastToProperFunctionPointerType*)
                 &cnx->hooks[egl_connection_t::GLESv2_INDEX]->gl,
             getProcAddress);
diff --git a/opengl/libs/EGL/Loader.h b/opengl/libs/EGL/Loader.h
index 6a32bb3..e88d1a2 100644
--- a/opengl/libs/EGL/Loader.h
+++ b/opengl/libs/EGL/Loader.h
@@ -29,7 +29,7 @@
 
 class Loader {
     typedef __eglMustCastToProperFunctionPointerType (* getProcAddressType)(const char*);
-   
+
     enum {
         EGL         = 0x01,
         GLESv1_CM   = 0x02,
@@ -42,25 +42,26 @@
         int set(void* hnd, int32_t api);
         void* dso[3];
     };
-    
+
     getProcAddressType getProcAddress;
 
 public:
     static Loader& getInstance();
     ~Loader();
-    
+
     void* open(egl_connection_t* cnx);
     void close(void* driver);
-    
+
 private:
     Loader();
     void *load_driver(const char* kind, egl_connection_t* cnx, uint32_t mask);
 
     static __attribute__((noinline))
-    void init_api(void* dso, 
-            char const * const * api, 
-            __eglMustCastToProperFunctionPointerType* curr, 
-            getProcAddressType getProcAddress); 
+    void init_api(void* dso,
+            char const * const * api,
+            char const * const * ref_api,
+            __eglMustCastToProperFunctionPointerType* curr,
+            getProcAddressType getProcAddress);
 };
 
 // ----------------------------------------------------------------------------
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index e292b80..7089860 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -252,6 +252,11 @@
     nullptr
 };
 
+char const * const gl_names_1[] = {
+    #include "../entries_gles1.in"
+    nullptr
+};
+
 char const * const egl_names[] = {
     #include "egl_entries.in"
     nullptr
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 1ed9850..d2dc514 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -562,6 +562,15 @@
                     break;
                 }
             }
+
+            // If the driver doesn't understand it, we should map sRGB-encoded P3 to
+            // sRGB rather than just dropping the colorspace on the floor.
+            // For this format, the driver is expected to apply the sRGB
+            // transfer function during framebuffer operations.
+            if (!copyAttribute && attr[1] == EGL_GL_COLORSPACE_DISPLAY_P3_EXT) {
+                strippedAttribList->push_back(attr[0]);
+                strippedAttribList->push_back(EGL_GL_COLORSPACE_SRGB_KHR);
+            }
         }
         if (copyAttribute) {
             strippedAttribList->push_back(attr[0]);
diff --git a/opengl/libs/EGL/egldefs.h b/opengl/libs/EGL/egldefs.h
index 4990af6..449ffc7 100644
--- a/opengl/libs/EGL/egldefs.h
+++ b/opengl/libs/EGL/egldefs.h
@@ -62,6 +62,7 @@
 extern "C" void gl_noop();
 
 extern char const * const gl_names[];
+extern char const * const gl_names_1[];
 extern char const * const egl_names[];
 
 extern egl_connection_t gEGLImpl;
diff --git a/opengl/libs/entries_gles1.in b/opengl/libs/entries_gles1.in
new file mode 100644
index 0000000..c9be593
--- /dev/null
+++ b/opengl/libs/entries_gles1.in
@@ -0,0 +1,298 @@
+GL_ENTRY(void, glActiveTexture, GLenum texture)
+GL_ENTRY(void, glAlphaFunc, GLenum func, GLfloat ref)
+GL_ENTRY(void, glAlphaFuncx, GLenum func, GLfixed ref)
+GL_ENTRY(void, glAlphaFuncxOES, GLenum func, GLfixed ref)
+GL_ENTRY(void, glBindBuffer, GLenum target, GLuint buffer)
+GL_ENTRY(void, glBindFramebufferOES, GLenum target, GLuint framebuffer)
+GL_ENTRY(void, glBindRenderbufferOES, GLenum target, GLuint renderbuffer)
+GL_ENTRY(void, glBindTexture, GLenum target, GLuint texture)
+GL_ENTRY(void, glBindVertexArrayOES, GLuint array)
+GL_ENTRY(void, glBlendEquationOES, GLenum mode)
+GL_ENTRY(void, glBlendEquationSeparateOES, GLenum modeRGB, GLenum modeAlpha)
+GL_ENTRY(void, glBlendFunc, GLenum sfactor, GLenum dfactor)
+GL_ENTRY(void, glBlendFuncSeparateOES, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha)
+GL_ENTRY(void, glBufferData, GLenum target, GLsizeiptr size, const void *data, GLenum usage)
+GL_ENTRY(void, glBufferSubData, GLenum target, GLintptr offset, GLsizeiptr size, const void *data)
+GL_ENTRY(GLenum, glCheckFramebufferStatusOES, GLenum target)
+GL_ENTRY(void, glClear, GLbitfield mask)
+GL_ENTRY(void, glClearColor, GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)
+GL_ENTRY(void, glClearColorx, GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha)
+GL_ENTRY(void, glClearColorxOES, GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha)
+GL_ENTRY(void, glClearDepthf, GLfloat d)
+GL_ENTRY(void, glClearDepthfOES, GLclampf depth)
+GL_ENTRY(void, glClearDepthx, GLfixed depth)
+GL_ENTRY(void, glClearDepthxOES, GLfixed depth)
+GL_ENTRY(void, glClearStencil, GLint s)
+GL_ENTRY(void, glClientActiveTexture, GLenum texture)
+GL_ENTRY(GLenum, glClientWaitSyncAPPLE, GLsync sync, GLbitfield flags, GLuint64 timeout)
+GL_ENTRY(void, glClipPlanef, GLenum p, const GLfloat *eqn)
+GL_ENTRY(void, glClipPlanefIMG, GLenum p, const GLfloat *eqn)
+GL_ENTRY(void, glClipPlanefOES, GLenum plane, const GLfloat *equation)
+GL_ENTRY(void, glClipPlanex, GLenum plane, const GLfixed *equation)
+GL_ENTRY(void, glClipPlanexIMG, GLenum p, const GLfixed *eqn)
+GL_ENTRY(void, glClipPlanexOES, GLenum plane, const GLfixed *equation)
+GL_ENTRY(void, glColor4f, GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)
+GL_ENTRY(void, glColor4ub, GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha)
+GL_ENTRY(void, glColor4x, GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha)
+GL_ENTRY(void, glColor4xOES, GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha)
+GL_ENTRY(void, glColorMask, GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)
+GL_ENTRY(void, glColorPointer, GLint size, GLenum type, GLsizei stride, const void *pointer)
+GL_ENTRY(void, glCompressedTexImage2D, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data)
+GL_ENTRY(void, glCompressedTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data)
+GL_ENTRY(void, glCopyTexImage2D, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border)
+GL_ENTRY(void, glCopyTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height)
+GL_ENTRY(void, glCopyTextureLevelsAPPLE, GLuint destinationTexture, GLuint sourceTexture, GLint sourceBaseLevel, GLsizei sourceLevelCount)
+GL_ENTRY(void, glCullFace, GLenum mode)
+GL_ENTRY(void, glCurrentPaletteMatrixOES, GLuint matrixpaletteindex)
+GL_ENTRY(void, glDeleteBuffers, GLsizei n, const GLuint *buffers)
+GL_ENTRY(void, glDeleteFencesNV, GLsizei n, const GLuint *fences)
+GL_ENTRY(void, glDeleteFramebuffersOES, GLsizei n, const GLuint *framebuffers)
+GL_ENTRY(void, glDeleteRenderbuffersOES, GLsizei n, const GLuint *renderbuffers)
+GL_ENTRY(void, glDeleteSyncAPPLE, GLsync sync)
+GL_ENTRY(void, glDeleteTextures, GLsizei n, const GLuint *textures)
+GL_ENTRY(void, glDeleteVertexArraysOES, GLsizei n, const GLuint *arrays)
+GL_ENTRY(void, glDepthFunc, GLenum func)
+GL_ENTRY(void, glDepthMask, GLboolean flag)
+GL_ENTRY(void, glDepthRangef, GLfloat n, GLfloat f)
+GL_ENTRY(void, glDepthRangefOES, GLclampf n, GLclampf f)
+GL_ENTRY(void, glDepthRangex, GLfixed n, GLfixed f)
+GL_ENTRY(void, glDepthRangexOES, GLfixed n, GLfixed f)
+GL_ENTRY(void, glDisable, GLenum cap)
+GL_ENTRY(void, glDisableClientState, GLenum array)
+GL_ENTRY(void, glDisableDriverControlQCOM, GLuint driverControl)
+GL_ENTRY(void, glDiscardFramebufferEXT, GLenum target, GLsizei numAttachments, const GLenum *attachments)
+GL_ENTRY(void, glDrawArrays, GLenum mode, GLint first, GLsizei count)
+GL_ENTRY(void, glDrawElements, GLenum mode, GLsizei count, GLenum type, const void *indices)
+GL_ENTRY(void, glDrawTexfOES, GLfloat x, GLfloat y, GLfloat z, GLfloat width, GLfloat height)
+GL_ENTRY(void, glDrawTexfvOES, const GLfloat *coords)
+GL_ENTRY(void, glDrawTexiOES, GLint x, GLint y, GLint z, GLint width, GLint height)
+GL_ENTRY(void, glDrawTexivOES, const GLint *coords)
+GL_ENTRY(void, glDrawTexsOES, GLshort x, GLshort y, GLshort z, GLshort width, GLshort height)
+GL_ENTRY(void, glDrawTexsvOES, const GLshort *coords)
+GL_ENTRY(void, glDrawTexxOES, GLfixed x, GLfixed y, GLfixed z, GLfixed width, GLfixed height)
+GL_ENTRY(void, glDrawTexxvOES, const GLfixed *coords)
+GL_ENTRY(void, glEGLImageTargetRenderbufferStorageOES, GLenum target, GLeglImageOES image)
+GL_ENTRY(void, glEGLImageTargetTexture2DOES, GLenum target, GLeglImageOES image)
+GL_ENTRY(void, glEnable, GLenum cap)
+GL_ENTRY(void, glEnableClientState, GLenum array)
+GL_ENTRY(void, glEnableDriverControlQCOM, GLuint driverControl)
+GL_ENTRY(void, glEndTilingQCOM, GLbitfield preserveMask)
+GL_ENTRY(void, glExtGetBufferPointervQCOM, GLenum target, void **params)
+GL_ENTRY(void, glExtGetBuffersQCOM, GLuint *buffers, GLint maxBuffers, GLint *numBuffers)
+GL_ENTRY(void, glExtGetFramebuffersQCOM, GLuint *framebuffers, GLint maxFramebuffers, GLint *numFramebuffers)
+GL_ENTRY(void, glExtGetProgramBinarySourceQCOM, GLuint program, GLenum shadertype, GLchar *source, GLint *length)
+GL_ENTRY(void, glExtGetProgramsQCOM, GLuint *programs, GLint maxPrograms, GLint *numPrograms)
+GL_ENTRY(void, glExtGetRenderbuffersQCOM, GLuint *renderbuffers, GLint maxRenderbuffers, GLint *numRenderbuffers)
+GL_ENTRY(void, glExtGetShadersQCOM, GLuint *shaders, GLint maxShaders, GLint *numShaders)
+GL_ENTRY(void, glExtGetTexLevelParameterivQCOM, GLuint texture, GLenum face, GLint level, GLenum pname, GLint *params)
+GL_ENTRY(void, glExtGetTexSubImageQCOM, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, void *texels)
+GL_ENTRY(void, glExtGetTexturesQCOM, GLuint *textures, GLint maxTextures, GLint *numTextures)
+GL_ENTRY(GLboolean, glExtIsProgramBinaryQCOM, GLuint program)
+GL_ENTRY(void, glExtTexObjectStateOverrideiQCOM, GLenum target, GLenum pname, GLint param)
+GL_ENTRY(GLsync, glFenceSyncAPPLE, GLenum condition, GLbitfield flags)
+GL_ENTRY(void, glFinish, void)
+GL_ENTRY(void, glFinishFenceNV, GLuint fence)
+GL_ENTRY(void, glFlush, void)
+GL_ENTRY(void, glFlushMappedBufferRangeEXT, GLenum target, GLintptr offset, GLsizeiptr length)
+GL_ENTRY(void, glFogf, GLenum pname, GLfloat param)
+GL_ENTRY(void, glFogfv, GLenum pname, const GLfloat *params)
+GL_ENTRY(void, glFogx, GLenum pname, GLfixed param)
+GL_ENTRY(void, glFogxOES, GLenum pname, GLfixed param)
+GL_ENTRY(void, glFogxv, GLenum pname, const GLfixed *param)
+GL_ENTRY(void, glFogxvOES, GLenum pname, const GLfixed *param)
+GL_ENTRY(void, glFramebufferRenderbufferOES, GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
+GL_ENTRY(void, glFramebufferTexture2DMultisampleEXT, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples)
+GL_ENTRY(void, glFramebufferTexture2DMultisampleIMG, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples)
+GL_ENTRY(void, glFramebufferTexture2DOES, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
+GL_ENTRY(void, glFrontFace, GLenum mode)
+GL_ENTRY(void, glFrustumf, GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f)
+GL_ENTRY(void, glFrustumfOES, GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f)
+GL_ENTRY(void, glFrustumx, GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f)
+GL_ENTRY(void, glFrustumxOES, GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f)
+GL_ENTRY(void, glGenBuffers, GLsizei n, GLuint *buffers)
+GL_ENTRY(void, glGenFencesNV, GLsizei n, GLuint *fences)
+GL_ENTRY(void, glGenFramebuffersOES, GLsizei n, GLuint *framebuffers)
+GL_ENTRY(void, glGenRenderbuffersOES, GLsizei n, GLuint *renderbuffers)
+GL_ENTRY(void, glGenTextures, GLsizei n, GLuint *textures)
+GL_ENTRY(void, glGenVertexArraysOES, GLsizei n, GLuint *arrays)
+GL_ENTRY(void, glGenerateMipmapOES, GLenum target)
+GL_ENTRY(void, glGetBooleanv, GLenum pname, GLboolean *data)
+GL_ENTRY(void, glGetBufferParameteriv, GLenum target, GLenum pname, GLint *params)
+GL_ENTRY(void, glGetBufferPointervOES, GLenum target, GLenum pname, void **params)
+GL_ENTRY(void, glGetClipPlanef, GLenum plane, GLfloat *equation)
+GL_ENTRY(void, glGetClipPlanefOES, GLenum plane, GLfloat *equation)
+GL_ENTRY(void, glGetClipPlanex, GLenum plane, GLfixed *equation)
+GL_ENTRY(void, glGetClipPlanexOES, GLenum plane, GLfixed *equation)
+GL_ENTRY(void, glGetDriverControlStringQCOM, GLuint driverControl, GLsizei bufSize, GLsizei *length, GLchar *driverControlString)
+GL_ENTRY(void, glGetDriverControlsQCOM, GLint *num, GLsizei size, GLuint *driverControls)
+GL_ENTRY(GLenum, glGetError, void)
+GL_ENTRY(void, glGetFenceivNV, GLuint fence, GLenum pname, GLint *params)
+GL_ENTRY(void, glGetFixedv, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetFixedvOES, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetFloatv, GLenum pname, GLfloat *data)
+GL_ENTRY(void, glGetFramebufferAttachmentParameterivOES, GLenum target, GLenum attachment, GLenum pname, GLint *params)
+GL_ENTRY(GLenum, glGetGraphicsResetStatusEXT, void)
+GL_ENTRY(void, glGetInteger64vAPPLE, GLenum pname, GLint64 *params)
+GL_ENTRY(void, glGetIntegerv, GLenum pname, GLint *data)
+GL_ENTRY(void, glGetLightfv, GLenum light, GLenum pname, GLfloat *params)
+GL_ENTRY(void, glGetLightxv, GLenum light, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetLightxvOES, GLenum light, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetMaterialfv, GLenum face, GLenum pname, GLfloat *params)
+GL_ENTRY(void, glGetMaterialxv, GLenum face, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetMaterialxvOES, GLenum face, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetPointerv, GLenum pname, void **params)
+GL_ENTRY(void, glGetRenderbufferParameterivOES, GLenum target, GLenum pname, GLint *params)
+GL_ENTRY(const GLubyte *, glGetString, GLenum name)
+GL_ENTRY(void, glGetSyncivAPPLE, GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values)
+GL_ENTRY(void, glGetTexEnvfv, GLenum target, GLenum pname, GLfloat *params)
+GL_ENTRY(void, glGetTexEnviv, GLenum target, GLenum pname, GLint *params)
+GL_ENTRY(void, glGetTexEnvxv, GLenum target, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetTexEnvxvOES, GLenum target, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetTexGenfvOES, GLenum coord, GLenum pname, GLfloat *params)
+GL_ENTRY(void, glGetTexGenivOES, GLenum coord, GLenum pname, GLint *params)
+GL_ENTRY(void, glGetTexGenxvOES, GLenum coord, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetTexParameterfv, GLenum target, GLenum pname, GLfloat *params)
+GL_ENTRY(void, glGetTexParameteriv, GLenum target, GLenum pname, GLint *params)
+GL_ENTRY(void, glGetTexParameterxv, GLenum target, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetTexParameterxvOES, GLenum target, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetnUniformfvEXT, GLuint program, GLint location, GLsizei bufSize, GLfloat *params)
+GL_ENTRY(void, glGetnUniformivEXT, GLuint program, GLint location, GLsizei bufSize, GLint *params)
+GL_ENTRY(void, glHint, GLenum target, GLenum mode)
+GL_ENTRY(void, glInsertEventMarkerEXT, GLsizei length, const GLchar *marker)
+GL_ENTRY(GLboolean, glIsBuffer, GLuint buffer)
+GL_ENTRY(GLboolean, glIsEnabled, GLenum cap)
+GL_ENTRY(GLboolean, glIsFenceNV, GLuint fence)
+GL_ENTRY(GLboolean, glIsFramebufferOES, GLuint framebuffer)
+GL_ENTRY(GLboolean, glIsRenderbufferOES, GLuint renderbuffer)
+GL_ENTRY(GLboolean, glIsSyncAPPLE, GLsync sync)
+GL_ENTRY(GLboolean, glIsTexture, GLuint texture)
+GL_ENTRY(GLboolean, glIsVertexArrayOES, GLuint array)
+GL_ENTRY(void, glLightModelf, GLenum pname, GLfloat param)
+GL_ENTRY(void, glLightModelfv, GLenum pname, const GLfloat *params)
+GL_ENTRY(void, glLightModelx, GLenum pname, GLfixed param)
+GL_ENTRY(void, glLightModelxOES, GLenum pname, GLfixed param)
+GL_ENTRY(void, glLightModelxv, GLenum pname, const GLfixed *param)
+GL_ENTRY(void, glLightModelxvOES, GLenum pname, const GLfixed *param)
+GL_ENTRY(void, glLightf, GLenum light, GLenum pname, GLfloat param)
+GL_ENTRY(void, glLightfv, GLenum light, GLenum pname, const GLfloat *params)
+GL_ENTRY(void, glLightx, GLenum light, GLenum pname, GLfixed param)
+GL_ENTRY(void, glLightxOES, GLenum light, GLenum pname, GLfixed param)
+GL_ENTRY(void, glLightxv, GLenum light, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glLightxvOES, GLenum light, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glLineWidth, GLfloat width)
+GL_ENTRY(void, glLineWidthx, GLfixed width)
+GL_ENTRY(void, glLineWidthxOES, GLfixed width)
+GL_ENTRY(void, glLoadIdentity, void)
+GL_ENTRY(void, glLoadMatrixf, const GLfloat *m)
+GL_ENTRY(void, glLoadMatrixx, const GLfixed *m)
+GL_ENTRY(void, glLoadMatrixxOES, const GLfixed *m)
+GL_ENTRY(void, glLoadPaletteFromModelViewMatrixOES, void)
+GL_ENTRY(void, glLogicOp, GLenum opcode)
+GL_ENTRY(void *, glMapBufferOES, GLenum target, GLenum access)
+GL_ENTRY(void *, glMapBufferRangeEXT, GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access)
+GL_ENTRY(void, glMaterialf, GLenum face, GLenum pname, GLfloat param)
+GL_ENTRY(void, glMaterialfv, GLenum face, GLenum pname, const GLfloat *params)
+GL_ENTRY(void, glMaterialx, GLenum face, GLenum pname, GLfixed param)
+GL_ENTRY(void, glMaterialxOES, GLenum face, GLenum pname, GLfixed param)
+GL_ENTRY(void, glMaterialxv, GLenum face, GLenum pname, const GLfixed *param)
+GL_ENTRY(void, glMaterialxvOES, GLenum face, GLenum pname, const GLfixed *param)
+GL_ENTRY(void, glMatrixIndexPointerOES, GLint size, GLenum type, GLsizei stride, const void *pointer)
+GL_ENTRY(void, glMatrixMode, GLenum mode)
+GL_ENTRY(void, glMultMatrixf, const GLfloat *m)
+GL_ENTRY(void, glMultMatrixx, const GLfixed *m)
+GL_ENTRY(void, glMultMatrixxOES, const GLfixed *m)
+GL_ENTRY(void, glMultiDrawArraysEXT, GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount)
+GL_ENTRY(void, glMultiDrawElementsEXT, GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount)
+GL_ENTRY(void, glMultiTexCoord4f, GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q)
+GL_ENTRY(void, glMultiTexCoord4x, GLenum texture, GLfixed s, GLfixed t, GLfixed r, GLfixed q)
+GL_ENTRY(void, glMultiTexCoord4xOES, GLenum texture, GLfixed s, GLfixed t, GLfixed r, GLfixed q)
+GL_ENTRY(void, glNormal3f, GLfloat nx, GLfloat ny, GLfloat nz)
+GL_ENTRY(void, glNormal3x, GLfixed nx, GLfixed ny, GLfixed nz)
+GL_ENTRY(void, glNormal3xOES, GLfixed nx, GLfixed ny, GLfixed nz)
+GL_ENTRY(void, glNormalPointer, GLenum type, GLsizei stride, const void *pointer)
+GL_ENTRY(void, glOrthof, GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f)
+GL_ENTRY(void, glOrthofOES, GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f)
+GL_ENTRY(void, glOrthox, GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f)
+GL_ENTRY(void, glOrthoxOES, GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f)
+GL_ENTRY(void, glPixelStorei, GLenum pname, GLint param)
+GL_ENTRY(void, glPointParameterf, GLenum pname, GLfloat param)
+GL_ENTRY(void, glPointParameterfv, GLenum pname, const GLfloat *params)
+GL_ENTRY(void, glPointParameterx, GLenum pname, GLfixed param)
+GL_ENTRY(void, glPointParameterxOES, GLenum pname, GLfixed param)
+GL_ENTRY(void, glPointParameterxv, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glPointParameterxvOES, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glPointSize, GLfloat size)
+GL_ENTRY(void, glPointSizePointerOES, GLenum type, GLsizei stride, const void *pointer)
+GL_ENTRY(void, glPointSizex, GLfixed size)
+GL_ENTRY(void, glPointSizexOES, GLfixed size)
+GL_ENTRY(void, glPolygonOffset, GLfloat factor, GLfloat units)
+GL_ENTRY(void, glPolygonOffsetx, GLfixed factor, GLfixed units)
+GL_ENTRY(void, glPolygonOffsetxOES, GLfixed factor, GLfixed units)
+GL_ENTRY(void, glPopGroupMarkerEXT, void)
+GL_ENTRY(void, glPopMatrix, void)
+GL_ENTRY(void, glPushGroupMarkerEXT, GLsizei length, const GLchar *marker)
+GL_ENTRY(void, glPushMatrix, void)
+GL_ENTRY(GLbitfield, glQueryMatrixxOES, GLfixed *mantissa, GLint *exponent)
+GL_ENTRY(void, glReadPixels, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels)
+GL_ENTRY(void, glReadnPixelsEXT, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data)
+GL_ENTRY(void, glRenderbufferStorageMultisampleAPPLE, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height)
+GL_ENTRY(void, glRenderbufferStorageMultisampleEXT, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height)
+GL_ENTRY(void, glRenderbufferStorageMultisampleIMG, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height)
+GL_ENTRY(void, glRenderbufferStorageOES, GLenum target, GLenum internalformat, GLsizei width, GLsizei height)
+GL_ENTRY(void, glResolveMultisampleFramebufferAPPLE, void)
+GL_ENTRY(void, glRotatef, GLfloat angle, GLfloat x, GLfloat y, GLfloat z)
+GL_ENTRY(void, glRotatex, GLfixed angle, GLfixed x, GLfixed y, GLfixed z)
+GL_ENTRY(void, glRotatexOES, GLfixed angle, GLfixed x, GLfixed y, GLfixed z)
+GL_ENTRY(void, glSampleCoverage, GLfloat value, GLboolean invert)
+GL_ENTRY(void, glSampleCoveragex, GLclampx value, GLboolean invert)
+GL_ENTRY(void, glSampleCoveragexOES, GLclampx value, GLboolean invert)
+GL_ENTRY(void, glScalef, GLfloat x, GLfloat y, GLfloat z)
+GL_ENTRY(void, glScalex, GLfixed x, GLfixed y, GLfixed z)
+GL_ENTRY(void, glScalexOES, GLfixed x, GLfixed y, GLfixed z)
+GL_ENTRY(void, glScissor, GLint x, GLint y, GLsizei width, GLsizei height)
+GL_ENTRY(void, glSetFenceNV, GLuint fence, GLenum condition)
+GL_ENTRY(void, glShadeModel, GLenum mode)
+GL_ENTRY(void, glStartTilingQCOM, GLuint x, GLuint y, GLuint width, GLuint height, GLbitfield preserveMask)
+GL_ENTRY(void, glStencilFunc, GLenum func, GLint ref, GLuint mask)
+GL_ENTRY(void, glStencilMask, GLuint mask)
+GL_ENTRY(void, glStencilOp, GLenum fail, GLenum zfail, GLenum zpass)
+GL_ENTRY(GLboolean, glTestFenceNV, GLuint fence)
+GL_ENTRY(void, glTexCoordPointer, GLint size, GLenum type, GLsizei stride, const void *pointer)
+GL_ENTRY(void, glTexEnvf, GLenum target, GLenum pname, GLfloat param)
+GL_ENTRY(void, glTexEnvfv, GLenum target, GLenum pname, const GLfloat *params)
+GL_ENTRY(void, glTexEnvi, GLenum target, GLenum pname, GLint param)
+GL_ENTRY(void, glTexEnviv, GLenum target, GLenum pname, const GLint *params)
+GL_ENTRY(void, glTexEnvx, GLenum target, GLenum pname, GLfixed param)
+GL_ENTRY(void, glTexEnvxOES, GLenum target, GLenum pname, GLfixed param)
+GL_ENTRY(void, glTexEnvxv, GLenum target, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glTexEnvxvOES, GLenum target, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glTexGenfOES, GLenum coord, GLenum pname, GLfloat param)
+GL_ENTRY(void, glTexGenfvOES, GLenum coord, GLenum pname, const GLfloat *params)
+GL_ENTRY(void, glTexGeniOES, GLenum coord, GLenum pname, GLint param)
+GL_ENTRY(void, glTexGenivOES, GLenum coord, GLenum pname, const GLint *params)
+GL_ENTRY(void, glTexGenxOES, GLenum coord, GLenum pname, GLfixed param)
+GL_ENTRY(void, glTexGenxvOES, GLenum coord, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glTexImage2D, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels)
+GL_ENTRY(void, glTexParameterf, GLenum target, GLenum pname, GLfloat param)
+GL_ENTRY(void, glTexParameterfv, GLenum target, GLenum pname, const GLfloat *params)
+GL_ENTRY(void, glTexParameteri, GLenum target, GLenum pname, GLint param)
+GL_ENTRY(void, glTexParameteriv, GLenum target, GLenum pname, const GLint *params)
+GL_ENTRY(void, glTexParameterx, GLenum target, GLenum pname, GLfixed param)
+GL_ENTRY(void, glTexParameterxOES, GLenum target, GLenum pname, GLfixed param)
+GL_ENTRY(void, glTexParameterxv, GLenum target, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glTexParameterxvOES, GLenum target, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glTexStorage1DEXT, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width)
+GL_ENTRY(void, glTexStorage2DEXT, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
+GL_ENTRY(void, glTexStorage3DEXT, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
+GL_ENTRY(void, glTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels)
+GL_ENTRY(void, glTextureStorage1DEXT, GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width)
+GL_ENTRY(void, glTextureStorage2DEXT, GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
+GL_ENTRY(void, glTextureStorage3DEXT, GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
+GL_ENTRY(void, glTranslatef, GLfloat x, GLfloat y, GLfloat z)
+GL_ENTRY(void, glTranslatex, GLfixed x, GLfixed y, GLfixed z)
+GL_ENTRY(void, glTranslatexOES, GLfixed x, GLfixed y, GLfixed z)
+GL_ENTRY(GLboolean, glUnmapBufferOES, GLenum target)
+GL_ENTRY(void, glVertexPointer, GLint size, GLenum type, GLsizei stride, const void *pointer)
+GL_ENTRY(void, glViewport, GLint x, GLint y, GLsizei width, GLsizei height)
+GL_ENTRY(void, glWaitSyncAPPLE, GLsync sync, GLbitfield flags, GLuint64 timeout)
+GL_ENTRY(void, glWeightPointerOES, GLint size, GLenum type, GLsizei stride, const void *pointer)
diff --git a/opengl/tools/glgen2/glgen.py b/opengl/tools/glgen2/glgen.py
index fa981a8..86fa28f 100755
--- a/opengl/tools/glgen2/glgen.py
+++ b/opengl/tools/glgen2/glgen.py
@@ -250,6 +250,27 @@
     for opts in TRAMPOLINE_OPTIONS:
         registry.apiGen(opts)
 
+    # Generate a GLESv1_CM entries separately to avoid extra driver loading time
+    apigen = ApiGenerator()
+    registry.setGenerator(apigen)
+    API_OPTIONS = [
+        # Generate non-extension versions of each API first, then extensions,
+        # so that if an extension enum was later standardized, we see the non-
+        # suffixed version first.
+        reg.GeneratorOptions(
+            apiname             = 'gles1',
+            profile             = 'common'),
+        reg.GeneratorOptions(
+            apiname             = 'gles1',
+            profile             = 'common',
+            emitversions        = None,
+            defaultExtensions   = 'gles1')]
+    for opts in API_OPTIONS:
+        registry.apiGen(opts)
+    apigen.finish()
+    with open('../../libs/entries_gles1.in', 'w') as f:
+        apigen.writeEntries(f)
+
     apigen = ApiGenerator()
     registry.setGenerator(apigen)
     API_OPTIONS = [
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index 45efb9f..9a65452 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -19,12 +19,10 @@
 
     srcs: [
         "EventHub.cpp",
-        "InputApplication.cpp",
         "InputDispatcher.cpp",
         "InputListener.cpp",
         "InputManager.cpp",
         "InputReader.cpp",
-        "InputWindow.cpp",
     ],
 
     shared_libs: [
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index d609573..38104c4 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -235,6 +235,12 @@
     }
 }
 
+template<typename T, typename U>
+static T getValueByKey(std::unordered_map<U, T>& map, U key) {
+    typename std::unordered_map<U, T>::const_iterator it = map.find(key);
+    return it != map.end() ? it->second : T{};
+}
+
 
 // --- InputDispatcher ---
 
@@ -244,6 +250,7 @@
     mAppSwitchSawKeyDown(false), mAppSwitchDueTime(LONG_LONG_MAX),
     mNextUnblockedEvent(nullptr),
     mDispatchEnabled(false), mDispatchFrozen(false), mInputFilterEnabled(false),
+    mFocusedDisplayId(ADISPLAY_ID_DEFAULT),
     mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) {
     mLooper = new Looper(false);
 
@@ -808,8 +815,10 @@
         if (entry->policyFlags & POLICY_FLAG_PASS_TO_USER) {
             CommandEntry* commandEntry = postCommandLocked(
                     & InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible);
-            if (mFocusedWindowHandle != nullptr) {
-                commandEntry->inputWindowHandle = mFocusedWindowHandle;
+            sp<InputWindowHandle> focusedWindowHandle =
+                    getValueByKey(mFocusedWindowHandlesByDisplay, getTargetDisplayId(entry));
+            if (focusedWindowHandle != nullptr) {
+                commandEntry->inputWindowHandle = focusedWindowHandle;
             }
             commandEntry->keyEntry = entry;
             entry->refCount += 1;
@@ -1108,17 +1117,49 @@
     mInputTargetWaitApplicationHandle.clear();
 }
 
+/**
+ * Get the display id that the given event should go to. If this event specifies a valid display id,
+ * then it should be dispatched to that display. Otherwise, the event goes to the focused display.
+ * Focused display is the display that the user most recently interacted with.
+ */
+int32_t InputDispatcher::getTargetDisplayId(const EventEntry* entry) {
+    int32_t displayId;
+    switch (entry->type) {
+    case EventEntry::TYPE_KEY: {
+        const KeyEntry* typedEntry = static_cast<const KeyEntry*>(entry);
+        displayId = typedEntry->displayId;
+        break;
+    }
+    case EventEntry::TYPE_MOTION: {
+        const MotionEntry* typedEntry = static_cast<const MotionEntry*>(entry);
+        displayId = typedEntry->displayId;
+        break;
+    }
+    default: {
+        ALOGE("Unsupported event type '%" PRId32 "' for target display.", entry->type);
+        return ADISPLAY_ID_NONE;
+    }
+    }
+    return displayId == ADISPLAY_ID_NONE ? mFocusedDisplayId : displayId;
+}
+
 int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime,
         const EventEntry* entry, Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime) {
     int32_t injectionResult;
     std::string reason;
 
+    int32_t displayId = getTargetDisplayId(entry);
+    sp<InputWindowHandle> focusedWindowHandle =
+            getValueByKey(mFocusedWindowHandlesByDisplay, displayId);
+    sp<InputApplicationHandle> focusedApplicationHandle =
+            getValueByKey(mFocusedApplicationHandlesByDisplay, displayId);
+
     // If there is no currently focused window and no focused application
     // then drop the event.
-    if (mFocusedWindowHandle == nullptr) {
-        if (mFocusedApplicationHandle != nullptr) {
+    if (focusedWindowHandle == nullptr) {
+        if (focusedApplicationHandle != nullptr) {
             injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
-                    mFocusedApplicationHandle, nullptr, nextWakeupTime,
+                    focusedApplicationHandle, nullptr, nextWakeupTime,
                     "Waiting because no window has focus but there is a "
                     "focused application that may eventually add a window "
                     "when it finishes starting up.");
@@ -1131,23 +1172,23 @@
     }
 
     // Check permissions.
-    if (! checkInjectionPermission(mFocusedWindowHandle, entry->injectionState)) {
+    if (!checkInjectionPermission(focusedWindowHandle, entry->injectionState)) {
         injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED;
         goto Failed;
     }
 
     // Check whether the window is ready for more input.
     reason = checkWindowReadyForMoreInputLocked(currentTime,
-            mFocusedWindowHandle, entry, "focused");
+            focusedWindowHandle, entry, "focused");
     if (!reason.empty()) {
         injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
-                mFocusedApplicationHandle, mFocusedWindowHandle, nextWakeupTime, reason.c_str());
+                focusedApplicationHandle, focusedWindowHandle, nextWakeupTime, reason.c_str());
         goto Unresponsive;
     }
 
     // Success!  Output targets.
     injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED;
-    addWindowTargetLocked(mFocusedWindowHandle,
+    addWindowTargetLocked(focusedWindowHandle,
             InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS, BitSet32(0),
             inputTargets);
 
@@ -1802,8 +1843,11 @@
 }
 
 void InputDispatcher::pokeUserActivityLocked(const EventEntry* eventEntry) {
-    if (mFocusedWindowHandle != nullptr) {
-        const InputWindowInfo* info = mFocusedWindowHandle->getInfo();
+    int32_t displayId = getTargetDisplayId(eventEntry);
+    sp<InputWindowHandle> focusedWindowHandle =
+            getValueByKey(mFocusedWindowHandlesByDisplay, displayId);
+    if (focusedWindowHandle != nullptr) {
+        const InputWindowInfo* info = focusedWindowHandle->getInfo();
         if (info->inputFeatures & InputWindowInfo::INPUT_FEATURE_DISABLE_USER_ACTIVITY) {
 #if DEBUG_DISPATCH_CYCLE
             ALOGD("Not poking user activity: disabled by window '%s'.", info->name.c_str());
@@ -2978,18 +3022,7 @@
         // Copy old handles for release if they are no longer present.
         const Vector<sp<InputWindowHandle>> oldWindowHandles = getWindowHandlesLocked(displayId);
 
-        // TODO(b/111361570): multi-display focus, one focus window per display.
-        sp<InputWindowHandle> newFocusedWindowHandle = mFocusedWindowHandle;
-        // Reset newFocusedWindowHandle to nullptr if current display own the focus window,
-        // that will be updated below when going through all window handles in current display.
-        // And if list of window handles becomes empty then it will be updated by other display.
-        if (mFocusedWindowHandle != nullptr) {
-            const InputWindowInfo* info = mFocusedWindowHandle->getInfo();
-            if (info == nullptr || info->displayId == displayId) {
-                newFocusedWindowHandle = nullptr;
-            }
-        }
-
+        sp<InputWindowHandle> newFocusedWindowHandle = nullptr;
         bool foundHoveredWindow = false;
 
         if (inputWindowHandles.isEmpty()) {
@@ -3026,28 +3059,31 @@
             mLastHoverWindowHandle = nullptr;
         }
 
-        // TODO(b/111361570): multi-display focus, one focus in all display in current.
-        if (mFocusedWindowHandle != newFocusedWindowHandle) {
-            if (mFocusedWindowHandle != nullptr) {
+        sp<InputWindowHandle> oldFocusedWindowHandle =
+                getValueByKey(mFocusedWindowHandlesByDisplay, displayId);
+
+        if (oldFocusedWindowHandle != newFocusedWindowHandle) {
+            if (oldFocusedWindowHandle != nullptr) {
 #if DEBUG_FOCUS
                 ALOGD("Focus left window: %s",
-                        mFocusedWindowHandle->getName().c_str());
+                        oldFocusedWindowHandle->getName().c_str());
 #endif
-                sp<InputChannel> focusedInputChannel = mFocusedWindowHandle->getInputChannel();
+                sp<InputChannel> focusedInputChannel = oldFocusedWindowHandle->getInputChannel();
                 if (focusedInputChannel != nullptr) {
                     CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS,
                             "focus left window");
                     synthesizeCancelationEventsForInputChannelLocked(
                             focusedInputChannel, options);
                 }
+                mFocusedWindowHandlesByDisplay.erase(displayId);
             }
             if (newFocusedWindowHandle != nullptr) {
 #if DEBUG_FOCUS
                 ALOGD("Focus entered window: %s",
                         newFocusedWindowHandle->getName().c_str());
 #endif
+                mFocusedWindowHandlesByDisplay[displayId] = newFocusedWindowHandle;
             }
-            mFocusedWindowHandle = newFocusedWindowHandle;
         }
 
         ssize_t stateIndex = mTouchStatesByDisplay.indexOfKey(displayId);
@@ -3096,25 +3132,28 @@
 }
 
 void InputDispatcher::setFocusedApplication(
-        const sp<InputApplicationHandle>& inputApplicationHandle) {
+        int32_t displayId, const sp<InputApplicationHandle>& inputApplicationHandle) {
 #if DEBUG_FOCUS
     ALOGD("setFocusedApplication");
 #endif
     { // acquire lock
         AutoMutex _l(mLock);
 
+        sp<InputApplicationHandle> oldFocusedApplicationHandle =
+                getValueByKey(mFocusedApplicationHandlesByDisplay, displayId);
         if (inputApplicationHandle != nullptr && inputApplicationHandle->updateInfo()) {
-            if (mFocusedApplicationHandle != inputApplicationHandle) {
-                if (mFocusedApplicationHandle != nullptr) {
+            if (oldFocusedApplicationHandle != inputApplicationHandle) {
+                if (oldFocusedApplicationHandle != nullptr) {
                     resetANRTimeoutsLocked();
-                    mFocusedApplicationHandle->releaseInfo();
+                    oldFocusedApplicationHandle->releaseInfo();
                 }
-                mFocusedApplicationHandle = inputApplicationHandle;
+                mFocusedApplicationHandlesByDisplay[displayId] = inputApplicationHandle;
             }
-        } else if (mFocusedApplicationHandle != nullptr) {
+        } else if (oldFocusedApplicationHandle != nullptr) {
             resetANRTimeoutsLocked();
-            mFocusedApplicationHandle->releaseInfo();
-            mFocusedApplicationHandle.clear();
+            oldFocusedApplicationHandle->releaseInfo();
+            oldFocusedApplicationHandle.clear();
+            mFocusedApplicationHandlesByDisplay.erase(displayId);
         }
 
 #if DEBUG_FOCUS
@@ -3126,6 +3165,62 @@
     mLooper->wake();
 }
 
+/**
+ * Sets the focused display, which is responsible for receiving focus-dispatched input events where
+ * the display not specified.
+ *
+ * We track any unreleased events for each window. If a window loses the ability to receive the
+ * released event, we will send a cancel event to it. So when the focused display is changed, we
+ * cancel all the unreleased display-unspecified events for the focused window on the old focused
+ * display. The display-specified events won't be affected.
+ */
+void InputDispatcher::setFocusedDisplay(int32_t displayId) {
+#if DEBUG_FOCUS
+    ALOGD("setFocusedDisplay displayId=%" PRId32, displayId);
+#endif
+    { // acquire lock
+        AutoMutex _l(mLock);
+
+        if (mFocusedDisplayId != displayId) {
+            sp<InputWindowHandle> oldFocusedWindowHandle =
+                    getValueByKey(mFocusedWindowHandlesByDisplay, mFocusedDisplayId);
+            if (oldFocusedWindowHandle != nullptr) {
+                sp<InputChannel> inputChannel = oldFocusedWindowHandle->getInputChannel();
+                if (inputChannel != nullptr) {
+                    CancelationOptions options(
+                            CancelationOptions::CANCEL_DISPLAY_UNSPECIFIED_EVENTS,
+                            "The display which contains this window no longer has focus.");
+                    synthesizeCancelationEventsForInputChannelLocked(inputChannel, options);
+                }
+            }
+            mFocusedDisplayId = displayId;
+
+            // Sanity check
+            sp<InputWindowHandle> newFocusedWindowHandle =
+                    getValueByKey(mFocusedWindowHandlesByDisplay, displayId);
+            if (newFocusedWindowHandle == nullptr) {
+                ALOGW("Focused display #%" PRId32 " does not have a focused window.", displayId);
+                if (!mFocusedWindowHandlesByDisplay.empty()) {
+                    ALOGE("But another display has a focused window:");
+                    for (auto& it : mFocusedWindowHandlesByDisplay) {
+                        const int32_t displayId = it.first;
+                        const sp<InputWindowHandle>& windowHandle = it.second;
+                        ALOGE("Display #%" PRId32 " has focused window: '%s'\n",
+                                displayId, windowHandle->getName().c_str());
+                    }
+                }
+            }
+        }
+
+#if DEBUG_FOCUS
+        logDispatchStateLocked();
+#endif
+    } // release lock
+
+    // Wake up poll loop since it may need to make new input dispatching choices.
+    mLooper->wake();
+}
+
 void InputDispatcher::setInputDispatchMode(bool enabled, bool frozen) {
 #if DEBUG_FOCUS
     ALOGD("setInputDispatchMode: enabled=%d, frozen=%d", enabled, frozen);
@@ -3152,7 +3247,7 @@
         }
 
 #if DEBUG_FOCUS
-        //logDispatchStateLocked();
+        logDispatchStateLocked();
 #endif
     } // release lock
 
@@ -3297,17 +3392,35 @@
 void InputDispatcher::dumpDispatchStateLocked(std::string& dump) {
     dump += StringPrintf(INDENT "DispatchEnabled: %d\n", mDispatchEnabled);
     dump += StringPrintf(INDENT "DispatchFrozen: %d\n", mDispatchFrozen);
+    dump += StringPrintf(INDENT "FocusedDisplayId: %" PRId32 "\n", mFocusedDisplayId);
 
-    if (mFocusedApplicationHandle != nullptr) {
-        dump += StringPrintf(INDENT "FocusedApplication: name='%s', dispatchingTimeout=%0.3fms\n",
-                mFocusedApplicationHandle->getName().c_str(),
-                mFocusedApplicationHandle->getDispatchingTimeout(
-                        DEFAULT_INPUT_DISPATCHING_TIMEOUT) / 1000000.0);
+    if (!mFocusedApplicationHandlesByDisplay.empty()) {
+        dump += StringPrintf(INDENT "FocusedApplications:\n");
+        for (auto& it : mFocusedApplicationHandlesByDisplay) {
+            const int32_t displayId = it.first;
+            const sp<InputApplicationHandle>& applicationHandle = it.second;
+            dump += StringPrintf(
+                    INDENT2 "displayId=%" PRId32 ", name='%s', dispatchingTimeout=%0.3fms\n",
+                    displayId,
+                    applicationHandle->getName().c_str(),
+                    applicationHandle->getDispatchingTimeout(
+                            DEFAULT_INPUT_DISPATCHING_TIMEOUT) / 1000000.0);
+        }
     } else {
-        dump += StringPrintf(INDENT "FocusedApplication: <null>\n");
+        dump += StringPrintf(INDENT "FocusedApplications: <none>\n");
     }
-    dump += StringPrintf(INDENT "FocusedWindow: name='%s'\n",
-            mFocusedWindowHandle != nullptr ? mFocusedWindowHandle->getName().c_str() : "<null>");
+
+    if (!mFocusedWindowHandlesByDisplay.empty()) {
+        dump += StringPrintf(INDENT "FocusedWindows:\n");
+        for (auto& it : mFocusedWindowHandlesByDisplay) {
+            const int32_t displayId = it.first;
+            const sp<InputWindowHandle>& windowHandle = it.second;
+            dump += StringPrintf(INDENT2 "displayId=%" PRId32 ", name='%s'\n",
+                    displayId, windowHandle->getName().c_str());
+        }
+    } else {
+        dump += StringPrintf(INDENT "FocusedWindows: <none>\n");
+    }
 
     if (!mTouchStatesByDisplay.isEmpty()) {
         dump += StringPrintf(INDENT "TouchStatesByDisplay:\n");
@@ -4527,6 +4640,8 @@
         return true;
     case CancelationOptions::CANCEL_FALLBACK_EVENTS:
         return memento.flags & AKEY_EVENT_FLAG_FALLBACK;
+    case CancelationOptions::CANCEL_DISPLAY_UNSPECIFIED_EVENTS:
+        return memento.displayId == ADISPLAY_ID_NONE;
     default:
         return false;
     }
@@ -4545,6 +4660,8 @@
         return memento.source & AINPUT_SOURCE_CLASS_POINTER;
     case CancelationOptions::CANCEL_NON_POINTER_EVENTS:
         return !(memento.source & AINPUT_SOURCE_CLASS_POINTER);
+    case CancelationOptions::CANCEL_DISPLAY_UNSPECIFIED_EVENTS:
+        return memento.displayId == ADISPLAY_ID_NONE;
     default:
         return false;
     }
diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h
index fdf75f6..aedad2f 100644
--- a/services/inputflinger/InputDispatcher.h
+++ b/services/inputflinger/InputDispatcher.h
@@ -18,7 +18,9 @@
 #define _UI_INPUT_DISPATCHER_H
 
 #include <input/Input.h>
+#include <input/InputApplication.h>
 #include <input/InputTransport.h>
+#include <input/InputWindow.h>
 #include <utils/KeyedVector.h>
 #include <utils/Vector.h>
 #include <utils/threads.h>
@@ -33,8 +35,6 @@
 #include <limits.h>
 #include <unordered_map>
 
-#include "InputWindow.h"
-#include "InputApplication.h"
 #include "InputListener.h"
 
 
@@ -311,12 +311,18 @@
     virtual void setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles,
             int32_t displayId) = 0;
 
-    /* Sets the focused application.
+    /* Sets the focused application on the given display.
      *
      * This method may be called on any thread (usually by the input manager).
      */
     virtual void setFocusedApplication(
-            const sp<InputApplicationHandle>& inputApplicationHandle) = 0;
+            int32_t displayId, const sp<InputApplicationHandle>& inputApplicationHandle) = 0;
+
+    /* Sets the focused display.
+     *
+     * This method may be called on any thread (usually by the input manager).
+     */
+    virtual void setFocusedDisplay(int32_t displayId) = 0;
 
     /* Sets the input dispatching mode.
      *
@@ -391,7 +397,9 @@
 
     virtual void setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles,
             int32_t displayId);
-    virtual void setFocusedApplication(const sp<InputApplicationHandle>& inputApplicationHandle);
+    virtual void setFocusedApplication(int32_t displayId,
+            const sp<InputApplicationHandle>& inputApplicationHandle);
+    virtual void setFocusedDisplay(int32_t displayId);
     virtual void setInputDispatchMode(bool enabled, bool frozen);
     virtual void setInputFilterEnabled(bool enabled);
 
@@ -686,6 +694,10 @@
             CANCEL_POINTER_EVENTS = 1,
             CANCEL_NON_POINTER_EVENTS = 2,
             CANCEL_FALLBACK_EVENTS = 3,
+
+            /* Cancel events where the display not specified. These events would go to the focused
+             * display. */
+            CANCEL_DISPLAY_UNSPECIFIED_EVENTS = 4,
         };
 
         // The criterion to use to determine which events should be canceled.
@@ -966,7 +978,7 @@
     bool hasWindowHandleLocked(const sp<InputWindowHandle>& windowHandle) const;
 
     // Focus tracking for keys, trackball, etc.
-    sp<InputWindowHandle> mFocusedWindowHandle;
+    std::unordered_map<int32_t, sp<InputWindowHandle>> mFocusedWindowHandlesByDisplay;
 
     // Focus tracking for touch.
     struct TouchedWindow {
@@ -997,8 +1009,11 @@
     KeyedVector<int32_t, TouchState> mTouchStatesByDisplay;
     TouchState mTempTouchState;
 
-    // Focused application.
-    sp<InputApplicationHandle> mFocusedApplicationHandle;
+    // Focused applications.
+    std::unordered_map<int32_t, sp<InputApplicationHandle>> mFocusedApplicationHandlesByDisplay;
+
+    // Top focused display.
+    int32_t mFocusedDisplayId;
 
     // Dispatcher state at time of last ANR.
     std::string mLastANRState;
@@ -1046,6 +1061,7 @@
     nsecs_t getTimeSpentWaitingForApplicationLocked(nsecs_t currentTime);
     void resetANRTimeoutsLocked();
 
+    int32_t getTargetDisplayId(const EventEntry* entry);
     int32_t findFocusedWindowTargetsLocked(nsecs_t currentTime, const EventEntry* entry,
             Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime);
     int32_t findTouchedWindowTargetsLocked(nsecs_t currentTime, const MotionEntry* entry,
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index 8f12129..57fc17f 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -258,64 +258,31 @@
 
 bool InputReaderConfiguration::getDisplayViewport(ViewportType viewportType,
         const std::string& uniqueDisplayId, DisplayViewport* outViewport) const {
-    const DisplayViewport* viewport = nullptr;
-    if (viewportType == ViewportType::VIEWPORT_VIRTUAL && !uniqueDisplayId.empty()) {
-
-        for (const DisplayViewport& currentViewport : mVirtualDisplays) {
-            if (currentViewport.uniqueId == uniqueDisplayId) {
-                viewport = &currentViewport;
-                break;
+    for (const DisplayViewport& currentViewport : mDisplays) {
+        if (currentViewport.type == viewportType) {
+            if (uniqueDisplayId.empty() ||
+                    (!uniqueDisplayId.empty() && uniqueDisplayId == currentViewport.uniqueId)) {
+                *outViewport = currentViewport;
+                return true;
             }
         }
-    } else if (viewportType == ViewportType::VIEWPORT_EXTERNAL) {
-        viewport = &mExternalDisplay;
-    } else if (viewportType == ViewportType::VIEWPORT_INTERNAL) {
-        viewport = &mInternalDisplay;
-    }
-
-    if (viewport != nullptr && viewport->displayId >= 0) {
-        *outViewport = *viewport;
-        return true;
     }
     return false;
 }
 
-void InputReaderConfiguration::setPhysicalDisplayViewport(ViewportType viewportType,
-        const DisplayViewport& viewport) {
-    if (viewportType == ViewportType::VIEWPORT_EXTERNAL) {
-        mExternalDisplay = viewport;
-    } else if (viewportType == ViewportType::VIEWPORT_INTERNAL) {
-        mInternalDisplay = viewport;
-    }
-}
-
-void InputReaderConfiguration::setVirtualDisplayViewports(
-        const Vector<DisplayViewport>& viewports) {
-    mVirtualDisplays = viewports;
+void InputReaderConfiguration::setDisplayViewports(const std::vector<DisplayViewport>& viewports) {
+    mDisplays = viewports;
 }
 
 void InputReaderConfiguration::dump(std::string& dump) const {
-    dump += INDENT4 "ViewportInternal:\n";
-    dumpViewport(dump, mInternalDisplay);
-    dump += INDENT4 "ViewportExternal:\n";
-    dumpViewport(dump, mExternalDisplay);
-    dump += INDENT4 "ViewportVirtual:\n";
-    for (const DisplayViewport& viewport : mVirtualDisplays) {
+    for (const DisplayViewport& viewport : mDisplays) {
         dumpViewport(dump, viewport);
     }
 }
 
-void InputReaderConfiguration::dumpViewport(std::string& dump, const DisplayViewport& viewport) const {
-    dump += StringPrintf(INDENT5 "Viewport: displayId=%d, orientation=%d, uniqueId='%s', "
-            "logicalFrame=[%d, %d, %d, %d], "
-            "physicalFrame=[%d, %d, %d, %d], "
-            "deviceSize=[%d, %d]\n",
-            viewport.displayId, viewport.orientation, viewport.uniqueId.c_str(),
-            viewport.logicalLeft, viewport.logicalTop,
-            viewport.logicalRight, viewport.logicalBottom,
-            viewport.physicalLeft, viewport.physicalTop,
-            viewport.physicalRight, viewport.physicalBottom,
-            viewport.deviceWidth, viewport.deviceHeight);
+void InputReaderConfiguration::dumpViewport(std::string& dump, const DisplayViewport& viewport)
+        const {
+    dump += StringPrintf(INDENT4 "%s\n", viewport.toString().c_str());
 }
 
 
@@ -3600,6 +3567,12 @@
                 break;
             }
 
+            if (naturalPhysicalHeight == 0 || naturalPhysicalWidth == 0) {
+                ALOGE("Viewport is not set properly: %s", mViewport.toString().c_str());
+                naturalPhysicalHeight = naturalPhysicalHeight == 0 ? 1 : naturalPhysicalHeight;
+                naturalPhysicalWidth = naturalPhysicalWidth == 0 ? 1 : naturalPhysicalWidth;
+            }
+
             mPhysicalWidth = naturalPhysicalWidth;
             mPhysicalHeight = naturalPhysicalHeight;
             mPhysicalLeft = naturalPhysicalLeft;
@@ -3913,17 +3886,7 @@
 }
 
 void TouchInputMapper::dumpSurface(std::string& dump) {
-    dump += StringPrintf(INDENT3 "Viewport: displayId=%d, orientation=%d, "
-            "logicalFrame=[%d, %d, %d, %d], "
-            "physicalFrame=[%d, %d, %d, %d], "
-            "deviceSize=[%d, %d]\n",
-            mViewport.displayId, mViewport.orientation,
-            mViewport.logicalLeft, mViewport.logicalTop,
-            mViewport.logicalRight, mViewport.logicalBottom,
-            mViewport.physicalLeft, mViewport.physicalTop,
-            mViewport.physicalRight, mViewport.physicalBottom,
-            mViewport.deviceWidth, mViewport.deviceHeight);
-
+    dump += StringPrintf(INDENT3 "%s\n", mViewport.toString().c_str());
     dump += StringPrintf(INDENT3 "SurfaceWidth: %dpx\n", mSurfaceWidth);
     dump += StringPrintf(INDENT3 "SurfaceHeight: %dpx\n", mSurfaceHeight);
     dump += StringPrintf(INDENT3 "SurfaceLeft: %d\n", mSurfaceLeft);
diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h
index c06168d..74668b7 100644
--- a/services/inputflinger/InputReader.h
+++ b/services/inputflinger/InputReader.h
@@ -38,6 +38,7 @@
 #include <optional>
 #include <stddef.h>
 #include <unistd.h>
+#include <vector>
 
 // Maximum supported size of a vibration pattern.
 // Must be at least 2.
@@ -203,17 +204,14 @@
 
     bool getDisplayViewport(ViewportType viewportType, const std::string& uniqueDisplayId,
             DisplayViewport* outViewport) const;
-    void setPhysicalDisplayViewport(ViewportType viewportType, const DisplayViewport& viewport);
-    void setVirtualDisplayViewports(const Vector<DisplayViewport>& viewports);
+    void setDisplayViewports(const std::vector<DisplayViewport>& viewports);
 
 
     void dump(std::string& dump) const;
     void dumpViewport(std::string& dump, const DisplayViewport& viewport) const;
 
 private:
-    DisplayViewport mInternalDisplay;
-    DisplayViewport mExternalDisplay;
-    Vector<DisplayViewport> mVirtualDisplays;
+    std::vector<DisplayViewport> mDisplays;
 };
 
 
diff --git a/services/inputflinger/InputWindow.cpp b/services/inputflinger/InputWindow.cpp
deleted file mode 100644
index 0d1dfdd..0000000
--- a/services/inputflinger/InputWindow.cpp
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2011 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 "InputWindow"
-#define LOG_NDEBUG 0
-
-#include "InputWindow.h"
-
-#include <log/log.h>
-
-#include <ui/Rect.h>
-#include <ui/Region.h>
-
-namespace android {
-
-// --- InputWindowInfo ---
-void InputWindowInfo::addTouchableRegion(const Rect& region) {
-    touchableRegion.orSelf(region);
-}
-
-bool InputWindowInfo::touchableRegionContainsPoint(int32_t x, int32_t y) const {
-    return touchableRegion.contains(x,y);
-}
-
-bool InputWindowInfo::frameContainsPoint(int32_t x, int32_t y) const {
-    return x >= frameLeft && x < frameRight
-            && y >= frameTop && y < frameBottom;
-}
-
-bool InputWindowInfo::isTrustedOverlay() const {
-    return layoutParamsType == TYPE_INPUT_METHOD
-            || layoutParamsType == TYPE_INPUT_METHOD_DIALOG
-            || layoutParamsType == TYPE_MAGNIFICATION_OVERLAY
-            || layoutParamsType == TYPE_STATUS_BAR
-            || layoutParamsType == TYPE_NAVIGATION_BAR
-            || layoutParamsType == TYPE_NAVIGATION_BAR_PANEL
-            || layoutParamsType == TYPE_SECURE_SYSTEM_OVERLAY
-            || layoutParamsType == TYPE_DOCK_DIVIDER
-            || layoutParamsType == TYPE_ACCESSIBILITY_OVERLAY
-            || layoutParamsType == TYPE_INPUT_CONSUMER;
-}
-
-bool InputWindowInfo::supportsSplitTouch() const {
-    return layoutParamsFlags & FLAG_SPLIT_TOUCH;
-}
-
-bool InputWindowInfo::overlaps(const InputWindowInfo* other) const {
-    return frameLeft < other->frameRight && frameRight > other->frameLeft
-            && frameTop < other->frameBottom && frameBottom > other->frameTop;
-}
-
-
-// --- InputWindowHandle ---
-
-InputWindowHandle::InputWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle) :
-    inputApplicationHandle(inputApplicationHandle), mInfo(nullptr) {
-}
-
-InputWindowHandle::~InputWindowHandle() {
-    delete mInfo;
-}
-
-void InputWindowHandle::releaseInfo() {
-    if (mInfo) {
-        delete mInfo;
-        mInfo = nullptr;
-    }
-}
-
-} // namespace android
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 61dcdd9..f75b0b6 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -340,7 +340,8 @@
         mDisplayId = displayId;
     }
 
-    void consumeEvent(int32_t expectedEventType, int32_t expectedDisplayId) {
+    void consumeEvent(int32_t expectedEventType, int32_t expectedDisplayId,
+            int32_t expectedFlags = 0) {
         uint32_t consumeSeq;
         InputEvent* event;
         status_t status = mConsumer->consume(&mEventFactory, false /*consumeBatches*/, -1,
@@ -351,10 +352,29 @@
         ASSERT_TRUE(event != nullptr)
                 << mName.c_str() << ": consumer should have returned non-NULL event.";
         ASSERT_EQ(expectedEventType, event->getType())
-                << mName.c_str() << ": consumer type should same as expected one.";
+                << mName.c_str() << ": event type should match.";
 
         ASSERT_EQ(expectedDisplayId, event->getDisplayId())
-                << mName.c_str() << ": consumer displayId should same as expected one.";
+                << mName.c_str() << ": event displayId should be the same as expected.";
+
+        int32_t flags;
+        switch (expectedEventType) {
+            case AINPUT_EVENT_TYPE_KEY: {
+                KeyEvent* typedEvent = static_cast<KeyEvent*>(event);
+                flags = typedEvent->getFlags();
+                break;
+            }
+            case AINPUT_EVENT_TYPE_MOTION: {
+                MotionEvent* typedEvent = static_cast<MotionEvent*>(event);
+                flags = typedEvent->getFlags();
+                break;
+            }
+            default: {
+                FAIL() << mName.c_str() << ": invalid event type: " << expectedEventType;
+            }
+        }
+        ASSERT_EQ(expectedFlags, flags)
+                << mName.c_str() << ": event flags should be the same as expected.";
 
         status = mConsumer->sendFinishedSignal(consumeSeq, true /*handled*/);
         ASSERT_EQ(OK, status)
@@ -382,12 +402,13 @@
         int32_t mDisplayId;
 };
 
-static int32_t injectKeyDown(const sp<InputDispatcher>& dispatcher) {
+static int32_t injectKeyDown(const sp<InputDispatcher>& dispatcher,
+        int32_t displayId = ADISPLAY_ID_NONE) {
     KeyEvent event;
     nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
     // Define a valid key down event.
-    event.initialize(DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE,
+    event.initialize(DEVICE_ID, AINPUT_SOURCE_KEYBOARD, displayId,
             AKEY_EVENT_ACTION_DOWN, /* flags */ 0,
             AKEYCODE_A, KEY_A, AMETA_NONE, /* repeatCount */ 0, currentTime, currentTime);
 
@@ -466,7 +487,7 @@
     sp<FakeWindowHandle> windowSecond = new FakeWindowHandle(application, mDispatcher, "Second");
 
     // Set focus application.
-    mDispatcher->setFocusedApplication(application);
+    mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
 
     // Expect one focus window exist in display.
     windowSecond->setFocus();
@@ -511,15 +532,21 @@
     windowInSecondary->consumeEvent(AINPUT_EVENT_TYPE_MOTION, SECOND_DISPLAY_ID);
 }
 
-// TODO(b/111361570): multi-display focus, one focus window per display.
 TEST_F(InputDispatcherTest, SetInputWindow_FocusedInMultiDisplay) {
     sp<FakeApplicationHandle> application = new FakeApplicationHandle();
     sp<FakeWindowHandle> windowInPrimary = new FakeWindowHandle(application, mDispatcher, "D_1");
     sp<FakeApplicationHandle> application2 = new FakeApplicationHandle();
     sp<FakeWindowHandle> windowInSecondary = new FakeWindowHandle(application2, mDispatcher, "D_2");
 
+    constexpr int32_t SECOND_DISPLAY_ID = 1;
+
+    // Set focus to primary display window.
+    mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
+    windowInPrimary->setFocus();
+
     // Set focus to second display window.
-    mDispatcher->setFocusedApplication(application2);
+    mDispatcher->setFocusedDisplay(SECOND_DISPLAY_ID);
+    mDispatcher->setFocusedApplication(SECOND_DISPLAY_ID, application2);
     windowInSecondary->setFocus();
 
     // Update all windows per displays.
@@ -527,13 +554,18 @@
     inputWindowHandles.push(windowInPrimary);
     mDispatcher->setInputWindows(inputWindowHandles, ADISPLAY_ID_DEFAULT);
 
-    constexpr int32_t SECOND_DISPLAY_ID = 1;
     windowInSecondary->setDisplayId(SECOND_DISPLAY_ID);
     Vector<sp<InputWindowHandle>> inputWindowHandles_Second;
     inputWindowHandles_Second.push(windowInSecondary);
     mDispatcher->setInputWindows(inputWindowHandles_Second, SECOND_DISPLAY_ID);
 
-    // Test inject a key down.
+    // Test inject a key down with display id specified.
+    ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyDown(mDispatcher, ADISPLAY_ID_DEFAULT))
+            << "Inject key event should return INPUT_EVENT_INJECTION_SUCCEEDED";
+    windowInPrimary->consumeEvent(AINPUT_EVENT_TYPE_KEY, ADISPLAY_ID_DEFAULT);
+    windowInSecondary->assertNoEvents();
+
+    // Test inject a key down without display id specified.
     ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyDown(mDispatcher))
             << "Inject key event should return INPUT_EVENT_INJECTION_SUCCEEDED";
     windowInPrimary->assertNoEvents();
@@ -544,7 +576,8 @@
     mDispatcher->setInputWindows(inputWindowHandles_Second, SECOND_DISPLAY_ID);
 
     // Expect old focus should receive a cancel event.
-    windowInSecondary->consumeEvent(AINPUT_EVENT_TYPE_KEY, ADISPLAY_ID_NONE);
+    windowInSecondary->consumeEvent(AINPUT_EVENT_TYPE_KEY, ADISPLAY_ID_NONE,
+            AKEY_EVENT_FLAG_CANCELED);
 
     // Test inject a key down, should timeout because of no target window.
     ASSERT_EQ(INPUT_EVENT_INJECTION_TIMED_OUT, injectKeyDown(mDispatcher))
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 9b985dc..b70ee09 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -132,6 +132,7 @@
     InputReaderConfiguration mConfig;
     KeyedVector<int32_t, sp<FakePointerController> > mPointerControllers;
     Vector<InputDeviceInfo> mInputDevices;
+    std::vector<DisplayViewport> mViewports;
     TouchAffineTransformation transform;
 
 protected:
@@ -143,17 +144,20 @@
 
     void setDisplayViewport(int32_t displayId, int32_t width, int32_t height, int32_t orientation,
             const std::string& uniqueId) {
-        DisplayViewport v = createDisplayViewport(displayId, width, height, orientation, uniqueId);
+        mViewports.clear();
         // Set the size of both the internal and external display at the same time.
-        mConfig.setPhysicalDisplayViewport(ViewportType::VIEWPORT_INTERNAL, v);
-        mConfig.setPhysicalDisplayViewport(ViewportType::VIEWPORT_EXTERNAL, v);
+        mViewports.push_back(createDisplayViewport(displayId, width, height, orientation, uniqueId,
+                ViewportType::VIEWPORT_INTERNAL));
+        mViewports.push_back(createDisplayViewport(displayId, width, height, orientation, uniqueId,
+                ViewportType::VIEWPORT_EXTERNAL));
+        mConfig.setDisplayViewports(mViewports);
     }
 
     void setVirtualDisplayViewport(int32_t displayId, int32_t width, int32_t height, int32_t orientation,
             const std::string& uniqueId) {
-        Vector<DisplayViewport> viewports;
-        viewports.push_back(createDisplayViewport(displayId, width, height, orientation, uniqueId));
-        mConfig.setVirtualDisplayViewports(viewports);
+        mViewports.push_back(createDisplayViewport(displayId, width, height, orientation, uniqueId,
+                ViewportType::VIEWPORT_VIRTUAL));
+        mConfig.setDisplayViewports(mViewports);
     }
 
     void addExcludedDeviceName(const std::string& deviceName) {
@@ -203,7 +207,7 @@
 
 private:
     DisplayViewport createDisplayViewport(int32_t displayId, int32_t width, int32_t height,
-            int32_t orientation, const std::string& uniqueId) {
+            int32_t orientation, const std::string& uniqueId, ViewportType type) {
         bool isRotated = (orientation == DISPLAY_ORIENTATION_90
                 || orientation == DISPLAY_ORIENTATION_270);
         DisplayViewport v;
@@ -220,6 +224,7 @@
         v.deviceWidth = isRotated ? height : width;
         v.deviceHeight = isRotated ? width : height;
         v.uniqueId = uniqueId;
+        v.type = type;
         return v;
     }
 
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index ebc7eb1..f2336cb 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -16,6 +16,7 @@
 
 #include "SensorDevice.h"
 
+#include "android/hardware/sensors/2.0/ISensorsCallback.h"
 #include "android/hardware/sensors/2.0/types.h"
 #include "SensorService.h"
 
@@ -32,6 +33,7 @@
 using namespace android::hardware::sensors;
 using namespace android::hardware::sensors::V1_0;
 using namespace android::hardware::sensors::V1_0::implementation;
+using android::hardware::sensors::V2_0::ISensorsCallback;
 using android::hardware::sensors::V2_0::EventQueueFlagBits;
 using android::hardware::hidl_vec;
 using android::hardware::Return;
@@ -57,12 +59,53 @@
     }
 }
 
+template<typename EnumType>
+constexpr typename std::underlying_type<EnumType>::type asBaseType(EnumType value) {
+    return static_cast<typename std::underlying_type<EnumType>::type>(value);
+}
+
+// Used internally by the framework to wake the Event FMQ. These values must start after
+// the last value of EventQueueFlagBits
+enum EventQueueFlagBitsInternal : uint32_t {
+    INTERNAL_WAKE =  1 << 16,
+};
+
+void SensorsHalDeathReceivier::serviceDied(
+        uint64_t /* cookie */,
+        const wp<::android::hidl::base::V1_0::IBase>& /* service */) {
+    ALOGW("Sensors HAL died, attempting to reconnect.");
+    SensorDevice::getInstance().prepareForReconnect();
+}
+
+struct SensorsCallback : public ISensorsCallback {
+    using Result = ::android::hardware::sensors::V1_0::Result;
+    Return<void> onDynamicSensorsConnected(
+            const hidl_vec<SensorInfo> &dynamicSensorsAdded) override {
+        return SensorDevice::getInstance().onDynamicSensorsConnected(dynamicSensorsAdded);
+    }
+
+    Return<void> onDynamicSensorsDisconnected(
+            const hidl_vec<int32_t> &dynamicSensorHandlesRemoved) override {
+        return SensorDevice::getInstance().onDynamicSensorsDisconnected(
+                dynamicSensorHandlesRemoved);
+    }
+};
+
 SensorDevice::SensorDevice()
-        : mHidlTransportErrors(20), mRestartWaiter(new HidlServiceRegistrationWaiter()) {
+        : mHidlTransportErrors(20),
+          mRestartWaiter(new HidlServiceRegistrationWaiter()),
+          mReconnecting(false) {
     if (!connectHidlService()) {
         return;
     }
 
+    initializeSensorList();
+
+    mIsDirectReportSupported =
+           (checkReturn(mSensors->unregisterDirectChannel(-1)) != Result::INVALID_OPERATION);
+}
+
+void SensorDevice::initializeSensorList() {
     float minPowerMa = 0.001; // 1 microAmp
 
     checkReturn(mSensors->getSensorsList(
@@ -87,9 +130,6 @@
                     checkReturn(mSensors->activate(list[i].sensorHandle, 0 /* enabled */));
                 }
             }));
-
-    mIsDirectReportSupported =
-           (checkReturn(mSensors->unregisterDirectChannel(-1)) != Result::INVALID_OPERATION);
 }
 
 SensorDevice::~SensorDevice() {
@@ -166,19 +206,123 @@
         status_t status = StatusFromResult(checkReturn(mSensors->initialize(
                 *mEventQueue->getDesc(),
                 *mWakeLockQueue->getDesc(),
-                this)));
+                new SensorsCallback())));
 
         if (status != NO_ERROR) {
             connectionStatus = HalConnectionStatus::FAILED_TO_CONNECT;
             ALOGE("Failed to initialize Sensors HAL (%s)", strerror(-status));
         } else {
             connectionStatus = HalConnectionStatus::CONNECTED;
+            mSensorsHalDeathReceiver = new SensorsHalDeathReceivier();
+            sensors->linkToDeath(mSensorsHalDeathReceiver, 0 /* cookie */);
         }
     }
 
     return connectionStatus;
 }
 
+void SensorDevice::prepareForReconnect() {
+    mReconnecting = true;
+
+    // Wake up the polling thread so it returns and allows the SensorService to initiate
+    // a reconnect.
+    mEventQueueFlag->wake(asBaseType(INTERNAL_WAKE));
+}
+
+void SensorDevice::reconnect() {
+    Mutex::Autolock _l(mLock);
+    mSensors = nullptr;
+
+    auto previousActivations = mActivationCount;
+    auto previousSensorList = mSensorList;
+
+    mActivationCount.clear();
+    mSensorList.clear();
+
+    if (connectHidlServiceV2_0() == HalConnectionStatus::CONNECTED) {
+        initializeSensorList();
+
+        if (sensorHandlesChanged(previousSensorList, mSensorList)) {
+            LOG_ALWAYS_FATAL("Sensor handles changed, cannot re-enable sensors.");
+        } else {
+            reactivateSensors(previousActivations);
+        }
+    }
+    mReconnecting = false;
+}
+
+bool SensorDevice::sensorHandlesChanged(const Vector<sensor_t>& oldSensorList,
+                                        const Vector<sensor_t>& newSensorList) {
+    bool didChange = false;
+
+    if (oldSensorList.size() != newSensorList.size()) {
+        didChange = true;
+    }
+
+    for (size_t i = 0; i < newSensorList.size() && !didChange; i++) {
+        bool found = false;
+        const sensor_t& newSensor = newSensorList[i];
+        for (size_t j = 0; j < oldSensorList.size() && !found; j++) {
+            const sensor_t& prevSensor = oldSensorList[j];
+            if (prevSensor.handle == newSensor.handle) {
+                found = true;
+                if (!sensorIsEquivalent(prevSensor, newSensor)) {
+                    didChange = true;
+                }
+            }
+        }
+
+        if (!found) {
+            // Could not find the new sensor in the old list of sensors, the lists must
+            // have changed.
+            didChange = true;
+        }
+    }
+    return didChange;
+}
+
+bool SensorDevice::sensorIsEquivalent(const sensor_t& prevSensor, const sensor_t& newSensor) {
+    bool equivalent = true;
+    if (prevSensor.handle != newSensor.handle ||
+            (strcmp(prevSensor.vendor, newSensor.vendor) != 0) ||
+            (strcmp(prevSensor.stringType, newSensor.stringType) != 0) ||
+            (strcmp(prevSensor.requiredPermission, newSensor.requiredPermission) != 0) ||
+            (prevSensor.version != newSensor.version) ||
+            (prevSensor.type != newSensor.type) ||
+            (std::abs(prevSensor.maxRange - newSensor.maxRange) > 0.001f) ||
+            (std::abs(prevSensor.resolution - newSensor.resolution) > 0.001f) ||
+            (std::abs(prevSensor.power - newSensor.power) > 0.001f) ||
+            (prevSensor.minDelay != newSensor.minDelay) ||
+            (prevSensor.fifoReservedEventCount != newSensor.fifoReservedEventCount) ||
+            (prevSensor.fifoMaxEventCount != newSensor.fifoMaxEventCount) ||
+            (prevSensor.maxDelay != newSensor.maxDelay) ||
+            (prevSensor.flags != newSensor.flags)) {
+        equivalent = false;
+    }
+    return equivalent;
+}
+
+void SensorDevice::reactivateSensors(const DefaultKeyedVector<int, Info>& previousActivations) {
+    for (size_t i = 0; i < mSensorList.size(); i++) {
+        int handle = mSensorList[i].handle;
+        ssize_t activationIndex = previousActivations.indexOfKey(handle);
+        if (activationIndex < 0 || previousActivations[activationIndex].numActiveClients() <= 0) {
+            continue;
+        }
+
+        const Info& info = previousActivations[activationIndex];
+        for (size_t j = 0; j < info.batchParams.size(); j++) {
+            const BatchParams& batchParams = info.batchParams[j];
+            status_t res = batchLocked(info.batchParams.keyAt(j), handle, 0 /* flags */,
+                    batchParams.mTSample, batchParams.mTBatch);
+
+            if (res == NO_ERROR) {
+                activateLocked(info.batchParams.keyAt(j), handle, true /* enabled */);
+            }
+        }
+    }
+}
+
 void SensorDevice::handleDynamicSensorConnection(int handle, bool connected) {
     // not need to check mSensors because this is is only called after successful poll()
     if (connected) {
@@ -236,6 +380,8 @@
 }
 
 ssize_t SensorDevice::poll(sensors_event_t* buffer, size_t count) {
+    if (mSensors == nullptr) return NO_INIT;
+
     ssize_t eventsRead = 0;
     if (mSensors->supportsMessageQueues()) {
         eventsRead = pollFmq(buffer, count);
@@ -249,8 +395,6 @@
 }
 
 ssize_t SensorDevice::pollHal(sensors_event_t* buffer, size_t count) {
-    if (mSensors == nullptr) return NO_INIT;
-
     ssize_t err;
     int numHidlTransportErrors = 0;
     bool hidlTransportError = false;
@@ -295,10 +439,6 @@
 }
 
 ssize_t SensorDevice::pollFmq(sensors_event_t* buffer, size_t maxNumEventsToRead) {
-    if (mSensors == nullptr) {
-        return NO_INIT;
-    }
-
     ssize_t eventsRead = 0;
     size_t availableEvents = mEventQueue->availableToRead();
 
@@ -309,13 +449,19 @@
         // able to be called with the correct number of events to read. If the specified number of
         // events is not available, then read() would return no events, possibly introducing
         // additional latency in delivering events to applications.
-        mEventQueueFlag->wait(static_cast<uint32_t>(EventQueueFlagBits::READ_AND_PROCESS),
-                              &eventFlagState);
+        mEventQueueFlag->wait(asBaseType(EventQueueFlagBits::READ_AND_PROCESS) |
+                              asBaseType(INTERNAL_WAKE), &eventFlagState);
         availableEvents = mEventQueue->availableToRead();
 
-        if (availableEvents == 0) {
+        if ((eventFlagState & asBaseType(EventQueueFlagBits::READ_AND_PROCESS)) &&
+                availableEvents == 0) {
             ALOGW("Event FMQ wake without any events");
         }
+
+        if ((eventFlagState & asBaseType(INTERNAL_WAKE)) && mReconnecting) {
+            ALOGD("Event FMQ internal wake, returning from poll with no events");
+            return DEAD_OBJECT;
+        }
     }
 
     size_t eventsToRead = std::min({availableEvents, maxNumEventsToRead, mEventBuffer.size()});
@@ -362,7 +508,8 @@
 }
 
 void SensorDevice::writeWakeLockHandled(uint32_t count) {
-    if (mSensors->supportsMessageQueues() && !mWakeLockQueue->write(&count)) {
+    if (mSensors != nullptr && mSensors->supportsMessageQueues() &&
+            !mWakeLockQueue->write(&count)) {
         ALOGW("Failed to write wake lock handled");
     }
 }
@@ -381,10 +528,15 @@
 status_t SensorDevice::activate(void* ident, int handle, int enabled) {
     if (mSensors == nullptr) return NO_INIT;
 
-    status_t err(NO_ERROR);
+    Mutex::Autolock _l(mLock);
+    return activateLocked(ident, handle, enabled);
+}
+
+status_t SensorDevice::activateLocked(void* ident, int handle, int enabled) {
     bool actuateHardware = false;
 
-    Mutex::Autolock _l(mLock);
+    status_t err(NO_ERROR);
+
     ssize_t activationIndex = mActivationCount.indexOfKey(handle);
     if (activationIndex < 0) {
         ALOGW("Handle %d cannot be found in activation record", handle);
@@ -484,6 +636,11 @@
              ident, handle, flags, samplingPeriodNs, maxBatchReportLatencyNs);
 
     Mutex::Autolock _l(mLock);
+    return batchLocked(ident, handle, flags, samplingPeriodNs, maxBatchReportLatencyNs);
+}
+
+status_t SensorDevice::batchLocked(void* ident, int handle, int flags, int64_t samplingPeriodNs,
+                                   int64_t maxBatchReportLatencyNs) {
     ssize_t activationIndex = mActivationCount.indexOfKey(handle);
     if (activationIndex < 0) {
         ALOGW("Handle %d cannot be found in activation record", handle);
@@ -714,7 +871,7 @@
 
 // ---------------------------------------------------------------------------
 
-int SensorDevice::Info::numActiveClients() {
+int SensorDevice::Info::numActiveClients() const {
     SensorDevice& device(SensorDevice::getInstance());
     int num = 0;
     for (size_t i = 0; i < batchParams.size(); ++i) {
@@ -813,8 +970,12 @@
 }
 
 void SensorDevice::handleHidlDeath(const std::string & detail) {
-    // restart is the only option at present.
-    LOG_ALWAYS_FATAL("Abort due to ISensors hidl service failure, detail: %s.", detail.c_str());
+    if (!SensorDevice::getInstance().mSensors->supportsMessageQueues()) {
+        // restart is the only option at present.
+        LOG_ALWAYS_FATAL("Abort due to ISensors hidl service failure, detail: %s.", detail.c_str());
+    } else {
+        ALOGD("ISensors HAL died, death recipient will attempt reconnect");
+    }
 }
 
 // ---------------------------------------------------------------------------
diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h
index 282550f..e1024ac 100644
--- a/services/sensorservice/SensorDevice.h
+++ b/services/sensorservice/SensorDevice.h
@@ -42,9 +42,12 @@
 namespace android {
 
 // ---------------------------------------------------------------------------
+class SensorsHalDeathReceivier : public android::hardware::hidl_death_recipient {
+    virtual void serviceDied(uint64_t cookie,
+                             const wp<::android::hidl::base::V1_0::IBase>& service) override;
+};
 
 class SensorDevice : public Singleton<SensorDevice>,
-                     public android::hardware::sensors::V2_0::ISensorsCallback,
                      public SensorServiceUtil::Dumpable {
 public:
     class HidlTransportErrorLog {
@@ -74,6 +77,8 @@
     };
 
     ~SensorDevice();
+    void prepareForReconnect();
+    void reconnect();
 
     ssize_t getSensorList(sensor_t const** list);
 
@@ -107,9 +112,13 @@
 
     using Result = ::android::hardware::sensors::V1_0::Result;
     hardware::Return<void> onDynamicSensorsConnected(
-            const hardware::hidl_vec<hardware::sensors::V1_0::SensorInfo> &dynamicSensorsAdded) override;
+            const hardware::hidl_vec<hardware::sensors::V1_0::SensorInfo> &dynamicSensorsAdded);
     hardware::Return<void> onDynamicSensorsDisconnected(
-            const hardware::hidl_vec<int32_t> &dynamicSensorHandlesRemoved) override;
+            const hardware::hidl_vec<int32_t> &dynamicSensorHandlesRemoved);
+
+    bool isReconnecting() const {
+        return mReconnecting;
+    }
 
     // Dumpable
     virtual std::string dump() const;
@@ -164,7 +173,7 @@
         // the removed ident. If index >=0, ident is present and successfully removed.
         ssize_t removeBatchParamsForIdent(void* ident);
 
-        int numActiveClients();
+        int numActiveClients() const;
     };
     DefaultKeyedVector<int, Info> mActivationCount;
 
@@ -176,6 +185,11 @@
     SortedVector<void *> mDisabledClients;
     SensorDevice();
     bool connectHidlService();
+    void initializeSensorList();
+    void reactivateSensors(const DefaultKeyedVector<int, Info>& previousActivations);
+    static bool sensorHandlesChanged(const Vector<sensor_t>& oldSensorList,
+                                     const Vector<sensor_t>& newSensorList);
+    static bool sensorIsEquivalent(const sensor_t& prevSensor, const sensor_t& newSensor);
 
     enum HalConnectionStatus {
         CONNECTED, // Successfully connected to the HAL
@@ -188,6 +202,9 @@
 
     ssize_t pollHal(sensors_event_t* buffer, size_t count);
     ssize_t pollFmq(sensors_event_t* buffer, size_t count);
+    status_t activateLocked(void* ident, int handle, int enabled);
+    status_t batchLocked(void* ident, int handle, int flags, int64_t samplingPeriodNs,
+                         int64_t maxBatchReportLatencyNs);
 
     static void handleHidlDeath(const std::string &detail);
     template<typename T>
@@ -223,6 +240,9 @@
     hardware::EventFlag* mEventQueueFlag;
 
     std::array<Event, SensorEventQueue::MAX_RECEIVE_BUFFER_EVENT_COUNT> mEventBuffer;
+
+    sp<SensorsHalDeathReceivier> mSensorsHalDeathReceiver;
+    std::atomic_bool mReconnecting;
 };
 
 // ---------------------------------------------------------------------------
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 7c56e5c..1b9b945 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -47,6 +47,7 @@
 #include "SensorRecord.h"
 #include "SensorRegistrationInfo.h"
 
+#include <ctime>
 #include <inttypes.h>
 #include <math.h>
 #include <sched.h>
@@ -423,6 +424,11 @@
         } else {
             // Default dump the sensor list and debugging information.
             //
+            timespec curTime;
+            clock_gettime(CLOCK_REALTIME, &curTime);
+            struct tm* timeinfo = localtime(&(curTime.tv_sec));
+            result.appendFormat("Captured at: %02d:%02d:%02d.%03d\n", timeinfo->tm_hour,
+                                timeinfo->tm_min, timeinfo->tm_sec, (int)ns2ms(curTime.tv_nsec));
             result.append("Sensor Device:\n");
             result.append(SensorDevice::getInstance().dump().c_str());
 
@@ -627,8 +633,13 @@
     do {
         ssize_t count = device.poll(mSensorEventBuffer, numEventMax);
         if (count < 0) {
-            ALOGE("sensor poll failed (%s)", strerror(-count));
-            break;
+            if(count == DEAD_OBJECT && device.isReconnecting()) {
+                device.reconnect();
+                continue;
+            } else {
+                ALOGE("sensor poll failed (%s)", strerror(-count));
+                break;
+            }
         }
 
         // Reset sensors_event_t.flags to zero for all events in the buffer.
diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp
index dfd0326..6826050 100644
--- a/services/surfaceflinger/BufferLayerConsumer.cpp
+++ b/services/surfaceflinger/BufferLayerConsumer.cpp
@@ -98,54 +98,7 @@
     mContentsChangedListener = listener;
 }
 
-// We need to determine the time when a buffer acquired now will be
-// displayed.  This can be calculated:
-//   time when previous buffer's actual-present fence was signaled
-//    + current display refresh rate * HWC latency
-//    + a little extra padding
-//
-// Buffer producers are expected to set their desired presentation time
-// based on choreographer time stamps, which (coming from vsync events)
-// will be slightly later then the actual-present timing.  If we get a
-// desired-present time that is unintentionally a hair after the next
-// vsync, we'll hold the frame when we really want to display it.  We
-// need to take the offset between actual-present and reported-vsync
-// into account.
-//
-// If the system is configured without a DispSync phase offset for the app,
-// we also want to throw in a bit of padding to avoid edge cases where we
-// just barely miss.  We want to do it here, not in every app.  A major
-// source of trouble is the app's use of the display's ideal refresh time
-// (via Display.getRefreshRate()), which could be off of the actual refresh
-// by a few percent, with the error multiplied by the number of frames
-// between now and when the buffer should be displayed.
-//
-// If the refresh reported to the app has a phase offset, we shouldn't need
-// to tweak anything here.
-nsecs_t BufferLayerConsumer::computeExpectedPresent(const DispSync& dispSync) {
-    // The HWC doesn't currently have a way to report additional latency.
-    // Assume that whatever we submit now will appear right after the flip.
-    // For a smart panel this might be 1.  This is expressed in frames,
-    // rather than time, because we expect to have a constant frame delay
-    // regardless of the refresh rate.
-    const uint32_t hwcLatency = 0;
-
-    // Ask DispSync when the next refresh will be (CLOCK_MONOTONIC).
-    const nsecs_t nextRefresh = dispSync.computeNextRefresh(hwcLatency);
-
-    // The DispSync time is already adjusted for the difference between
-    // vsync and reported-vsync (SurfaceFlinger::dispSyncPresentTimeOffset), so
-    // we don't need to factor that in here.  Pad a little to avoid
-    // weird effects if apps might be requesting times right on the edge.
-    nsecs_t extraPadding = 0;
-    if (SurfaceFlinger::vsyncPhaseOffsetNs == 0) {
-        extraPadding = 1000000; // 1ms (6% of 60Hz)
-    }
-
-    return nextRefresh + extraPadding;
-}
-
-status_t BufferLayerConsumer::updateTexImage(BufferRejecter* rejecter, const DispSync& dispSync,
+status_t BufferLayerConsumer::updateTexImage(BufferRejecter* rejecter, nsecs_t expectedPresentTime,
                                              bool* autoRefresh, bool* queuedBuffer,
                                              uint64_t maxFrameNumber,
                                              const sp<Fence>& releaseFence) {
@@ -163,7 +116,7 @@
     // Acquire the next buffer.
     // In asynchronous mode the list is guaranteed to be one buffer
     // deep, while in synchronous mode we use the oldest buffer.
-    status_t err = acquireBufferLocked(&item, computeExpectedPresent(dispSync), maxFrameNumber);
+    status_t err = acquireBufferLocked(&item, expectedPresentTime, maxFrameNumber);
     if (err != NO_ERROR) {
         if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
             err = NO_ERROR;
diff --git a/services/surfaceflinger/BufferLayerConsumer.h b/services/surfaceflinger/BufferLayerConsumer.h
index a6610b7..ea46245 100644
--- a/services/surfaceflinger/BufferLayerConsumer.h
+++ b/services/surfaceflinger/BufferLayerConsumer.h
@@ -80,8 +80,6 @@
     // ConsumerBase::setFrameAvailableListener().
     void setContentsChangedListener(const wp<ContentsChangedListener>& listener);
 
-    nsecs_t computeExpectedPresent(const DispSync& dispSync);
-
     // updateTexImage acquires the most recently queued buffer, and sets the
     // image contents of the target texture to it.
     //
@@ -93,8 +91,8 @@
     // Unlike the GLConsumer version, this version takes a functor that may be
     // used to reject the newly acquired buffer.  It also does not bind the
     // RenderEngine texture until bindTextureImage is called.
-    status_t updateTexImage(BufferRejecter* rejecter, const DispSync& dispSync, bool* autoRefresh,
-                            bool* queuedBuffer, uint64_t maxFrameNumber,
+    status_t updateTexImage(BufferRejecter* rejecter, nsecs_t expectedPresentTime,
+                            bool* autoRefresh, bool* queuedBuffer, uint64_t maxFrameNumber,
                             const sp<Fence>& releaseFence);
 
     // See BufferLayerConsumer::bindTextureImageLocked().
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 576724c..e75fbdf 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -79,7 +79,7 @@
     return mQueuedFrames;
 }
 
-bool BufferQueueLayer::shouldPresentNow(const DispSync& dispSync) const {
+bool BufferQueueLayer::shouldPresentNow(nsecs_t expectedPresentTime) const {
     if (getSidebandStreamChanged() || getAutoRefresh()) {
         return true;
     }
@@ -91,7 +91,6 @@
     Mutex::Autolock lock(mQueueItemLock);
 
     const int64_t addedTime = mQueueItems[0].mTimestamp;
-    const nsecs_t expectedPresentTime = mConsumer->computeExpectedPresent(dispSync);
 
     // Ignore timestamps more than a second in the future
     const bool isPlausible = addedTime < (expectedPresentTime + s2ns(1));
@@ -231,8 +230,12 @@
     LayerRejecter r(mDrawingState, getCurrentState(), recomputeVisibleRegions,
                     getProducerStickyTransform() != 0, mName.string(), mOverrideScalingMode,
                     getTransformToDisplayInverse(), mFreezeGeometryUpdates);
+
+    const nsecs_t expectedPresentTime = mFlinger->mUseScheduler
+            ? mFlinger->mScheduler->mPrimaryDispSync->expectedPresentTime()
+            : mFlinger->mPrimaryDispSync->expectedPresentTime();
     status_t updateResult =
-            mConsumer->updateTexImage(&r, *mFlinger->mPrimaryDispSync, &mAutoRefresh, &queuedBuffer,
+            mConsumer->updateTexImage(&r, expectedPresentTime, &mAutoRefresh, &queuedBuffer,
                                       mLastFrameNumberReceived, releaseFence);
     if (updateResult == BufferQueue::PRESENT_LATER) {
         // Producer doesn't want buffer to be displayed yet.  Signal a
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index 472abf2..abe0bc7 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -55,7 +55,7 @@
 
     int32_t getQueuedFrameCount() const override;
 
-    bool shouldPresentNow(const DispSync& dispSync) const override;
+    bool shouldPresentNow(nsecs_t expectedPresentTime) const override;
     // -----------------------------------------------------------------------
 
     // -----------------------------------------------------------------------
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index c0e85dd..e52b35a 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -56,7 +56,7 @@
     return;
 }
 
-bool BufferStateLayer::shouldPresentNow(const DispSync& /*dispSync*/) const {
+bool BufferStateLayer::shouldPresentNow(nsecs_t /*expectedPresentTime*/) const {
     if (getSidebandStreamChanged() || getAutoRefresh()) {
         return true;
     }
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index b106f23..0c6eaf5 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -39,7 +39,7 @@
     void setTransformHint(uint32_t orientation) const override;
     void releasePendingBuffer(nsecs_t dequeueReadyTime) override;
 
-    bool shouldPresentNow(const DispSync& dispSync) const override;
+    bool shouldPresentNow(nsecs_t expectedPresentTime) const override;
 
     bool getTransformToDisplayInverse() const override;
 
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 3eb8327..e2d1178 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -395,7 +395,7 @@
 
     virtual void abandon() {}
 
-    virtual bool shouldPresentNow(const DispSync& /*dispSync*/) const { return false; }
+    virtual bool shouldPresentNow(nsecs_t /*expectedPresentTime*/) const { return false; }
     virtual void setTransformHint(uint32_t /*orientation*/) const { }
 
     /*
diff --git a/services/surfaceflinger/LayerStats.cpp b/services/surfaceflinger/LayerStats.cpp
index 9c2d312..c0174ae 100644
--- a/services/surfaceflinger/LayerStats.cpp
+++ b/services/surfaceflinger/LayerStats.cpp
@@ -68,7 +68,7 @@
         base::StringAppendF(&key, ",%s", layerCompositionType(layer->hwcCompositionType));
         base::StringAppendF(&key, ",%d", layer->isProtected);
         base::StringAppendF(&key, ",%s", layerTransform(layer->hwcTransform));
-        base::StringAppendF(&key, ",%s", layerPixelFormat(layer->activeBuffer.format));
+        base::StringAppendF(&key, ",%s", layerPixelFormat(layer->activeBuffer.format).c_str());
         base::StringAppendF(&key, ",%s", layer->dataspace.c_str());
         base::StringAppendF(&key, ",%s",
                             destinationLocation(layer->hwcFrame.left, layerGlobal.resolution[0],
@@ -162,8 +162,8 @@
     return getCompositionName(static_cast<hwc2_composition_t>(compositionType));
 }
 
-const char* LayerStats::layerPixelFormat(int32_t pixelFormat) {
-    return decodePixelFormat(pixelFormat).c_str();
+std::string LayerStats::layerPixelFormat(int32_t pixelFormat) {
+    return decodePixelFormat(pixelFormat);
 }
 
 std::string LayerStats::scaleRatioWH(const LayerProtoParser::Layer* layer) {
diff --git a/services/surfaceflinger/LayerStats.h b/services/surfaceflinger/LayerStats.h
index 944073b..9de9cce 100644
--- a/services/surfaceflinger/LayerStats.h
+++ b/services/surfaceflinger/LayerStats.h
@@ -50,7 +50,7 @@
     // Return the name of the composition type
     static const char* layerCompositionType(int32_t compositionType);
     // Return the name of the pixel format
-    static const char* layerPixelFormat(int32_t pixelFormat);
+    static std::string layerPixelFormat(int32_t pixelFormat);
     // Calculate scale ratios of layer's width/height with rotation information
     static std::string scaleRatioWH(const LayerProtoParser::Layer* layer);
     // Calculate scale ratio from source to destination and convert to string
diff --git a/services/surfaceflinger/RenderEngine/Mesh.cpp b/services/surfaceflinger/RenderEngine/Mesh.cpp
index 5a3c2c8..809a0d7 100644
--- a/services/surfaceflinger/RenderEngine/Mesh.cpp
+++ b/services/surfaceflinger/RenderEngine/Mesh.cpp
@@ -27,7 +27,7 @@
         mTexCoordsSize(texCoordSize),
         mPrimitive(primitive) {
     if (vertexCount == 0) {
-        mVertices = new float[1];
+        mVertices.resize(1);
         mVertices[0] = 0.0f;
         mStride = 0;
         return;
@@ -40,7 +40,7 @@
     // will be equal to stride as long as stride * vertexCount doesn't overflow.
     if ((stride < vertexSize) || (remainder != stride)) {
         ALOGE("Overflow in Mesh(..., %zu, %zu, %zu)", vertexCount, vertexSize, texCoordSize);
-        mVertices = new float[1];
+        mVertices.resize(1);
         mVertices[0] = 0.0f;
         mVertexCount = 0;
         mVertexSize = 0;
@@ -49,30 +49,26 @@
         return;
     }
 
-    mVertices = new float[stride * vertexCount];
+    mVertices.resize(stride * vertexCount);
     mStride = stride;
 }
 
-Mesh::~Mesh() {
-    delete[] mVertices;
-}
-
 Mesh::Primitive Mesh::getPrimitive() const {
     return mPrimitive;
 }
 
 float const* Mesh::getPositions() const {
-    return mVertices;
+    return mVertices.data();
 }
 float* Mesh::getPositions() {
-    return mVertices;
+    return mVertices.data();
 }
 
 float const* Mesh::getTexCoords() const {
-    return mVertices + mVertexSize;
+    return mVertices.data() + mVertexSize;
 }
 float* Mesh::getTexCoords() {
-    return mVertices + mVertexSize;
+    return mVertices.data() + mVertexSize;
 }
 
 size_t Mesh::getVertexCount() const {
diff --git a/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.cpp b/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.cpp
index 1b0a539..5c4c3d5 100644
--- a/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.cpp
@@ -35,6 +35,7 @@
 #include <ui/DebugUtils.h>
 #include <ui/Rect.h>
 #include <ui/Region.h>
+#include <utils/KeyedVector.h>
 #include <utils/String8.h>
 #include <utils/Trace.h>
 #include "GLExtensions.h"
@@ -115,28 +116,27 @@
                                          EGLint wanted, EGLConfig* outConfig) {
     EGLint numConfigs = -1, n = 0;
     eglGetConfigs(dpy, nullptr, 0, &numConfigs);
-    EGLConfig* const configs = new EGLConfig[numConfigs];
-    eglChooseConfig(dpy, attrs, configs, numConfigs, &n);
+    std::vector<EGLConfig> configs(numConfigs, EGL_NO_CONFIG_KHR);
+    eglChooseConfig(dpy, attrs, configs.data(), configs.size(), &n);
+    configs.resize(n);
 
-    if (n) {
+    if (!configs.empty()) {
         if (attribute != EGL_NONE) {
-            for (int i = 0; i < n; i++) {
+            for (EGLConfig config : configs) {
                 EGLint value = 0;
-                eglGetConfigAttrib(dpy, configs[i], attribute, &value);
+                eglGetConfigAttrib(dpy, config, attribute, &value);
                 if (wanted == value) {
-                    *outConfig = configs[i];
-                    delete[] configs;
+                    *outConfig = config;
                     return NO_ERROR;
                 }
             }
         } else {
             // just pick the first one
             *outConfig = configs[0];
-            delete[] configs;
             return NO_ERROR;
         }
     }
-    delete[] configs;
+
     return NAME_NOT_FOUND;
 }
 
@@ -883,6 +883,10 @@
     result.appendFormat("GLES: %s, %s, %s\n", extensions.getVendor(), extensions.getRenderer(),
                         extensions.getVersion());
     result.appendFormat("%s\n", extensions.getExtensions());
+
+    result.appendFormat("RenderEngine program cache size: %zu\n",
+                        ProgramCache::getInstance().getSize());
+
     result.appendFormat("RenderEngine last dataspace conversion: (%s) to (%s)\n",
                         dataspaceDetails(static_cast<android_dataspace>(mDataSpace)).c_str(),
                         dataspaceDetails(static_cast<android_dataspace>(mOutputDataSpace)).c_str());
diff --git a/services/surfaceflinger/RenderEngine/gl/GLExtensions.cpp b/services/surfaceflinger/RenderEngine/gl/GLExtensions.cpp
index 6f50ea7..0fdb9aa 100644
--- a/services/surfaceflinger/RenderEngine/gl/GLExtensions.cpp
+++ b/services/surfaceflinger/RenderEngine/gl/GLExtensions.cpp
@@ -16,6 +16,9 @@
 
 #include "GLExtensions.h"
 
+#include <string>
+#include <unordered_set>
+
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -26,22 +29,30 @@
 namespace renderengine {
 namespace gl {
 
-SortedVector<String8> GLExtensions::parseExtensionString(char const* extensions) {
-    SortedVector<String8> list;
+namespace {
 
-    char const* curr = extensions;
-    char const* head = curr;
-    do {
-        head = strchr(curr, ' ');
-        String8 s(curr, head ? head - curr : strlen(curr));
-        if (s.length()) {
-            list.add(s);
-        }
-        curr = head + 1;
-    } while (head);
+class ExtensionSet {
+public:
+    ExtensionSet(const char* extensions) {
+        char const* curr = extensions;
+        char const* head = curr;
+        do {
+            head = strchr(curr, ' ');
+            size_t len = head ? head - curr : strlen(curr);
+            if (len > 0) {
+                mExtensions.emplace(curr, len);
+            }
+            curr = head + 1;
+        } while (head);
+    }
 
-    return list;
-}
+    bool hasExtension(const char* extension) const { return mExtensions.count(extension) > 0; }
+
+private:
+    std::unordered_set<std::string> mExtensions;
+};
+
+} // anonymous namespace
 
 void GLExtensions::initWithGLStrings(GLubyte const* vendor, GLubyte const* renderer,
                                      GLubyte const* version, GLubyte const* extensions) {
@@ -49,12 +60,6 @@
     mRenderer = (char const*)renderer;
     mVersion = (char const*)version;
     mExtensions = (char const*)extensions;
-    mExtensionList = parseExtensionString(mExtensions);
-}
-
-bool GLExtensions::hasExtension(char const* extension) const {
-    const String8 s(extension);
-    return mExtensionList.indexOf(s) >= 0;
 }
 
 char const* GLExtensions::getVendor() const {
@@ -76,7 +81,8 @@
 void GLExtensions::initWithEGLStrings(char const* eglVersion, char const* eglExtensions) {
     mEGLVersion = eglVersion;
     mEGLExtensions = eglExtensions;
-    mEGLExtensionList = parseExtensionString(mEGLExtensions);
+
+    ExtensionSet extensionSet(eglExtensions);
 
     // EGL_ANDROIDX_no_config_context is an experimental extension with no
     // written specification. It will be replaced by something more formal.
@@ -86,24 +92,24 @@
     //
     // EGL_KHR_no_config_context is official extension to allow creating a
     // context that works with any surface of a display.
-    if (hasEGLExtension("EGL_ANDROIDX_no_config_context") ||
-        hasEGLExtension("EGL_KHR_no_config_context")) {
+    if (extensionSet.hasExtension("EGL_ANDROIDX_no_config_context") ||
+        extensionSet.hasExtension("EGL_KHR_no_config_context")) {
         mHasNoConfigContext = true;
     }
 
-    if (hasEGLExtension("EGL_ANDROID_native_fence_sync")) {
+    if (extensionSet.hasExtension("EGL_ANDROID_native_fence_sync")) {
         mHasNativeFenceSync = true;
     }
-    if (hasEGLExtension("EGL_KHR_fence_sync")) {
+    if (extensionSet.hasExtension("EGL_KHR_fence_sync")) {
         mHasFenceSync = true;
     }
-    if (hasEGLExtension("EGL_KHR_wait_sync")) {
+    if (extensionSet.hasExtension("EGL_KHR_wait_sync")) {
         mHasWaitSync = true;
     }
-    if (hasEGLExtension("EGL_EXT_protected_content")) {
+    if (extensionSet.hasExtension("EGL_EXT_protected_content")) {
         mHasProtectedContent = true;
     }
-    if (hasEGLExtension("EGL_IMG_context_priority")) {
+    if (extensionSet.hasExtension("EGL_IMG_context_priority")) {
         mHasContextPriority = true;
     }
 }
@@ -116,11 +122,6 @@
     return mEGLExtensions.string();
 }
 
-bool GLExtensions::hasEGLExtension(char const* extension) const {
-    const String8 s(extension);
-    return mEGLExtensionList.indexOf(s) >= 0;
-}
-
 }  // namespace gl
 }  // namespace renderengine
 }  // namespace android
diff --git a/services/surfaceflinger/RenderEngine/gl/GLExtensions.h b/services/surfaceflinger/RenderEngine/gl/GLExtensions.h
index efdd8b7..02ad965 100644
--- a/services/surfaceflinger/RenderEngine/gl/GLExtensions.h
+++ b/services/surfaceflinger/RenderEngine/gl/GLExtensions.h
@@ -25,7 +25,6 @@
 #include <GLES/gl.h>
 #include <GLES/glext.h>
 #include <utils/Singleton.h>
-#include <utils/SortedVector.h>
 #include <utils/String8.h>
 
 namespace android {
@@ -46,13 +45,9 @@
     String8 mRenderer;
     String8 mVersion;
     String8 mExtensions;
-    SortedVector<String8> mExtensionList;
 
     String8 mEGLVersion;
     String8 mEGLExtensions;
-    SortedVector<String8> mEGLExtensionList;
-
-    static SortedVector<String8> parseExtensionString(char const* extensions);
 
     GLExtensions(const GLExtensions&);
     GLExtensions& operator=(const GLExtensions&);
@@ -74,12 +69,10 @@
     char const* getRenderer() const;
     char const* getVersion() const;
     char const* getExtensions() const;
-    bool hasExtension(char const* extension) const;
 
     void initWithEGLStrings(char const* eglVersion, char const* eglExtensions);
     char const* getEGLVersion() const;
     char const* getEGLExtensions() const;
-    bool hasEGLExtension(char const* extension) const;
 };
 
 }  // namespace gl
diff --git a/services/surfaceflinger/RenderEngine/gl/Program.cpp b/services/surfaceflinger/RenderEngine/gl/Program.cpp
index da67f92..7ae5736 100644
--- a/services/surfaceflinger/RenderEngine/gl/Program.cpp
+++ b/services/surfaceflinger/RenderEngine/gl/Program.cpp
@@ -74,8 +74,6 @@
     }
 }
 
-Program::~Program() {}
-
 bool Program::isValid() const {
     return mInitialized;
 }
@@ -112,17 +110,6 @@
     return shader;
 }
 
-String8& Program::dumpShader(String8& result, GLenum /*type*/) {
-    GLuint shader = GL_FRAGMENT_SHADER ? mFragmentShader : mVertexShader;
-    GLint l;
-    glGetShaderiv(shader, GL_SHADER_SOURCE_LENGTH, &l);
-    char* src = new char[l];
-    glGetShaderSource(shader, l, nullptr, src);
-    result.append(src);
-    delete[] src;
-    return result;
-}
-
 void Program::setUniforms(const Description& desc) {
     // TODO: we should have a mechanism here to not always reset uniforms that
     // didn't change for this program.
diff --git a/services/surfaceflinger/RenderEngine/gl/Program.h b/services/surfaceflinger/RenderEngine/gl/Program.h
index bb429ef..b1ce8cf 100644
--- a/services/surfaceflinger/RenderEngine/gl/Program.h
+++ b/services/surfaceflinger/RenderEngine/gl/Program.h
@@ -39,7 +39,7 @@
     enum { position = 0, texCoords = 1 };
 
     Program(const ProgramCache::Key& needs, const char* vertex, const char* fragment);
-    ~Program();
+    ~Program() = default;
 
     /* whether this object is usable */
     bool isValid() const;
@@ -58,7 +58,6 @@
 
 private:
     GLuint buildShader(const char* source, GLenum type);
-    String8& dumpShader(String8& result, GLenum type);
 
     // whether the initialization succeeded
     bool mInitialized;
diff --git a/services/surfaceflinger/RenderEngine/gl/ProgramCache.cpp b/services/surfaceflinger/RenderEngine/gl/ProgramCache.cpp
index 9254aa0..6d431b6 100644
--- a/services/surfaceflinger/RenderEngine/gl/ProgramCache.cpp
+++ b/services/surfaceflinger/RenderEngine/gl/ProgramCache.cpp
@@ -20,6 +20,7 @@
 
 #include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
+#include <log/log.h>
 #include <renderengine/private/Description.h>
 #include <utils/String8.h>
 #include <utils/Trace.h>
@@ -76,10 +77,6 @@
     return f;
 }
 
-ProgramCache::ProgramCache() {}
-
-ProgramCache::~ProgramCache() {}
-
 void ProgramCache::primeCache(bool useColorManagement) {
     uint32_t shaderCount = 0;
     uint32_t keyMask = Key::BLEND_MASK | Key::OPACITY_MASK | Key::ALPHA_MASK | Key::TEXTURE_MASK;
@@ -94,10 +91,8 @@
         if (tex != Key::TEXTURE_OFF && tex != Key::TEXTURE_EXT && tex != Key::TEXTURE_2D) {
             continue;
         }
-        Program* program = mCache.valueFor(shaderKey);
-        if (program == nullptr) {
-            program = generateProgram(shaderKey);
-            mCache.add(shaderKey, program);
+        if (mCache.count(shaderKey) == 0) {
+            mCache.emplace(shaderKey, generateProgram(shaderKey));
             shaderCount++;
         }
     }
@@ -113,10 +108,8 @@
             shaderKey.set(Key::OPACITY_MASK,
                           (i & 1) ? Key::OPACITY_OPAQUE : Key::OPACITY_TRANSLUCENT);
             shaderKey.set(Key::ALPHA_MASK, (i & 2) ? Key::ALPHA_LT_ONE : Key::ALPHA_EQ_ONE);
-            Program* program = mCache.valueFor(shaderKey);
-            if (program == nullptr) {
-                program = generateProgram(shaderKey);
-                mCache.add(shaderKey, program);
+            if (mCache.count(shaderKey) == 0) {
+                mCache.emplace(shaderKey, generateProgram(shaderKey));
                 shaderCount++;
             }
         }
@@ -316,7 +309,7 @@
 
                             // scale [0.0, maxInLumi] to [0.0, maxOutLumi]
                             if (maxInLumi <= maxOutLumi) {
-                                nits *= maxOutLumi / maxInLumi;
+                                return color * (maxOutLumi / maxInLumi);
                             } else {
                                 // three control points
                                 const float x0 = 10.0;
@@ -337,7 +330,7 @@
                                 if (nits < x0) {
                                     // scale [0.0, x0] to [0.0, y0] linearly
                                     float slope = y0 / x0;
-                                    nits *= slope;
+                                    return color * slope;
                                 } else if (nits < x1) {
                                     // scale [x0, x1] to [y0, y1] linearly
                                     float slope = (y1 - y0) / (x1 - x0);
@@ -355,7 +348,8 @@
                                 }
                             }
 
-                            return color * (nits / max(1e-6, color.y));
+                            // color.y is greater than x0 and is thus non-zero
+                            return color * (nits / color.y);
                         }
                     )__SHADER__";
                     break;
@@ -386,7 +380,7 @@
                     if (nits <= x0) {
                         // scale [0.0, x0] to [0.0, y0] linearly
                         const float slope = y0 / x0;
-                        nits *= slope;
+                        return color * slope;
                     } else if (nits <= x1) {
                         // scale [x0, x1] to [y0, y1] using a curve
                         float t = (nits - x0) / (x1 - x0);
@@ -401,7 +395,8 @@
                         nits = (1.0 - t) * (1.0 - t) * y2 + 2.0 * (1.0 - t) * t * c3 + t * t * y3;
                     }
 
-                    return color * (nits / max(1e-6, color.y));
+                    // color.y is greater than x0 and is thus non-zero
+                    return color * (nits / color.y);
                 }
             )__SHADER__";
             break;
@@ -574,7 +569,7 @@
             fs << "uniform mat4 inputTransformMatrix;";
             fs << R"__SHADER__(
                 highp vec3 InputTransform(const highp vec3 color) {
-                    return vec3(inputTransformMatrix * vec4(color, 1.0));
+                    return clamp(vec3(inputTransformMatrix * vec4(color, 1.0)), 0.0, 1.0);
                 }
             )__SHADER__";
         } else {
@@ -647,7 +642,7 @@
     return fs.getString();
 }
 
-Program* ProgramCache::generateProgram(const Key& needs) {
+std::unique_ptr<Program> ProgramCache::generateProgram(const Key& needs) {
     ATRACE_CALL();
 
     // vertex shader
@@ -656,8 +651,7 @@
     // fragment shader
     String8 fs = generateFragmentShader(needs);
 
-    Program* program = new Program(needs, vs.string(), fs.string());
-    return program;
+    return std::make_unique<Program>(needs, vs.string(), fs.string());
 }
 
 void ProgramCache::useProgram(const Description& description) {
@@ -665,19 +659,19 @@
     Key needs(computeKey(description));
 
     // look-up the program in the cache
-    Program* program = mCache.valueFor(needs);
-    if (program == nullptr) {
+    auto it = mCache.find(needs);
+    if (it == mCache.end()) {
         // we didn't find our program, so generate one...
-        nsecs_t time = -systemTime();
-        program = generateProgram(needs);
-        mCache.add(needs, program);
-        time += systemTime();
+        nsecs_t time = systemTime();
+        it = mCache.emplace(needs, generateProgram(needs)).first;
+        time = systemTime() - time;
 
         ALOGV(">>> generated new program: needs=%08X, time=%u ms (%zu programs)", needs.mKey,
               uint32_t(ns2ms(time)), mCache.size());
     }
 
     // here we have a suitable program for this description
+    std::unique_ptr<Program>& program = it->second;
     if (program->isValid()) {
         program->use();
         program->setUniforms(description);
diff --git a/services/surfaceflinger/RenderEngine/gl/ProgramCache.h b/services/surfaceflinger/RenderEngine/gl/ProgramCache.h
index 47963eb..120b3d1 100644
--- a/services/surfaceflinger/RenderEngine/gl/ProgramCache.h
+++ b/services/surfaceflinger/RenderEngine/gl/ProgramCache.h
@@ -17,9 +17,11 @@
 #ifndef SF_RENDER_ENGINE_PROGRAMCACHE_H
 #define SF_RENDER_ENGINE_PROGRAMCACHE_H
 
+#include <memory>
+#include <unordered_map>
+
 #include <GLES2/gl2.h>
 #include <renderengine/private/Description.h>
-#include <utils/KeyedVector.h>
 #include <utils/Singleton.h>
 #include <utils/TypeHelpers.h>
 
@@ -155,18 +157,27 @@
         }
         inline bool isY410BT2020() const { return (mKey & Y410_BT2020_MASK) == Y410_BT2020_ON; }
 
-        // this is the definition of a friend function -- not a method of class Needs
-        friend inline int strictly_order_type(const Key& lhs, const Key& rhs) {
-            return (lhs.mKey < rhs.mKey) ? 1 : 0;
+        // for use by std::unordered_map
+
+        bool operator==(const Key& other) const {
+            return mKey == other.mKey;
         }
+
+        struct Hash {
+            size_t operator()(const Key& key) const {
+                return static_cast<size_t>(key.mKey);
+            }
+        };
     };
 
-    ProgramCache();
-    ~ProgramCache();
+    ProgramCache() = default;
+    ~ProgramCache() = default;
 
     // Generate shaders to populate the cache
     void primeCache(bool useColorManagement);
 
+    size_t getSize() const { return mCache.size(); }
+
     // useProgram lookup a suitable program in the cache or generates one
     // if none can be found.
     void useProgram(const Description& description);
@@ -183,15 +194,15 @@
     // Generate OETF based from Key.
     static void generateOETF(Formatter& fs, const Key& needs);
     // generates a program from the Key
-    static Program* generateProgram(const Key& needs);
+    static std::unique_ptr<Program> generateProgram(const Key& needs);
     // generates the vertex shader from the Key
     static String8 generateVertexShader(const Key& needs);
     // generates the fragment shader from the Key
     static String8 generateFragmentShader(const Key& needs);
 
     // Key/Value map used for caching Programs. Currently the cache
-    // is never shrunk.
-    DefaultKeyedVector<Key, Program*> mCache;
+    // is never shrunk (and the GL program objects are never deleted).
+    std::unordered_map<Key, std::unique_ptr<Program>, Key::Hash> mCache;
 };
 
 }  // namespace gl
diff --git a/services/surfaceflinger/RenderEngine/include/renderengine/Mesh.h b/services/surfaceflinger/RenderEngine/include/renderengine/Mesh.h
index 39ca2f7..15d2a11 100644
--- a/services/surfaceflinger/RenderEngine/include/renderengine/Mesh.h
+++ b/services/surfaceflinger/RenderEngine/include/renderengine/Mesh.h
@@ -17,6 +17,8 @@
 #ifndef SF_RENDER_ENGINE_MESH_H
 #define SF_RENDER_ENGINE_MESH_H
 
+#include <vector>
+
 #include <stdint.h>
 
 namespace android {
@@ -31,7 +33,7 @@
     };
 
     Mesh(Primitive primitive, size_t vertexCount, size_t vertexSize, size_t texCoordsSize = 0);
-    ~Mesh();
+    ~Mesh() = default;
 
     /*
      * VertexArray handles the stride automatically.
@@ -90,7 +92,8 @@
 
     float* getPositions();
     float* getTexCoords();
-    float* mVertices;
+
+    std::vector<float> mVertices;
     size_t mVertexCount;
     size_t mVertexSize;
     size_t mTexCoordsSize;
diff --git a/services/surfaceflinger/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp
index 54a1b51..cba9181 100644
--- a/services/surfaceflinger/Scheduler/DispSync.cpp
+++ b/services/surfaceflinger/Scheduler/DispSync.cpp
@@ -44,10 +44,6 @@
 
 namespace impl {
 
-// Setting this to true enables verbose tracing that can be used to debug
-// vsync event model or phase issues.
-static const bool kTraceDetailedInfo = false;
-
 // Setting this to true adds a zero-phase tracer for correlating with hardware
 // vsync events
 static const bool kEnableZeroPhaseTracer = false;
@@ -62,19 +58,20 @@
 #define LOG_TAG "DispSyncThread"
 class DispSyncThread : public Thread {
 public:
-    explicit DispSyncThread(const char* name)
+    DispSyncThread(const char* name, bool showTraceDetailedInfo)
           : mName(name),
             mStop(false),
             mPeriod(0),
             mPhase(0),
             mReferenceTime(0),
             mWakeupLatency(0),
-            mFrameNumber(0) {}
+            mFrameNumber(0),
+            mTraceDetailedInfo(showTraceDetailedInfo) {}
 
     virtual ~DispSyncThread() {}
 
     void updateModel(nsecs_t period, nsecs_t phase, nsecs_t referenceTime) {
-        if (kTraceDetailedInfo) ATRACE_CALL();
+        if (mTraceDetailedInfo) ATRACE_CALL();
         Mutex::Autolock lock(mMutex);
         mPeriod = period;
         mPhase = phase;
@@ -86,7 +83,7 @@
     }
 
     void stop() {
-        if (kTraceDetailedInfo) ATRACE_CALL();
+        if (mTraceDetailedInfo) ATRACE_CALL();
         Mutex::Autolock lock(mMutex);
         mStop = true;
         mCond.signal();
@@ -104,7 +101,7 @@
             { // Scope for lock
                 Mutex::Autolock lock(mMutex);
 
-                if (kTraceDetailedInfo) {
+                if (mTraceDetailedInfo) {
                     ATRACE_INT64("DispSync:Frame", mFrameNumber);
                 }
                 ALOGV("[%s] Frame %" PRId64, mName, mFrameNumber);
@@ -128,7 +125,7 @@
                 bool isWakeup = false;
 
                 if (now < targetTime) {
-                    if (kTraceDetailedInfo) ATRACE_NAME("DispSync waiting");
+                    if (mTraceDetailedInfo) ATRACE_NAME("DispSync waiting");
 
                     if (targetTime == INT64_MAX) {
                         ALOGV("[%s] Waiting forever", mName);
@@ -154,7 +151,7 @@
                 if (isWakeup) {
                     mWakeupLatency = ((mWakeupLatency * 63) + (now - targetTime)) / 64;
                     mWakeupLatency = min(mWakeupLatency, kMaxWakeupLatency);
-                    if (kTraceDetailedInfo) {
+                    if (mTraceDetailedInfo) {
                         ATRACE_INT64("DispSync:WakeupLat", now - targetTime);
                         ATRACE_INT64("DispSync:AvgWakeupLat", mWakeupLatency);
                     }
@@ -172,7 +169,7 @@
     }
 
     status_t addEventListener(const char* name, nsecs_t phase, DispSync::Callback* callback) {
-        if (kTraceDetailedInfo) ATRACE_CALL();
+        if (mTraceDetailedInfo) ATRACE_CALL();
         Mutex::Autolock lock(mMutex);
 
         for (size_t i = 0; i < mEventListeners.size(); i++) {
@@ -198,7 +195,7 @@
     }
 
     status_t removeEventListener(DispSync::Callback* callback) {
-        if (kTraceDetailedInfo) ATRACE_CALL();
+        if (mTraceDetailedInfo) ATRACE_CALL();
         Mutex::Autolock lock(mMutex);
 
         for (std::vector<EventListener>::iterator it = mEventListeners.begin();
@@ -214,7 +211,7 @@
     }
 
     status_t changePhaseOffset(DispSync::Callback* callback, nsecs_t phase) {
-        if (kTraceDetailedInfo) ATRACE_CALL();
+        if (mTraceDetailedInfo) ATRACE_CALL();
         Mutex::Autolock lock(mMutex);
 
         for (auto& eventListener : mEventListeners) {
@@ -254,7 +251,7 @@
     };
 
     nsecs_t computeNextEventTimeLocked(nsecs_t now) {
-        if (kTraceDetailedInfo) ATRACE_CALL();
+        if (mTraceDetailedInfo) ATRACE_CALL();
         ALOGV("[%s] computeNextEventTimeLocked", mName);
         nsecs_t nextEventTime = INT64_MAX;
         for (size_t i = 0; i < mEventListeners.size(); i++) {
@@ -270,7 +267,7 @@
     }
 
     std::vector<CallbackInvocation> gatherCallbackInvocationsLocked(nsecs_t now) {
-        if (kTraceDetailedInfo) ATRACE_CALL();
+        if (mTraceDetailedInfo) ATRACE_CALL();
         ALOGV("[%s] gatherCallbackInvocationsLocked @ %" PRId64, mName, ns2us(now));
 
         std::vector<CallbackInvocation> callbackInvocations;
@@ -293,7 +290,7 @@
     }
 
     nsecs_t computeListenerNextEventTimeLocked(const EventListener& listener, nsecs_t baseTime) {
-        if (kTraceDetailedInfo) ATRACE_CALL();
+        if (mTraceDetailedInfo) ATRACE_CALL();
         ALOGV("[%s] [%s] computeListenerNextEventTimeLocked(%" PRId64 ")", mName, listener.mName,
               ns2us(baseTime));
 
@@ -344,7 +341,7 @@
     }
 
     void fireCallbackInvocations(const std::vector<CallbackInvocation>& callbacks) {
-        if (kTraceDetailedInfo) ATRACE_CALL();
+        if (mTraceDetailedInfo) ATRACE_CALL();
         for (size_t i = 0; i < callbacks.size(); i++) {
             callbacks[i].mCallback->onDispSyncEvent(callbacks[i].mEventTime);
         }
@@ -365,6 +362,9 @@
 
     Mutex mMutex;
     Condition mCond;
+
+    // Flag to turn on logging in systrace.
+    const bool mTraceDetailedInfo;
 };
 
 #undef LOG_TAG
@@ -383,8 +383,13 @@
     bool mParity;
 };
 
-DispSync::DispSync(const char* name)
-      : mName(name), mRefreshSkipCount(0), mThread(new DispSyncThread(name)) {}
+DispSync::DispSync(const char* name) : mName(name), mRefreshSkipCount(0) {
+    // This flag offers the ability to turn on systrace logging from the shell.
+    char value[PROPERTY_VALUE_MAX];
+    property_get("debug.sf.dispsync_trace_detailed_info", value, "0");
+    mTraceDetailedInfo = atoi(value);
+    mThread = new DispSyncThread(name, mTraceDetailedInfo);
+}
 
 DispSync::~DispSync() {}
 
@@ -403,7 +408,7 @@
     reset();
     beginResync();
 
-    if (kTraceDetailedInfo && kEnableZeroPhaseTracer) {
+    if (mTraceDetailedInfo && kEnableZeroPhaseTracer) {
         mZeroPhaseTracer = std::make_unique<ZeroPhaseTracer>();
         addEventListener("ZeroPhaseTracer", 0, mZeroPhaseTracer.get());
     }
@@ -588,7 +593,7 @@
             ALOGV("[%s] Adjusting mPhase -> %" PRId64, mName, ns2us(mPhase));
         }
 
-        if (kTraceDetailedInfo) {
+        if (mTraceDetailedInfo) {
             ATRACE_INT64("DispSync:Period", mPeriod);
             ATRACE_INT64("DispSync:Phase", mPhase + mPeriod / 2);
         }
@@ -647,7 +652,7 @@
                  "No present times for model error.");
     }
 
-    if (kTraceDetailedInfo) {
+    if (mTraceDetailedInfo) {
         ATRACE_INT64("DispSync:Error", mError);
     }
 }
@@ -726,6 +731,54 @@
     result.appendFormat("current monotonic time: %" PRId64 "\n", now);
 }
 
+// TODO(b/113612090): Figure out how much of this is still relevant.
+// We need to determine the time when a buffer acquired now will be
+// displayed.  This can be calculated:
+//   time when previous buffer's actual-present fence was signaled
+//    + current display refresh rate * HWC latency
+//    + a little extra padding
+//
+// Buffer producers are expected to set their desired presentation time
+// based on choreographer time stamps, which (coming from vsync events)
+// will be slightly later then the actual-present timing.  If we get a
+// desired-present time that is unintentionally a hair after the next
+// vsync, we'll hold the frame when we really want to display it.  We
+// need to take the offset between actual-present and reported-vsync
+// into account.
+//
+// If the system is configured without a DispSync phase offset for the app,
+// we also want to throw in a bit of padding to avoid edge cases where we
+// just barely miss.  We want to do it here, not in every app.  A major
+// source of trouble is the app's use of the display's ideal refresh time
+// (via Display.getRefreshRate()), which could be off of the actual refresh
+// by a few percent, with the error multiplied by the number of frames
+// between now and when the buffer should be displayed.
+//
+// If the refresh reported to the app has a phase offset, we shouldn't need
+// to tweak anything here.
+nsecs_t DispSync::expectedPresentTime() {
+    // The HWC doesn't currently have a way to report additional latency.
+    // Assume that whatever we submit now will appear right after the flip.
+    // For a smart panel this might be 1.  This is expressed in frames,
+    // rather than time, because we expect to have a constant frame delay
+    // regardless of the refresh rate.
+    const uint32_t hwcLatency = 0;
+
+    // Ask DispSync when the next refresh will be (CLOCK_MONOTONIC).
+    const nsecs_t nextRefresh = computeNextRefresh(hwcLatency);
+
+    // The DispSync time is already adjusted for the difference between
+    // vsync and reported-vsync (SurfaceFlinger::dispSyncPresentTimeOffset), so
+    // we don't need to factor that in here.  Pad a little to avoid
+    // weird effects if apps might be requesting times right on the edge.
+    nsecs_t extraPadding = 0;
+    if (SurfaceFlinger::vsyncPhaseOffsetNs == 0) {
+        extraPadding = 1000000; // 1ms (6% of 60Hz)
+    }
+
+    return nextRefresh + extraPadding;
+}
+
 } // namespace impl
 
 } // namespace android
diff --git a/services/surfaceflinger/Scheduler/DispSync.h b/services/surfaceflinger/Scheduler/DispSync.h
index b3aef2d..5b511f4 100644
--- a/services/surfaceflinger/Scheduler/DispSync.h
+++ b/services/surfaceflinger/Scheduler/DispSync.h
@@ -57,6 +57,7 @@
     virtual status_t changePhaseOffset(Callback* callback, nsecs_t phase) = 0;
     virtual nsecs_t computeNextRefresh(int periodOffset) const = 0;
     virtual void setIgnorePresentFences(bool ignore) = 0;
+    virtual nsecs_t expectedPresentTime() = 0;
 
     virtual void dump(String8& result) const = 0;
 };
@@ -164,6 +165,9 @@
     // true from addPresentFence() and addResyncSample().
     void setIgnorePresentFences(bool ignore) override;
 
+    // Determine the expected present time when a buffer acquired now will be displayed.
+    nsecs_t expectedPresentTime();
+
     // dump appends human-readable debug info to the result string.
     void dump(String8& result) const override;
 
@@ -237,6 +241,9 @@
     bool mIgnorePresentFences;
 
     std::unique_ptr<Callback> mZeroPhaseTracer;
+
+    // Flag to turn on logging in systrace.
+    bool mTraceDetailedInfo = false;
 };
 
 } // namespace impl
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 54e19c7..18a8bb1 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -20,15 +20,25 @@
 #include <cstdint>
 #include <memory>
 
+#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
+#include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h>
+#include <android/hardware/configstore/1.2/ISurfaceFlingerConfigs.h>
+#include <configstore/Utils.h>
+
 #include <gui/ISurfaceComposer.h>
+#include <ui/DisplayStatInfo.h>
 
 #include "DispSync.h"
 #include "DispSyncSource.h"
+#include "EventControlThread.h"
 #include "EventThread.h"
 #include "InjectVSyncSource.h"
 
 namespace android {
 
+using namespace android::hardware::configstore;
+using namespace android::hardware::configstore::V1_0;
+
 #define RETURN_VALUE_IF_INVALID(value) \
     if (handle == nullptr || mConnections.count(handle->id) == 0) return value
 #define RETURN_IF_INVALID() \
@@ -36,17 +46,34 @@
 
 std::atomic<int64_t> Scheduler::sNextId = 0;
 
+Scheduler::Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function)
+      : mHasSyncFramework(
+                getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasSyncFramework>(true)),
+        mDispSyncPresentTimeOffset(
+                getInt64<ISurfaceFlingerConfigs,
+                         &ISurfaceFlingerConfigs::presentTimeOffsetFromVSyncNs>(0)),
+        mPrimaryHWVsyncEnabled(false),
+        mHWVsyncAvailable(false) {
+    // Note: We create a local temporary with the real DispSync implementation
+    // type temporarily so we can initialize it with the configured values,
+    // before storing it for more generic use using the interface type.
+    auto primaryDispSync = std::make_unique<impl::DispSync>("SchedulerDispSync");
+    primaryDispSync->init(mHasSyncFramework, mDispSyncPresentTimeOffset);
+    mPrimaryDispSync = std::move(primaryDispSync);
+    mEventControlThread = std::make_unique<impl::EventControlThread>(function);
+}
+
 Scheduler::~Scheduler() = default;
 
 sp<Scheduler::ConnectionHandle> Scheduler::createConnection(
-        const std::string& connectionName, DispSync* dispSync, int64_t phaseOffsetNs,
+        const std::string& connectionName, int64_t phaseOffsetNs,
         impl::EventThread::ResyncWithRateLimitCallback resyncCallback,
         impl::EventThread::InterceptVSyncsCallback interceptCallback) {
     const int64_t id = sNextId++;
     ALOGV("Creating a connection handle with ID: %" PRId64 "\n", id);
 
     std::unique_ptr<EventThread> eventThread =
-            makeEventThread(connectionName, dispSync, phaseOffsetNs, resyncCallback,
+            makeEventThread(connectionName, mPrimaryDispSync.get(), phaseOffsetNs, resyncCallback,
                             interceptCallback);
     auto connection = std::make_unique<Connection>(new ConnectionHandle(id),
                                                    eventThread->createEventConnection(),
@@ -108,4 +135,65 @@
     RETURN_IF_INVALID();
     mConnections[handle->id]->thread->setPhaseOffset(phaseOffset);
 }
+
+void Scheduler::getDisplayStatInfo(DisplayStatInfo* stats) {
+    stats->vsyncTime = mPrimaryDispSync->computeNextRefresh(0);
+    stats->vsyncPeriod = mPrimaryDispSync->getPeriod();
+}
+
+void Scheduler::enableHardwareVsync() {
+    std::lock_guard<std::mutex> lock(mHWVsyncLock);
+    if (!mPrimaryHWVsyncEnabled && mHWVsyncAvailable) {
+        mPrimaryDispSync->beginResync();
+        mEventControlThread->setVsyncEnabled(true);
+        mPrimaryHWVsyncEnabled = true;
+    }
+}
+
+void Scheduler::disableHardwareVsync(bool makeUnavailable) {
+    std::lock_guard<std::mutex> lock(mHWVsyncLock);
+    if (mPrimaryHWVsyncEnabled) {
+        mEventControlThread->setVsyncEnabled(false);
+        mPrimaryDispSync->endResync();
+        mPrimaryHWVsyncEnabled = false;
+    }
+    if (makeUnavailable) {
+        mHWVsyncAvailable = false;
+    }
+}
+
+void Scheduler::setVsyncPeriod(const nsecs_t period) {
+    mPrimaryDispSync->reset();
+    mPrimaryDispSync->setPeriod(period);
+    enableHardwareVsync();
+}
+
+void Scheduler::addResyncSample(const nsecs_t timestamp) {
+    bool needsHwVsync = false;
+    { // Scope for the lock
+        std::lock_guard<std::mutex> lock(mHWVsyncLock);
+        if (mPrimaryHWVsyncEnabled) {
+            needsHwVsync = mPrimaryDispSync->addResyncSample(timestamp);
+        }
+    }
+
+    if (needsHwVsync) {
+        enableHardwareVsync();
+    } else {
+        disableHardwareVsync(false);
+    }
+}
+
+void Scheduler::addPresentFence(const std::shared_ptr<FenceTime>& fenceTime) {
+    if (mPrimaryDispSync->addPresentFence(fenceTime)) {
+        enableHardwareVsync();
+    } else {
+        disableHardwareVsync(false);
+    }
+}
+
+void Scheduler::setIgnorePresentFences(bool ignore) {
+    mPrimaryDispSync->setIgnorePresentFences(ignore);
+}
+
 } // namespace android
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index fcb46e6..fdafe58 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -20,22 +20,31 @@
 #include <memory>
 
 #include <gui/ISurfaceComposer.h>
+#include <ui/DisplayStatInfo.h>
 
 #include "DispSync.h"
+#include "EventControlThread.h"
 #include "EventThread.h"
 #include "InjectVSyncSource.h"
 
 namespace android {
 
+class EventControlThread;
+
 class Scheduler {
 public:
+    // Enum to indicate whether to start the transaction early, or at vsync time.
+    enum class TransactionStart { EARLY, NORMAL };
+
     /* The scheduler handle is a BBinder object passed to the client from which we can extract
      * an ID for subsequent operations.
      */
     class ConnectionHandle : public BBinder {
     public:
         ConnectionHandle(int64_t id) : id(id) {}
+
         ~ConnectionHandle() = default;
+
         const int64_t id;
     };
 
@@ -44,6 +53,7 @@
         Connection(sp<ConnectionHandle> handle, sp<BnDisplayEventConnection> eventConnection,
                    std::unique_ptr<EventThread> eventThread)
               : handle(handle), eventConnection(eventConnection), thread(std::move(eventThread)) {}
+
         ~Connection() = default;
 
         sp<ConnectionHandle> handle;
@@ -51,32 +61,48 @@
         const std::unique_ptr<EventThread> thread;
     };
 
-    Scheduler() = default;
+    explicit Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function);
+
     virtual ~Scheduler();
 
     /** Creates an EventThread connection. */
     sp<ConnectionHandle> createConnection(
-            const std::string& connectionName, DispSync* dispSync, int64_t phaseOffsetNs,
+            const std::string& connectionName, int64_t phaseOffsetNs,
             impl::EventThread::ResyncWithRateLimitCallback resyncCallback,
             impl::EventThread::InterceptVSyncsCallback interceptCallback);
+
     sp<IDisplayEventConnection> createDisplayEventConnection(const sp<ConnectionHandle>& handle);
 
     // Getter methods.
     EventThread* getEventThread(const sp<ConnectionHandle>& handle);
+
     sp<BnDisplayEventConnection> getEventConnection(const sp<ConnectionHandle>& handle);
 
     // Should be called when receiving a hotplug event.
     void hotplugReceived(const sp<ConnectionHandle>& handle, EventThread::DisplayType displayType,
                          bool connected);
+
     // Should be called after the screen is turned on.
     void onScreenAcquired(const sp<ConnectionHandle>& handle);
+
     // Should be called before the screen is turned off.
     void onScreenReleased(const sp<ConnectionHandle>& handle);
+
     // Should be called when dumpsys command is received.
     void dump(const sp<ConnectionHandle>& handle, String8& result) const;
+
     // Offers ability to modify phase offset in the event thread.
     void setPhaseOffset(const sp<ConnectionHandle>& handle, nsecs_t phaseOffset);
 
+    void getDisplayStatInfo(DisplayStatInfo* stats);
+
+    void enableHardwareVsync();
+    void disableHardwareVsync(bool makeUnavailable);
+    void setVsyncPeriod(const nsecs_t period);
+    void addResyncSample(const nsecs_t timestamp);
+    void addPresentFence(const std::shared_ptr<FenceTime>& fenceTime);
+    void setIgnorePresentFences(bool ignore);
+
 protected:
     virtual std::unique_ptr<EventThread> makeEventThread(
             const std::string& connectionName, DispSync* dispSync, int64_t phaseOffsetNs,
@@ -84,8 +110,29 @@
             impl::EventThread::InterceptVSyncsCallback interceptCallback);
 
 private:
+    // TODO(b/113612090): Instead of letting BufferQueueLayer to access mDispSync directly, it
+    // should make request to Scheduler to compute next refresh.
+    friend class BufferQueueLayer;
+
+    // If fences from sync Framework are supported.
+    const bool mHasSyncFramework;
+
+    // The offset in nanoseconds to use, when DispSync timestamps present fence
+    // signaling time.
+    const nsecs_t mDispSyncPresentTimeOffset;
+
+    // Each connection has it's own ID. This variable keeps track of the count.
     static std::atomic<int64_t> sNextId;
+
+    // Connections are stored in a map <connection ID, connection> for easy retrieval.
     std::unordered_map<int64_t, std::unique_ptr<Connection>> mConnections;
+
+    std::mutex mHWVsyncLock;
+    bool mPrimaryHWVsyncEnabled GUARDED_BY(mHWVsyncLock);
+    bool mHWVsyncAvailable GUARDED_BY(mHWVsyncLock);
+
+    std::unique_ptr<DispSync> mPrimaryDispSync;
+    std::unique_ptr<EventControlThread> mEventControlThread;
 };
 
 } // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.h b/services/surfaceflinger/Scheduler/VSyncModulator.h
index ea8ca4c..dde0c57 100644
--- a/services/surfaceflinger/Scheduler/VSyncModulator.h
+++ b/services/surfaceflinger/Scheduler/VSyncModulator.h
@@ -39,8 +39,6 @@
         nsecs_t app;
     };
 
-    enum TransactionStart { EARLY, NORMAL };
-
     // Sets the phase offsets
     //
     // sfEarly: The phase offset when waking up SF early, which happens when marking a transaction
@@ -75,13 +73,14 @@
         mSfConnectionHandle = sfConnectionHandle;
     }
 
-    void setTransactionStart(TransactionStart transactionStart) {
-        if (transactionStart == TransactionStart::EARLY) {
+    void setTransactionStart(Scheduler::TransactionStart transactionStart) {
+        if (transactionStart == Scheduler::TransactionStart::EARLY) {
             mRemainingEarlyFrameCount = MIN_EARLY_FRAME_COUNT;
         }
 
         // An early transaction stays an early transaction.
-        if (transactionStart == mTransactionStart || mTransactionStart == TransactionStart::EARLY) {
+        if (transactionStart == mTransactionStart ||
+            mTransactionStart == Scheduler::TransactionStart::EARLY) {
             return;
         }
         mTransactionStart = transactionStart;
@@ -89,8 +88,8 @@
     }
 
     void onTransactionHandled() {
-        if (mTransactionStart == TransactionStart::NORMAL) return;
-        mTransactionStart = TransactionStart::NORMAL;
+        if (mTransactionStart == Scheduler::TransactionStart::NORMAL) return;
+        mTransactionStart = Scheduler::TransactionStart::NORMAL;
         updateOffsets();
     }
 
@@ -138,7 +137,8 @@
     }
 
     Offsets getOffsets() {
-        if (mTransactionStart == TransactionStart::EARLY || mRemainingEarlyFrameCount > 0) {
+        if (mTransactionStart == Scheduler::TransactionStart::EARLY ||
+            mRemainingEarlyFrameCount > 0) {
             return mEarlyOffsets;
         } else if (mLastFrameUsedRenderEngine) {
             return mEarlyGlOffsets;
@@ -160,7 +160,8 @@
 
     std::atomic<Offsets> mOffsets;
 
-    std::atomic<TransactionStart> mTransactionStart = TransactionStart::NORMAL;
+    std::atomic<Scheduler::TransactionStart> mTransactionStart =
+            Scheduler::TransactionStart::NORMAL;
     std::atomic<bool> mLastFrameUsedRenderEngine = false;
     std::atomic<int> mRemainingEarlyFrameCount = 0;
 };
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 37b32ed..f0723e8 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -584,15 +584,14 @@
 
     // start the EventThread
     if (mUseScheduler) {
-        mScheduler = std::make_unique<Scheduler>();
+        mScheduler = std::make_unique<Scheduler>(
+                [this](bool enabled) { setVsyncEnabled(HWC_DISPLAY_PRIMARY, enabled); });
         mAppConnectionHandle =
-                mScheduler->createConnection("appConnection", mPrimaryDispSync.get(),
-                                             SurfaceFlinger::vsyncPhaseOffsetNs,
+                mScheduler->createConnection("appConnection", SurfaceFlinger::vsyncPhaseOffsetNs,
                                              [this] { resyncWithRateLimit(); },
                                              impl::EventThread::InterceptVSyncsCallback());
         mSfConnectionHandle =
-                mScheduler->createConnection("sfConnection", mPrimaryDispSync.get(),
-                                             SurfaceFlinger::sfVsyncPhaseOffsetNs,
+                mScheduler->createConnection("sfConnection", SurfaceFlinger::sfVsyncPhaseOffsetNs,
                                              [this] { resyncWithRateLimit(); },
                                              [this](nsecs_t timestamp) {
                                                  mInterceptor->saveVSyncEvent(timestamp);
@@ -912,10 +911,13 @@
         return BAD_VALUE;
     }
 
-    // FIXME for now we always return stats for the primary display
-    memset(stats, 0, sizeof(*stats));
-    stats->vsyncTime = mPrimaryDispSync->computeNextRefresh(0);
-    stats->vsyncPeriod = mPrimaryDispSync->getPeriod();
+    // FIXME for now we always return stats for the primary display.
+    if (mUseScheduler) {
+        mScheduler->getDisplayStatInfo(stats);
+    } else {
+        stats->vsyncTime = mPrimaryDispSync->computeNextRefresh(0);
+        stats->vsyncPeriod = mPrimaryDispSync->getPeriod();
+    }
     return NO_ERROR;
 }
 
@@ -1246,13 +1248,17 @@
     const auto activeConfig = getHwComposer().getActiveConfig(displayId);
     const nsecs_t period = activeConfig->getVsyncPeriod();
 
-    mPrimaryDispSync->reset();
-    mPrimaryDispSync->setPeriod(period);
+    if (mUseScheduler) {
+        mScheduler->setVsyncPeriod(period);
+    } else {
+        mPrimaryDispSync->reset();
+        mPrimaryDispSync->setPeriod(period);
 
-    if (!mPrimaryHWVsyncEnabled) {
-        mPrimaryDispSync->beginResync();
-        mEventControlThread->setVsyncEnabled(true);
-        mPrimaryHWVsyncEnabled = true;
+        if (!mPrimaryHWVsyncEnabled) {
+            mPrimaryDispSync->beginResync();
+            mEventControlThread->setVsyncEnabled(true);
+            mPrimaryHWVsyncEnabled = true;
+        }
     }
 }
 
@@ -1300,19 +1306,22 @@
         return;
     }
 
-    bool needsHwVsync = false;
-
-    { // Scope for the lock
-        Mutex::Autolock _l(mHWVsyncLock);
-        if (mPrimaryHWVsyncEnabled) {
-            needsHwVsync = mPrimaryDispSync->addResyncSample(timestamp);
-        }
-    }
-
-    if (needsHwVsync) {
-        enableHardwareVsync();
+    if (mUseScheduler) {
+        mScheduler->addResyncSample(timestamp);
     } else {
-        disableHardwareVsync(false);
+        bool needsHwVsync = false;
+        { // Scope for the lock
+            Mutex::Autolock _l(mHWVsyncLock);
+            if (mPrimaryHWVsyncEnabled) {
+                needsHwVsync = mPrimaryDispSync->addResyncSample(timestamp);
+            }
+        }
+
+        if (needsHwVsync) {
+            enableHardwareVsync();
+        } else {
+            disableHardwareVsync(false);
+        }
     }
 }
 
@@ -1364,7 +1373,11 @@
 
 // Note: it is assumed the caller holds |mStateLock| when this is called
 void SurfaceFlinger::resetDisplayState() {
-    disableHardwareVsync(true);
+    if (mUseScheduler) {
+        mScheduler->disableHardwareVsync(true);
+    } else {
+        disableHardwareVsync(true);
+    }
     // Clear the drawing state so that the logic inside of
     // handleTransactionLocked will fire. It will determine the delta between
     // mCurrentState and mDrawingState and re-apply all changes when we make the
@@ -1432,12 +1445,17 @@
 
     // The present fences returned from vr_hwc are not an accurate
     // representation of vsync times.
-    mPrimaryDispSync->setIgnorePresentFences(getBE().mHwc->isUsingVrComposer() ||
-                                             !hasSyncFramework);
+    if (mUseScheduler) {
+        mScheduler->setIgnorePresentFences(getBE().mHwc->isUsingVrComposer() || !hasSyncFramework);
+    } else {
+        mPrimaryDispSync->setIgnorePresentFences(getBE().mHwc->isUsingVrComposer() ||
+                                                 !hasSyncFramework);
+    }
 
     // Use phase of 0 since phase is not known.
     // Use latency of 0, which will snap to the ideal latency.
-    setCompositorTimingSnapped(0, period, 0);
+    DisplayStatInfo stats{0 /* vsyncTime */, period /* vsyncPeriod */};
+    setCompositorTimingSnapped(stats, 0);
 
     resyncToHardwareVsync(false);
 
@@ -1736,9 +1754,8 @@
     }
 }
 
-void SurfaceFlinger::updateCompositorTiming(
-        nsecs_t vsyncPhase, nsecs_t vsyncInterval, nsecs_t compositeTime,
-        std::shared_ptr<FenceTime>& presentFenceTime) {
+void SurfaceFlinger::updateCompositorTiming(const DisplayStatInfo& stats, nsecs_t compositeTime,
+                                            std::shared_ptr<FenceTime>& presentFenceTime) {
     // Update queue of past composite+present times and determine the
     // most recently known composite to present latency.
     getBE().mCompositePresentTimes.push({compositeTime, presentFenceTime});
@@ -1760,21 +1777,20 @@
         getBE().mCompositePresentTimes.pop();
     }
 
-    setCompositorTimingSnapped(
-            vsyncPhase, vsyncInterval, compositeToPresentLatency);
+    setCompositorTimingSnapped(stats, compositeToPresentLatency);
 }
 
-void SurfaceFlinger::setCompositorTimingSnapped(nsecs_t vsyncPhase,
-        nsecs_t vsyncInterval, nsecs_t compositeToPresentLatency) {
+void SurfaceFlinger::setCompositorTimingSnapped(const DisplayStatInfo& stats,
+                                                nsecs_t compositeToPresentLatency) {
     // Integer division and modulo round toward 0 not -inf, so we need to
     // treat negative and positive offsets differently.
-    nsecs_t idealLatency = (sfVsyncPhaseOffsetNs > 0) ?
-            (vsyncInterval - (sfVsyncPhaseOffsetNs % vsyncInterval)) :
-            ((-sfVsyncPhaseOffsetNs) % vsyncInterval);
+    nsecs_t idealLatency = (sfVsyncPhaseOffsetNs > 0)
+            ? (stats.vsyncPeriod - (sfVsyncPhaseOffsetNs % stats.vsyncPeriod))
+            : ((-sfVsyncPhaseOffsetNs) % stats.vsyncPeriod);
 
     // Just in case sfVsyncPhaseOffsetNs == -vsyncInterval.
     if (idealLatency <= 0) {
-        idealLatency = vsyncInterval;
+        idealLatency = stats.vsyncPeriod;
     }
 
     // Snap the latency to a value that removes scheduling jitter from the
@@ -1783,15 +1799,14 @@
     // something (such as user input) to an accurate diasplay time.
     // Snapping also allows an app to precisely calculate sfVsyncPhaseOffsetNs
     // with (presentLatency % interval).
-    nsecs_t bias = vsyncInterval / 2;
-    int64_t extraVsyncs =
-            (compositeToPresentLatency - idealLatency + bias) / vsyncInterval;
-    nsecs_t snappedCompositeToPresentLatency = (extraVsyncs > 0) ?
-            idealLatency + (extraVsyncs * vsyncInterval) : idealLatency;
+    nsecs_t bias = stats.vsyncPeriod / 2;
+    int64_t extraVsyncs = (compositeToPresentLatency - idealLatency + bias) / stats.vsyncPeriod;
+    nsecs_t snappedCompositeToPresentLatency =
+            (extraVsyncs > 0) ? idealLatency + (extraVsyncs * stats.vsyncPeriod) : idealLatency;
 
     std::lock_guard<std::mutex> lock(getBE().mCompositorTimingLock);
-    getBE().mCompositorTiming.deadline = vsyncPhase - idealLatency;
-    getBE().mCompositorTiming.interval = vsyncInterval;
+    getBE().mCompositorTiming.deadline = stats.vsyncTime - idealLatency;
+    getBE().mCompositorTiming.interval = stats.vsyncPeriod;
     getBE().mCompositorTiming.presentLatency = snappedCompositeToPresentLatency;
 }
 
@@ -1825,14 +1840,18 @@
     auto presentFenceTime = std::make_shared<FenceTime>(mPreviousPresentFence);
     getBE().mDisplayTimeline.push(presentFenceTime);
 
-    nsecs_t vsyncPhase = mPrimaryDispSync->computeNextRefresh(0);
-    nsecs_t vsyncInterval = mPrimaryDispSync->getPeriod();
+    DisplayStatInfo stats;
+    if (mUseScheduler) {
+        mScheduler->getDisplayStatInfo(&stats);
+    } else {
+        stats.vsyncTime = mPrimaryDispSync->computeNextRefresh(0);
+        stats.vsyncPeriod = mPrimaryDispSync->getPeriod();
+    }
 
     // We use the mRefreshStartTime which might be sampled a little later than
     // when we started doing work for this frame, but that should be okay
     // since updateCompositorTiming has snapping logic.
-    updateCompositorTiming(
-        vsyncPhase, vsyncInterval, mRefreshStartTime, presentFenceTime);
+    updateCompositorTiming(stats, mRefreshStartTime, presentFenceTime);
     CompositorTiming compositorTiming;
     {
         std::lock_guard<std::mutex> lock(getBE().mCompositorTimingLock);
@@ -1849,16 +1868,24 @@
     });
 
     if (presentFenceTime->isValid()) {
-        if (mPrimaryDispSync->addPresentFence(presentFenceTime)) {
-            enableHardwareVsync();
+        if (mUseScheduler) {
+            mScheduler->addPresentFence(presentFenceTime);
         } else {
-            disableHardwareVsync(false);
+            if (mPrimaryDispSync->addPresentFence(presentFenceTime)) {
+                enableHardwareVsync();
+            } else {
+                disableHardwareVsync(false);
+            }
         }
     }
 
     if (!hasSyncFramework) {
         if (display && getHwComposer().isConnected(display->getId()) && display->isPoweredOn()) {
-            enableHardwareVsync();
+            if (mUseScheduler) {
+                mScheduler->enableHardwareVsync();
+            } else {
+                enableHardwareVsync();
+            }
         }
     }
 
@@ -1892,7 +1919,7 @@
         mHasPoweredOff = false;
     } else {
         nsecs_t elapsedTime = currentTime - getBE().mLastSwapTime;
-        size_t numPeriods = static_cast<size_t>(elapsedTime / vsyncInterval);
+        size_t numPeriods = static_cast<size_t>(elapsedTime / stats.vsyncPeriod);
         if (numPeriods < SurfaceFlingerBE::NUM_BUCKETS - 1) {
             getBE().mFrameBuckets[numPeriods] += elapsedTime;
         } else {
@@ -3039,7 +3066,8 @@
     mDrawingState.traverseInZOrder([&](Layer* layer) {
         if (layer->hasReadyFrame()) {
             frameQueued = true;
-            if (layer->shouldPresentNow(*mPrimaryDispSync)) {
+            const nsecs_t expectedPresentTime = mPrimaryDispSync->expectedPresentTime();
+            if (layer->shouldPresentNow(expectedPresentTime)) {
                 mLayersWithQueuedFrames.push_back(layer);
             } else {
                 layer->useEmptyDamage();
@@ -3371,11 +3399,11 @@
 }
 
 uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags) {
-    return setTransactionFlags(flags, VSyncModulator::TransactionStart::NORMAL);
+    return setTransactionFlags(flags, Scheduler::TransactionStart::NORMAL);
 }
 
 uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags,
-        VSyncModulator::TransactionStart transactionStart) {
+                                             Scheduler::TransactionStart transactionStart) {
     uint32_t old = mTransactionFlags.fetch_or(flags);
     mVsyncModulator.setTransactionStart(transactionStart);
     if ((old & flags)==0) { // wake the server up
@@ -3466,9 +3494,8 @@
         }
 
         // this triggers the transaction
-        const auto start = (flags & eEarlyWakeup)
-                ? VSyncModulator::TransactionStart::EARLY
-                : VSyncModulator::TransactionStart::NORMAL;
+        const auto start = (flags & eEarlyWakeup) ? Scheduler::TransactionStart::EARLY
+                                                  : Scheduler::TransactionStart::NORMAL;
         setTransactionFlags(transactionFlags, start);
 
         // if this is a synchronous transaction, wait for it to take effect
@@ -3991,7 +4018,8 @@
 
     // Use phase of 0 since phase is not known.
     // Use latency of 0, which will snap to the ideal latency.
-    setCompositorTimingSnapped(0, period, 0);
+    DisplayStatInfo stats{0 /* vsyncTime */, period /* vsyncPeriod */};
+    setCompositorTimingSnapped(stats, 0);
 }
 
 void SurfaceFlinger::initializeDisplays() {
@@ -4057,8 +4085,11 @@
         }
 
         if (display->isPrimary() && currentMode != HWC_POWER_MODE_DOZE_SUSPEND) {
-            disableHardwareVsync(true); // also cancels any in-progress resync
-
+            if (mUseScheduler) {
+                mScheduler->disableHardwareVsync(true);
+            } else {
+                disableHardwareVsync(true); // also cancels any in-progress resync
+            }
             // FIXME: eventthread only knows about the main display right now
             if (mUseScheduler) {
                 mScheduler->onScreenReleased(mAppConnectionHandle);
@@ -4086,7 +4117,11 @@
     } else if (mode == HWC_POWER_MODE_DOZE_SUSPEND) {
         // Leave display going to doze
         if (display->isPrimary()) {
-            disableHardwareVsync(true); // also cancels any in-progress resync
+            if (mUseScheduler) {
+                mScheduler->disableHardwareVsync(true);
+            } else {
+                disableHardwareVsync(true); // also cancels any in-progress resync
+            }
             // FIXME: eventthread only knows about the main display right now
             if (mUseScheduler) {
                 mScheduler->onScreenReleased(mAppConnectionHandle);
@@ -5033,6 +5068,7 @@
             // Needs to be shifted to proper binder interface when we productize
             case 1016: {
                 n = data.readInt32();
+                // TODO(b/113612090): Evaluate if this can be removed.
                 mPrimaryDispSync->setRefreshSkipCount(n);
                 return NO_ERROR;
             }
@@ -5161,9 +5197,17 @@
                 }
 
                 if ((frequencyScaler.multiplier == 1) && (frequencyScaler.divisor == 1)) {
-                    enableHardwareVsync();
+                    if (mUseScheduler) {
+                        mScheduler->enableHardwareVsync();
+                    } else {
+                        enableHardwareVsync();
+                    }
                 } else {
-                    disableHardwareVsync(true);
+                    if (mUseScheduler) {
+                        mScheduler->disableHardwareVsync(true);
+                    } else {
+                        disableHardwareVsync(true);
+                    }
                 }
                 mPrimaryDispSync->scalePeriod(frequencyScaler);
                 getBE().mHwc->setDisplayFrequencyScaleParameters(frequencyScaler);
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index a0f7c75..f535c4e 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -523,7 +523,7 @@
     uint32_t peekTransactionFlags();
     // Can only be called from the main thread or with mStateLock held
     uint32_t setTransactionFlags(uint32_t flags);
-    uint32_t setTransactionFlags(uint32_t flags, VSyncModulator::TransactionStart transactionStart);
+    uint32_t setTransactionFlags(uint32_t flags, Scheduler::TransactionStart transactionStart);
     void commitTransaction();
     bool containsAnyInvalidClientState(const Vector<ComposerState>& states);
     uint32_t setClientStateLocked(const ComposerState& composerState);
@@ -662,12 +662,10 @@
 
     void preComposition();
     void postComposition();
-    void updateCompositorTiming(
-            nsecs_t vsyncPhase, nsecs_t vsyncInterval, nsecs_t compositeTime,
-            std::shared_ptr<FenceTime>& presentFenceTime);
-    void setCompositorTimingSnapped(
-            nsecs_t vsyncPhase, nsecs_t vsyncInterval,
-            nsecs_t compositeToPresentLatency);
+    void updateCompositorTiming(const DisplayStatInfo& stats, nsecs_t compositeTime,
+                                std::shared_ptr<FenceTime>& presentFenceTime);
+    void setCompositorTimingSnapped(const DisplayStatInfo& stats,
+                                    nsecs_t compositeToPresentLatency);
     void rebuildLayerStacks();
 
     ui::Dataspace getBestDataspace(const sp<const DisplayDevice>& display,
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index d77a324..0bc1c0a 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -32,11 +32,8 @@
 namespace android {
 
 TimeStats& TimeStats::getInstance() {
-    static std::unique_ptr<TimeStats> sInstance;
-    static std::once_flag sOnceFlag;
-
-    std::call_once(sOnceFlag, [] { sInstance.reset(new TimeStats); });
-    return *sInstance.get();
+    static TimeStats sInstance;
+    return sInstance;
 }
 
 void TimeStats::parseArgs(bool asProto, const Vector<String16>& args, size_t& index,
diff --git a/services/surfaceflinger/tests/SurfaceFlinger_test.filter b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
index 34d0fd7..8bd5fcb 100644
--- a/services/surfaceflinger/tests/SurfaceFlinger_test.filter
+++ b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
@@ -1,5 +1,5 @@
 {
         "presubmit": {
-            "filter": "CredentialsTest.*:LayerTransactionTest.*:LayerUpdateTest.*:ChildLayerTest.*:SurfaceFlingerStress.*:CropLatchingTest.*:GeometryLatchingTest.*:ScreenCaptureTest.*:DereferenceSurfaceControlTest.*:SurfaceInterceptorTest.*"
+            "filter": "CredentialsTest.*:SurfaceFlingerStress.*:SurfaceInterceptorTest.*:LayerTransactionTest.*:LayerTypeTransactionTest.*:LayerUpdateTest.*:GeometryLatchingTest.*:CropLatchingTest.*:ChildLayerTest.*:ScreenCaptureTest.*:ScreenCaptureChildOnlyTest.*:DereferenceSurfaceControlTest.*"
         }
 }
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index df0d982..be91a9c 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -6,8 +6,11 @@
 
 #include <log/log.h>
 
+#include <mutex>
+
 #include "AsyncCallRecorder.h"
 #include "Scheduler/DispSync.h"
+#include "Scheduler/EventControlThread.h"
 #include "Scheduler/EventThread.h"
 #include "Scheduler/Scheduler.h"
 #include "mock/MockDispSync.h"
@@ -37,7 +40,7 @@
     class MockScheduler : public android::Scheduler {
     public:
         MockScheduler(std::unique_ptr<EventThread> eventThread)
-              : mEventThread(std::move(eventThread)) {}
+              : Scheduler([](bool) {}), mEventThread(std::move(eventThread)) {}
 
         std::unique_ptr<EventThread> makeEventThread(
                 const std::string& /* connectionName */, DispSync* /* dispSync */,
@@ -81,9 +84,9 @@
     EXPECT_CALL(*mEventThread, createEventConnection())
             .WillRepeatedly(Return(mEventThreadConnection));
 
-    mConnectionHandle = mScheduler->createConnection("appConnection", mPrimaryDispSync, 16,
-                                                     mResyncCallRecorder.getInvocable(),
-                                                     mInterceptVSyncCallRecorder.getInvocable());
+    mConnectionHandle =
+            mScheduler->createConnection("appConnection", 16, mResyncCallRecorder.getInvocable(),
+                                         mInterceptVSyncCallRecorder.getInvocable());
 }
 
 SchedulerTest::~SchedulerTest() {
diff --git a/services/surfaceflinger/tests/unittests/mock/MockDispSync.h b/services/surfaceflinger/tests/unittests/mock/MockDispSync.h
index 46d6558..495b3f2 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockDispSync.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockDispSync.h
@@ -43,6 +43,7 @@
     MOCK_METHOD2(changePhaseOffset, status_t(Callback*, nsecs_t));
     MOCK_CONST_METHOD1(computeNextRefresh, nsecs_t(int));
     MOCK_METHOD1(setIgnorePresentFences, void(bool));
+    MOCK_METHOD0(expectedPresentTime, nsecs_t());
 
     MOCK_CONST_METHOD1(dump, void(String8&));
 };
diff --git a/services/vr/bufferhubd/Android.bp b/services/vr/bufferhubd/Android.bp
index 04b9511..c35ddd4 100644
--- a/services/vr/bufferhubd/Android.bp
+++ b/services/vr/bufferhubd/Android.bp
@@ -16,6 +16,7 @@
     "libbase",
     "libbinder",
     "libcutils",
+    "libgtest_prod",
     "libgui",
     "liblog",
     "libpdx_default_transport",
@@ -27,13 +28,13 @@
 cc_library_static {
     name: "libbufferhubd",
     srcs: [
-        "binder/android/dvr/IBufferHub.aidl",
         "buffer_channel.cpp",
         "buffer_hub.cpp",
         "buffer_hub_binder.cpp",
         "buffer_node.cpp",
         "consumer_channel.cpp",
         "consumer_queue_channel.cpp",
+        "IBufferHub.cpp",
         "producer_channel.cpp",
         "producer_queue_channel.cpp",
     ],
@@ -48,11 +49,9 @@
     static_libs: [
         "libbufferhub",
     ],
-    aidl: {
-        local_include_dirs: ["binder"],
-        include_dirs: ["frameworks/native/aidl/binder"],
-        export_aidl_headers: true,
-    },
+
+    // TODO(b/117568153): Temporarily opt out using libcrt.
+    no_libcrt: true,
 }
 
 cc_binary {
diff --git a/services/vr/bufferhubd/IBufferHub.cpp b/services/vr/bufferhubd/IBufferHub.cpp
new file mode 100644
index 0000000..9d5b91a
--- /dev/null
+++ b/services/vr/bufferhubd/IBufferHub.cpp
@@ -0,0 +1,20 @@
+#include <log/log.h>
+#include <private/dvr/IBufferHub.h>
+
+namespace android {
+namespace dvr {
+
+IMPLEMENT_META_INTERFACE(BufferHub, "android.dvr.IBufferHub");
+
+status_t BnBufferHub::onTransact(uint32_t code, const Parcel& data,
+                                 Parcel* reply, uint32_t flags) {
+  switch (code) {
+    default:
+      // Should not reach
+      ALOGE("onTransact(): unknown code %u received!", code);
+      return BBinder::onTransact(code, data, reply, flags);
+  }
+}
+
+}  // namespace dvr
+}  // namespace android
\ No newline at end of file
diff --git a/services/vr/bufferhubd/binder/android/dvr/IBufferHub.aidl b/services/vr/bufferhubd/binder/android/dvr/IBufferHub.aidl
deleted file mode 100644
index 6a86adc..0000000
--- a/services/vr/bufferhubd/binder/android/dvr/IBufferHub.aidl
+++ /dev/null
@@ -1,5 +0,0 @@
-package android.dvr;
-
-/** {@hide} */
-interface IBufferHub {
-}
\ No newline at end of file
diff --git a/services/vr/bufferhubd/buffer_channel.cpp b/services/vr/bufferhubd/buffer_channel.cpp
index 6d22dee..dcc6ea4 100644
--- a/services/vr/bufferhubd/buffer_channel.cpp
+++ b/services/vr/bufferhubd/buffer_channel.cpp
@@ -13,11 +13,10 @@
 
 BufferChannel::BufferChannel(BufferHubService* service, int buffer_id,
                              int channel_id, IonBuffer buffer,
-                             IonBuffer metadata_buffer,
                              size_t user_metadata_size)
     : BufferHubChannel(service, buffer_id, channel_id, kDetachedBufferType),
-      buffer_node_(std::make_shared<BufferNode>(
-          std::move(buffer), std::move(metadata_buffer), user_metadata_size)),
+      buffer_node_(
+          std::make_shared<BufferNode>(std::move(buffer), user_metadata_size)),
       buffer_state_bit_(BufferHubDefs::FindFirstClearedBit()) {
   buffer_node_->set_buffer_state_bit(buffer_state_bit_);
 }
@@ -85,19 +84,26 @@
   }
 }
 
-Status<BufferDescription<BorrowedHandle>> BufferChannel::OnImport(
+Status<BufferTraits<BorrowedHandle>> BufferChannel::OnImport(
     Message& /*message*/) {
   ATRACE_NAME("BufferChannel::OnImport");
-  ALOGD_IF(TRACE, "BufferChannel::OnImport: buffer=%d.",
-           buffer_id());
+  ALOGD_IF(TRACE, "BufferChannel::OnImport: buffer=%d.", buffer_id());
 
-  return BufferDescription<BorrowedHandle>{buffer_node_->buffer(),
-                                           buffer_node_->metadata_buffer(),
-                                           buffer_id(),
-                                           channel_id(),
-                                           buffer_state_bit_,
-                                           BorrowedHandle{},
-                                           BorrowedHandle{}};
+  // TODO(b/112057680) Move away from the GraphicBuffer-based IonBuffer.
+  return BufferTraits<BorrowedHandle>{
+      /*buffer_handle=*/buffer_node_->buffer().handle(),
+      /*metadata_handle=*/buffer_node_->metadata().ashmem_handle().Borrow(),
+      /*id=*/buffer_id(),
+      /*buffer_state_bit=*/buffer_state_bit_,
+      /*metadata_size=*/buffer_node_->metadata().metadata_size(),
+      /*width=*/buffer_node_->buffer().width(),
+      /*height=*/buffer_node_->buffer().height(),
+      /*layer_count=*/buffer_node_->buffer().layer_count(),
+      /*format=*/buffer_node_->buffer().format(),
+      /*usage=*/buffer_node_->buffer().usage(),
+      /*stride=*/buffer_node_->buffer().stride(),
+      /*acquire_fence_fd=*/BorrowedHandle{},
+      /*released_fence_fd=*/BorrowedHandle{}};
 }
 
 Status<RemoteChannelHandle> BufferChannel::OnDuplicate(
@@ -175,7 +181,17 @@
   }
 
   IonBuffer buffer = std::move(buffer_node_->buffer());
-  IonBuffer metadata_buffer = std::move(buffer_node_->metadata_buffer());
+  IonBuffer metadata_buffer;
+  if (int ret = metadata_buffer.Alloc(buffer_node_->metadata().metadata_size(),
+                                      /*height=*/1,
+                                      /*layer_count=*/1,
+                                      BufferHubDefs::kMetadataFormat,
+                                      BufferHubDefs::kMetadataUsage)) {
+    ALOGE("BufferChannel::OnPromote: Failed to allocate metadata: %s",
+          strerror(-ret));
+    return ErrorStatus(EINVAL);
+  }
+
   size_t user_metadata_size = buffer_node_->user_metadata_size();
 
   std::unique_ptr<ProducerChannel> channel = ProducerChannel::Create(
diff --git a/services/vr/bufferhubd/buffer_hub_binder.cpp b/services/vr/bufferhubd/buffer_hub_binder.cpp
index def15f1..b507717 100644
--- a/services/vr/bufferhubd/buffer_hub_binder.cpp
+++ b/services/vr/bufferhubd/buffer_hub_binder.cpp
@@ -1,33 +1,81 @@
 #include <stdio.h>
 
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
 #include <log/log.h>
 #include <private/dvr/buffer_hub_binder.h>
 
 namespace android {
 namespace dvr {
 
-status_t BufferHubBinderService::start() {
-  ProcessState::self()->startThreadPool();
+status_t BufferHubBinderService::start(
+    const std::shared_ptr<BufferHubService>& pdx_service) {
   IPCThreadState::self()->disableBackgroundScheduling(true);
-  status_t result = BinderService<BufferHubBinderService>::publish();
-  if (result != OK) {
+
+  BufferHubBinderService* service = new BufferHubBinderService();
+  service->pdx_service_ = pdx_service;
+
+  // Not using BinderService::publish because need to get an instance of this
+  // class (above). Following code is the same as
+  // BinderService::publishAndJoinThreadPool
+  sp<IServiceManager> sm = defaultServiceManager();
+  status_t result = sm->addService(
+      String16(getServiceName()), service,
+      /*allowIsolated =*/false,
+      /*dump flags =*/IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT);
+  if (result != NO_ERROR) {
     ALOGE("Publishing bufferhubd failed with error %d", result);
     return result;
   }
 
+  sp<ProcessState> process_self(ProcessState::self());
+  process_self->startThreadPool();
+
   return result;
 }
 
-status_t BufferHubBinderService::dump(int fd, const Vector<String16> & /* args */) {
-  // TODO(b/115435506): not implemented yet
-  FILE *out = fdopen(dup(fd), "w");
+status_t BufferHubBinderService::dump(int fd, const Vector<String16>& args) {
+  FILE* out = fdopen(dup(fd), "w");
 
-  fprintf(out, "BufferHubBinderService::dump(): Not Implemented.\n");
+  // Currently not supporting args, so notify the user.
+  if (!args.isEmpty()) {
+    fprintf(out,
+            "Note: dumpsys bufferhubd currently does not support args."
+            "Input arguments are ignored.\n");
+  }
+
+  // TODO(b/116526156): output real data in this class once we have it
+  if (pdx_service_) {
+    // BufferHubService::Dumpstate(size_t) is not actually using the param
+    // So just using 0 as the length
+    fprintf(out, "%s", pdx_service_->DumpState(0).c_str());
+  } else {
+    fprintf(out, "PDX service not registered or died.\n");
+  }
 
   fclose(out);
   return NO_ERROR;
 }
 
+sp<IBufferHub> BufferHubBinderService::getServiceProxy() {
+  sp<IServiceManager> sm = defaultServiceManager();
+  sp<IBinder> service = sm->checkService(String16(getServiceName()));
+
+  if (service == nullptr) {
+    ALOGE("getServiceProxy(): %s binder service not found!", getServiceName());
+    return nullptr;
+  }
+
+  sp<IBufferHub> ret = interface_cast<IBufferHub>(service);
+  if (ret == nullptr) {
+    ALOGE("getServiceProxy(): %s binder service type casting error!",
+          getServiceName());
+    return nullptr;
+  }
+
+  return ret;
+}
 
 }  // namespace dvr
-}  // namespace android
\ No newline at end of file
+}  // namespace android
diff --git a/services/vr/bufferhubd/buffer_node.cpp b/services/vr/bufferhubd/buffer_node.cpp
index 5a04d0c..782b9c2 100644
--- a/services/vr/bufferhubd/buffer_node.cpp
+++ b/services/vr/bufferhubd/buffer_node.cpp
@@ -4,26 +4,15 @@
 namespace android {
 namespace dvr {
 
-BufferNode::BufferNode(IonBuffer buffer, IonBuffer metadata_buffer,
-                       size_t user_metadata_size)
-    : buffer_(std::move(buffer)),
-      metadata_buffer_(std::move(metadata_buffer)),
-      user_metadata_size_(user_metadata_size) {}
+BufferNode::BufferNode(IonBuffer buffer, size_t user_metadata_size)
+    : buffer_(std::move(buffer)) {
+  metadata_ = BufferHubMetadata::Create(user_metadata_size);
+}
 
 // Allocates a new BufferNode.
 BufferNode::BufferNode(uint32_t width, uint32_t height, uint32_t layer_count,
                        uint32_t format, uint64_t usage,
-                       size_t user_metadata_size)
-    : user_metadata_size_(user_metadata_size) {
-  // The size the of metadata buffer is used as the "width" parameter during
-  // allocation. Thus it cannot overflow uint32_t.
-  if (user_metadata_size_ >= (std::numeric_limits<uint32_t>::max() -
-                              BufferHubDefs::kMetadataHeaderSize)) {
-    ALOGE(
-        "DetachedBufferChannel::DetachedBufferChannel: metadata size too big.");
-    return;
-  }
-
+                       size_t user_metadata_size) {
   if (int ret = buffer_.Alloc(width, height, layer_count, format, usage)) {
     ALOGE(
         "DetachedBufferChannel::DetachedBufferChannel: Failed to allocate "
@@ -32,20 +21,7 @@
     return;
   }
 
-  // Buffer metadata has two parts: 1) a fixed sized metadata header; and 2)
-  // user requested metadata.
-  const size_t size = BufferHubDefs::kMetadataHeaderSize + user_metadata_size_;
-  if (int ret = metadata_buffer_.Alloc(size,
-                                       /*height=*/1,
-                                       /*layer_count=*/1,
-                                       BufferHubDefs::kMetadataFormat,
-                                       BufferHubDefs::kMetadataUsage)) {
-    ALOGE(
-        "DetachedBufferChannel::DetachedBufferChannel: Failed to allocate "
-        "metadata: %s",
-        strerror(-ret));
-    return;
-  }
+  metadata_ = BufferHubMetadata::Create(user_metadata_size);
 }
 
 }  // namespace dvr
diff --git a/services/vr/bufferhubd/bufferhubd.cpp b/services/vr/bufferhubd/bufferhubd.cpp
index 0ca7edc..3e10b26 100644
--- a/services/vr/bufferhubd/bufferhubd.cpp
+++ b/services/vr/bufferhubd/bufferhubd.cpp
@@ -10,7 +10,7 @@
 
 int main(int, char**) {
   int ret = -1;
-  std::shared_ptr<android::pdx::Service> service;
+  std::shared_ptr<android::dvr::BufferHubService> pdx_service;
   std::unique_ptr<android::pdx::ServiceDispatcher> dispatcher;
 
   // We need to be able to create endpoints with full perms.
@@ -33,15 +33,16 @@
   else
     ALOGI("New nofile limit is %llu/%llu.", rlim.rlim_cur, rlim.rlim_max);
 
-  CHECK_ERROR(android::dvr::BufferHubBinderService::start() != android::OK,
-              error, "Failed to create bufferhub binder service\n");
-
   dispatcher = android::pdx::ServiceDispatcher::Create();
   CHECK_ERROR(!dispatcher, error, "Failed to create service dispatcher\n");
 
-  service = android::dvr::BufferHubService::Create();
-  CHECK_ERROR(!service, error, "Failed to create bufferhubd service\n");
-  dispatcher->AddService(service);
+  pdx_service = android::dvr::BufferHubService::Create();
+  CHECK_ERROR(!pdx_service, error, "Failed to create bufferhub pdx service\n");
+  dispatcher->AddService(pdx_service);
+
+  ret = android::dvr::BufferHubBinderService::start(pdx_service);
+  CHECK_ERROR(ret != android::NO_ERROR, error,
+              "Failed to create bufferhub binder service\n");
 
   ret = dvrSetSchedulerClass(0, "graphics");
   CHECK_ERROR(ret < 0, error, "Failed to set thread priority");
diff --git a/services/vr/bufferhubd/consumer_channel.cpp b/services/vr/bufferhubd/consumer_channel.cpp
index 623c9d6..4ff7adf 100644
--- a/services/vr/bufferhubd/consumer_channel.cpp
+++ b/services/vr/bufferhubd/consumer_channel.cpp
@@ -90,11 +90,6 @@
           *this, &ConsumerChannel::OnConsumerRelease, message);
       return true;
 
-    case BufferHubRPC::ConsumerSetIgnore::Opcode:
-      DispatchRemoteMethod<BufferHubRPC::ConsumerSetIgnore>(
-          *this, &ConsumerChannel::OnConsumerSetIgnore, message);
-      return true;
-
     default:
       return false;
   }
@@ -120,9 +115,8 @@
   if (acquired_ || released_) {
     ALOGE(
         "ConsumerChannel::OnConsumerAcquire: Acquire when not posted: "
-        "ignored=%d acquired=%d released=%d channel_id=%d buffer_id=%d",
-        ignored_, acquired_, released_, message.GetChannelId(),
-        producer->buffer_id());
+        "acquired=%d released=%d channel_id=%d buffer_id=%d",
+        acquired_, released_, message.GetChannelId(), producer->buffer_id());
     return ErrorStatus(EBUSY);
   } else {
     auto status = producer->OnConsumerAcquire(message);
@@ -144,9 +138,8 @@
   if (!acquired_ || released_) {
     ALOGE(
         "ConsumerChannel::OnConsumerRelease: Release when not acquired: "
-        "ignored=%d acquired=%d released=%d channel_id=%d buffer_id=%d",
-        ignored_, acquired_, released_, message.GetChannelId(),
-        producer->buffer_id());
+        "acquired=%d released=%d channel_id=%d buffer_id=%d",
+        acquired_, released_, message.GetChannelId(), producer->buffer_id());
     return ErrorStatus(EBUSY);
   } else {
     auto status =
@@ -160,36 +153,11 @@
   }
 }
 
-Status<void> ConsumerChannel::OnConsumerSetIgnore(Message&, bool ignored) {
-  ATRACE_NAME("ConsumerChannel::OnConsumerSetIgnore");
-  auto producer = GetProducer();
-  if (!producer)
-    return ErrorStatus(EPIPE);
-
-  ignored_ = ignored;
-  if (ignored_ && acquired_) {
-    // Update the producer if ignore is set after the consumer acquires the
-    // buffer.
-    ClearAvailable();
-    producer->OnConsumerIgnored();
-    acquired_ = false;
-    released_ = true;
-  }
-
-  return {};
-}
-
 bool ConsumerChannel::OnProducerPosted() {
-  if (ignored_) {
-    acquired_ = false;
-    released_ = true;
-    return false;
-  } else {
-    acquired_ = false;
-    released_ = false;
-    SignalAvailable();
-    return true;
-  }
+  acquired_ = false;
+  released_ = false;
+  SignalAvailable();
+  return true;
 }
 
 void ConsumerChannel::OnProducerClosed() {
diff --git a/services/vr/bufferhubd/include/private/dvr/IBufferHub.h b/services/vr/bufferhubd/include/private/dvr/IBufferHub.h
new file mode 100644
index 0000000..266ae88
--- /dev/null
+++ b/services/vr/bufferhubd/include/private/dvr/IBufferHub.h
@@ -0,0 +1,30 @@
+#ifndef ANDROID_DVR_IBUFFERHUB_H
+#define ANDROID_DVR_IBUFFERHUB_H
+
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+
+namespace android {
+namespace dvr {
+
+class IBufferHub : public IInterface {
+ public:
+  DECLARE_META_INTERFACE(BufferHub);
+};
+
+class BnBufferHub : public BnInterface<IBufferHub> {
+ public:
+  virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+                              uint32_t flags = 0);
+};
+
+class BpBufferHub : public BpInterface<IBufferHub> {
+ public:
+  explicit BpBufferHub(const sp<IBinder>& impl)
+      : BpInterface<IBufferHub>(impl) {}
+};
+
+}  // namespace dvr
+}  // namespace android
+
+#endif
\ No newline at end of file
diff --git a/services/vr/bufferhubd/include/private/dvr/buffer_channel.h b/services/vr/bufferhubd/include/private/dvr/buffer_channel.h
index bcc93a1..1697251 100644
--- a/services/vr/bufferhubd/include/private/dvr/buffer_channel.h
+++ b/services/vr/bufferhubd/include/private/dvr/buffer_channel.h
@@ -4,6 +4,7 @@
 #include <pdx/channel_handle.h>
 #include <pdx/file_handle.h>
 #include <private/dvr/buffer_hub.h>
+#include <private/dvr/buffer_hub_defs.h>
 #include <private/dvr/buffer_node.h>
 
 namespace android {
@@ -34,8 +35,7 @@
  private:
   // Creates a detached buffer from existing IonBuffers.
   BufferChannel(BufferHubService* service, int buffer_id, int channel_id,
-                IonBuffer buffer, IonBuffer metadata_buffer,
-                size_t user_metadata_size);
+                IonBuffer buffer, size_t user_metadata_size);
 
   // Allocates a new detached buffer.
   BufferChannel(BufferHubService* service, int buffer_id, uint32_t width,
@@ -47,7 +47,7 @@
                 std::shared_ptr<BufferNode> buffer_node,
                 uint64_t buffer_state_bit);
 
-  pdx::Status<BufferDescription<pdx::BorrowedHandle>> OnImport(
+  pdx::Status<BufferTraits<pdx::BorrowedHandle>> OnImport(
       pdx::Message& message);
   pdx::Status<pdx::RemoteChannelHandle> OnDuplicate(pdx::Message& message);
   pdx::Status<pdx::RemoteChannelHandle> OnPromote(pdx::Message& message);
diff --git a/services/vr/bufferhubd/include/private/dvr/buffer_hub_binder.h b/services/vr/bufferhubd/include/private/dvr/buffer_hub_binder.h
index c0281fd..e266ff8 100644
--- a/services/vr/bufferhubd/include/private/dvr/buffer_hub_binder.h
+++ b/services/vr/bufferhubd/include/private/dvr/buffer_hub_binder.h
@@ -2,22 +2,29 @@
 #define ANDROID_DVR_BUFFER_HUB_BINDER_H
 
 #include <binder/BinderService.h>
-
-#include "android/dvr/BnBufferHub.h"
+#include <private/dvr/IBufferHub.h>
+#include <private/dvr/buffer_hub.h>
 
 namespace android {
 namespace dvr {
 
-class BufferHubBinderService : public BinderService<BufferHubBinderService>, public BnBufferHub {
+class BufferHubBinderService : public BinderService<BufferHubBinderService>,
+                               public BnBufferHub {
  public:
-  static status_t start();
+  static status_t start(const std::shared_ptr<BufferHubService>& pdx_service);
   static const char* getServiceName() { return "bufferhubd"; }
   // Dump bufferhub related information to given fd (usually stdout)
   // usage: adb shell dumpsys bufferhubd
-  virtual status_t dump(int fd, const Vector<String16> &args) override;
+  virtual status_t dump(int fd, const Vector<String16>& args) override;
+
+  // Helper function to get the BpReference to this service
+  static sp<IBufferHub> getServiceProxy();
+
+ private:
+  std::shared_ptr<BufferHubService> pdx_service_;
 };
 
 }  // namespace dvr
 }  // namespace android
 
-#endif // ANDROID_DVR_BUFFER_HUB_BINDER_H
\ No newline at end of file
+#endif  // ANDROID_DVR_BUFFER_HUB_BINDER_H
diff --git a/services/vr/bufferhubd/include/private/dvr/buffer_node.h b/services/vr/bufferhubd/include/private/dvr/buffer_node.h
index 4bcf4e3..d6c6105 100644
--- a/services/vr/bufferhubd/include/private/dvr/buffer_node.h
+++ b/services/vr/bufferhubd/include/private/dvr/buffer_node.h
@@ -2,6 +2,7 @@
 #define ANDROID_DVR_BUFFERHUBD_BUFFER_NODE_H_
 
 #include <private/dvr/ion_buffer.h>
+#include <ui/BufferHubMetadata.h>
 
 namespace android {
 namespace dvr {
@@ -10,39 +11,32 @@
  public:
   // Creates a BufferNode from existing IonBuffers, i.e. creating from an
   // existing ProducerChannel.
-  BufferNode(IonBuffer buffer, IonBuffer metadata_buffer,
-             size_t user_metadata_size);
+  BufferNode(IonBuffer buffer, size_t user_metadata_size);
 
   // Allocates a new BufferNode.
   BufferNode(uint32_t width, uint32_t height, uint32_t layer_count,
              uint32_t format, uint64_t usage, size_t user_metadata_size);
 
   // Returns whether the object holds a valid graphic buffer.
-  bool IsValid() const {
-    return buffer_.IsValid() && metadata_buffer_.IsValid();
-  }
+  bool IsValid() const { return buffer_.IsValid() && metadata_.IsValid(); }
 
-  size_t user_metadata_size() const { return user_metadata_size_; }
+  size_t user_metadata_size() const { return metadata_.user_metadata_size(); }
   uint64_t active_buffer_bit_mask() const { return active_buffer_bit_mask_; }
   void set_buffer_state_bit(uint64_t buffer_state_bit) {
     active_buffer_bit_mask_ |= buffer_state_bit;
   }
 
-  // Used to take out IonBuffers.
+  // Accessor of the IonBuffer.
   IonBuffer& buffer() { return buffer_; }
-  IonBuffer& metadata_buffer() { return metadata_buffer_; }
-
-  // Used to access IonBuffers.
   const IonBuffer& buffer() const { return buffer_; }
-  const IonBuffer& metadata_buffer() const { return metadata_buffer_; }
+
+  // Accessor of the metadata.
+  const BufferHubMetadata& metadata() const { return metadata_; }
 
  private:
   // Gralloc buffer handles.
   IonBuffer buffer_;
-  IonBuffer metadata_buffer_;
-
-  // Size of user requested metadata.
-  const size_t user_metadata_size_;
+  BufferHubMetadata metadata_;
 
   // All active buffer bits. Valid bits are the lower 63 bits, while the
   // highest bit is reserved for the exclusive writing and should not be set.
diff --git a/services/vr/bufferhubd/include/private/dvr/consumer_channel.h b/services/vr/bufferhubd/include/private/dvr/consumer_channel.h
index 0d70409..84f664d 100644
--- a/services/vr/bufferhubd/include/private/dvr/consumer_channel.h
+++ b/services/vr/bufferhubd/include/private/dvr/consumer_channel.h
@@ -37,12 +37,10 @@
   pdx::Status<LocalFence> OnConsumerAcquire(Message& message);
   pdx::Status<void> OnConsumerRelease(Message& message,
                                       LocalFence release_fence);
-  pdx::Status<void> OnConsumerSetIgnore(Message& message, bool ignore);
 
   uint64_t consumer_state_bit_{0};
   bool acquired_{false};
   bool released_{true};
-  bool ignored_{false};  // True if we are ignoring events.
   std::weak_ptr<Channel> producer_;
 
   ConsumerChannel(const ConsumerChannel&) = delete;
diff --git a/services/vr/bufferhubd/include/private/dvr/producer_channel.h b/services/vr/bufferhubd/include/private/dvr/producer_channel.h
index 242198f..18bb7bf 100644
--- a/services/vr/bufferhubd/include/private/dvr/producer_channel.h
+++ b/services/vr/bufferhubd/include/private/dvr/producer_channel.h
@@ -8,8 +8,8 @@
 #include <pdx/channel_handle.h>
 #include <pdx/file_handle.h>
 #include <pdx/rpc/buffer_wrapper.h>
-#include <private/dvr/bufferhub_rpc.h>
 #include <private/dvr/buffer_hub.h>
+#include <private/dvr/bufferhub_rpc.h>
 #include <private/dvr/ion_buffer.h>
 
 namespace android {
@@ -58,7 +58,7 @@
   pdx::Status<void> OnConsumerRelease(Message& message,
                                       LocalFence release_fence);
 
-  void OnConsumerIgnored();
+  void DecrementPendingConsumers();
   void OnConsumerOrphaned(ConsumerChannel* channel);
 
   void AddConsumer(ConsumerChannel* channel);
@@ -81,10 +81,8 @@
   BufferHubDefs::MetadataHeader* metadata_header_ = nullptr;
   std::atomic<uint64_t>* buffer_state_ = nullptr;
   std::atomic<uint64_t>* fence_state_ = nullptr;
+  std::atomic<uint64_t>* active_clients_bit_mask_ = nullptr;
 
-  // All active consumer bits. Valid bits are the lower 63 bits, while the
-  // highest bit is reserved for the producer and should not be set.
-  uint64_t active_consumer_bit_mask_{0ULL};
   // All orphaned consumer bits. Valid bits are the lower 63 bits, while the
   // highest bit is reserved for the producer and should not be set.
   uint64_t orphaned_consumer_bit_mask_{0ULL};
diff --git a/services/vr/bufferhubd/producer_channel.cpp b/services/vr/bufferhubd/producer_channel.cpp
index 057d4f4..581390f 100644
--- a/services/vr/bufferhubd/producer_channel.cpp
+++ b/services/vr/bufferhubd/producer_channel.cpp
@@ -7,8 +7,8 @@
 #include <thread>
 
 #include <log/log.h>
-#include <private/dvr/bufferhub_rpc.h>
 #include <private/dvr/buffer_channel.h>
+#include <private/dvr/bufferhub_rpc.h>
 #include <private/dvr/consumer_channel.h>
 #include <private/dvr/producer_channel.h>
 #include <sync/sync.h>
@@ -96,8 +96,9 @@
   // and also initialize the value to zero.
   buffer_state_ =
       new (&metadata_header_->buffer_state) std::atomic<uint64_t>(0);
-  fence_state_ =
-      new (&metadata_header_->fence_state) std::atomic<uint64_t>(0);
+  fence_state_ = new (&metadata_header_->fence_state) std::atomic<uint64_t>(0);
+  active_clients_bit_mask_ =
+      new (&metadata_header_->active_clients_bit_mask) std::atomic<uint64_t>(0);
 
   acquire_fence_fd_.Reset(epoll_create1(EPOLL_CLOEXEC));
   release_fence_fd_.Reset(epoll_create1(EPOLL_CLOEXEC));
@@ -261,8 +262,12 @@
 
   // Try find the next consumer state bit which has not been claimed by any
   // consumer yet.
+  // memory_order_acquire is chosen here because all writes in other threads
+  // that release active_clients_bit_mask_ need to be visible here.
+  uint64_t current_active_clients_bit_mask =
+      active_clients_bit_mask_->load(std::memory_order_acquire);
   uint64_t consumer_state_bit = BufferHubDefs::FindNextClearedBit(
-      active_consumer_bit_mask_ | orphaned_consumer_bit_mask_ |
+      current_active_clients_bit_mask | orphaned_consumer_bit_mask_ |
       BufferHubDefs::kProducerStateBit);
   if (consumer_state_bit == 0ULL) {
     ALOGE(
@@ -271,6 +276,23 @@
     return ErrorStatus(E2BIG);
   }
 
+  uint64_t updated_active_clients_bit_mask =
+      current_active_clients_bit_mask | consumer_state_bit;
+  // Set the updated value only if the current value stays the same as what was
+  // read before. If the comparison succeeds, update the value without
+  // reordering anything before or after this read-modify-write in the current
+  // thread, and the modification will be visible in other threads that acquire
+  // active_clients_bit_mask_. If the comparison fails, load the result of
+  // all writes from all threads to updated_active_clients_bit_mask.
+  if (!active_clients_bit_mask_->compare_exchange_weak(
+          current_active_clients_bit_mask, updated_active_clients_bit_mask,
+          std::memory_order_acq_rel, std::memory_order_acquire)) {
+    ALOGE("Current active clients bit mask is changed to %" PRIu64
+          ", which was expected to be %" PRIu64 ".",
+          updated_active_clients_bit_mask, current_active_clients_bit_mask);
+    return ErrorStatus(EBUSY);
+  }
+
   auto consumer =
       std::make_shared<ConsumerChannel>(service(), buffer_id(), channel_id,
                                         consumer_state_bit, shared_from_this());
@@ -280,6 +302,10 @@
         "ProducerChannel::CreateConsumer: failed to set new consumer channel: "
         "%s",
         channel_status.GetErrorMessage().c_str());
+    // Restore the consumer state bit and make it visible in other threads that
+    // acquire the active_clients_bit_mask_.
+    active_clients_bit_mask_->fetch_and(~consumer_state_bit,
+                                        std::memory_order_release);
     return ErrorStatus(ENOMEM);
   }
 
@@ -290,7 +316,6 @@
       pending_consumers_++;
   }
 
-  active_consumer_bit_mask_ |= consumer_state_bit;
   return {status.take()};
 }
 
@@ -300,8 +325,8 @@
   return CreateConsumer(message);
 }
 
-Status<void> ProducerChannel::OnProducerPost(
-    Message&, LocalFence acquire_fence) {
+Status<void> ProducerChannel::OnProducerPost(Message&,
+                                             LocalFence acquire_fence) {
   ATRACE_NAME("ProducerChannel::OnProducerPost");
   ALOGD_IF(TRACE, "ProducerChannel::OnProducerPost: buffer_id=%d", buffer_id());
   if (!producer_owns_) {
@@ -315,9 +340,9 @@
   int ret = epoll_ctl(release_fence_fd_.Get(), EPOLL_CTL_MOD,
                       dummy_fence_fd_.Get(), &event);
   ALOGE_IF(ret < 0,
-      "ProducerChannel::OnProducerPost: Failed to modify the shared "
-      "release fence to include the dummy fence: %s",
-      strerror(errno));
+           "ProducerChannel::OnProducerPost: Failed to modify the shared "
+           "release fence to include the dummy fence: %s",
+           strerror(errno));
 
   eventfd_t dummy_fence_count = 0ULL;
   if (eventfd_read(dummy_fence_fd_.Get(), &dummy_fence_count) < 0) {
@@ -410,9 +435,9 @@
     return ErrorStatus(-ret);
   };
 
-  std::unique_ptr<BufferChannel> channel = BufferChannel::Create(
-      service(), buffer_id(), channel_id, std::move(buffer_),
-      std::move(metadata_buffer_), user_metadata_size_);
+  std::unique_ptr<BufferChannel> channel =
+      BufferChannel::Create(service(), buffer_id(), channel_id,
+                            std::move(buffer_), user_metadata_size_);
   if (!channel) {
     ALOGE("ProducerChannel::OnProducerDetach: Invalid buffer.");
     return ErrorStatus(EINVAL);
@@ -474,7 +499,7 @@
     }
   }
 
-  OnConsumerIgnored();
+  DecrementPendingConsumers();
   if (pending_consumers_ == 0) {
     // Clear the producer bit atomically to transit into released state. This
     // has to done by BufferHub as it requries synchronization among all
@@ -507,21 +532,22 @@
   return {};
 }
 
-void ProducerChannel::OnConsumerIgnored() {
+void ProducerChannel::DecrementPendingConsumers() {
   if (pending_consumers_ == 0) {
-    ALOGE("ProducerChannel::OnConsumerIgnored: no pending consumer.");
+    ALOGE("ProducerChannel::DecrementPendingConsumers: no pending consumer.");
     return;
   }
 
   --pending_consumers_;
   ALOGD_IF(TRACE,
-           "ProducerChannel::OnConsumerIgnored: buffer_id=%d %d consumers left",
+           "ProducerChannel::DecrementPendingConsumers: buffer_id=%d %d "
+           "consumers left",
            buffer_id(), pending_consumers_);
 }
 
 void ProducerChannel::OnConsumerOrphaned(ConsumerChannel* channel) {
   // Ignore the orphaned consumer.
-  OnConsumerIgnored();
+  DecrementPendingConsumers();
 
   const uint64_t consumer_state_bit = channel->consumer_state_bit();
   ALOGE_IF(orphaned_consumer_bit_mask_ & consumer_state_bit,
@@ -551,7 +577,10 @@
 void ProducerChannel::RemoveConsumer(ConsumerChannel* channel) {
   consumer_channels_.erase(
       std::find(consumer_channels_.begin(), consumer_channels_.end(), channel));
-  active_consumer_bit_mask_ &= ~channel->consumer_state_bit();
+  // Restore the consumer state bit and make it visible in other threads that
+  // acquire the active_clients_bit_mask_.
+  active_clients_bit_mask_->fetch_and(~channel->consumer_state_bit(),
+                                      std::memory_order_release);
 
   const uint64_t buffer_state = buffer_state_->load();
   if (BufferHubDefs::IsBufferPosted(buffer_state) ||
diff --git a/services/vr/bufferhubd/tests/Android.bp b/services/vr/bufferhubd/tests/Android.bp
index 4d1d43f..bf8ea5b 100644
--- a/services/vr/bufferhubd/tests/Android.bp
+++ b/services/vr/bufferhubd/tests/Android.bp
@@ -6,11 +6,21 @@
         "-DTRACE=0",
         "-DATRACE_TAG=ATRACE_TAG_GRAPHICS",
     ],
-    static_libs: ["libbufferhubd"],
+    header_libs: ["libdvr_headers"],
+    static_libs: [
+        "libbufferhub",
+        "libbufferhubd",
+        "libgmock",
+    ],
     shared_libs: [
         "libbase",
         "libbinder",
         "liblog",
+        "libpdx_default_transport",
+        "libui",
         "libutils",
     ],
+
+    // TODO(b/117568153): Temporarily opt out using libcrt.
+    no_libcrt: true,
 }
\ No newline at end of file
diff --git a/services/vr/bufferhubd/tests/buffer_hub_binder_service-test.cpp b/services/vr/bufferhubd/tests/buffer_hub_binder_service-test.cpp
index e3f2825..587e6db 100644
--- a/services/vr/bufferhubd/tests/buffer_hub_binder_service-test.cpp
+++ b/services/vr/bufferhubd/tests/buffer_hub_binder_service-test.cpp
@@ -1,19 +1,23 @@
-#include <private/dvr/buffer_hub_binder.h>
-
+#include <gmock/gmock.h>
 #include <gtest/gtest.h>
+#include <private/dvr/buffer_hub_binder.h>
 
 namespace android {
 namespace dvr {
 
 namespace {
 
+using testing::Ne;
+
 class BufferHubBinderServiceTest : public ::testing::Test {
   // Add setup and teardown if necessary
 };
 
 TEST_F(BufferHubBinderServiceTest, TestInitialize) {
-  // Test if start binder server returns OK
-  EXPECT_EQ(BufferHubBinderService::start(), OK);
+  // Create a new service will kill the current one.
+  // So just check if Binder service is running
+  sp<IBufferHub> service = BufferHubBinderService::getServiceProxy();
+  EXPECT_THAT(service, Ne(nullptr));
 }
 
 }  // namespace
diff --git a/vulkan/api/vulkan.api b/vulkan/api/vulkan.api
index fa63fbd..5722810 100644
--- a/vulkan/api/vulkan.api
+++ b/vulkan/api/vulkan.api
@@ -28,7 +28,7 @@
 // API version (major.minor.patch)
 define VERSION_MAJOR 1
 define VERSION_MINOR 1
-define VERSION_PATCH 85
+define VERSION_PATCH 86
 
 // API limits
 define VK_MAX_PHYSICAL_DEVICE_NAME_SIZE 256
@@ -45,6 +45,10 @@
 define VK_QUEUE_FAMILY_EXTERNAL         -2
 @extension("VK_EXT_queue_family_foreign")
 define VK_QUEUE_FAMILY_FOREIGN_EXT      -3
+@extension("VK_MAX_DRIVER_NAME_SIZE_KHR") // 197
+define VK_MAX_DRIVER_NAME_SIZE_KHR      256
+@extension("VK_MAX_DRIVER_NAME_SIZE_KHR") // 197
+define VK_MAX_DRIVER_INFO_SIZE_KHR      256
 
 // API keywords
 define VK_TRUE        1
@@ -545,6 +549,10 @@
 @extension("VK_AMD_buffer_marker") define VK_AMD_BUFFER_MARKER_SPEC_VERSION 1
 @extension("VK_AMD_buffer_marker") define VK_AMD_BUFFER_MARKER_EXTENSION_NAME "VK_AMD_buffer_marker"
 
+// 181
+@extension("VK_KHR_shader_atomic_int64") define VK_KHR_SHADER_ATOMIC_INT64_SPEC_VERSION 1
+@extension("VK_KHR_shader_atomic_int64") define VK_KHR_SHADER_ATOMIC_INT64_EXTENSION_NAME "VK_KHR_shader_atomic_int64"
+
 // 186
 @extension("VK_AMD_shader_core_properties") define VK_AMD_SHADER_CORE_PROPERTIES_SPEC_VERSION 1
 @extension("VK_AMD_shader_core_properties") define VK_AMD_SHADER_CORE_PROPERTIES_EXTENSION_NAME "VK_AMD_shader_core_properties"
@@ -553,6 +561,10 @@
 @extension("VK_EXT_vertex_attribute_divisor") define VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_SPEC_VERSION 2
 @extension("VK_EXT_vertex_attribute_divisor") define VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME "VK_EXT_vertex_attribute_divisor"
 
+// 197
+@extension("VK_KHR_driver_properties") define VK_KHR_DRIVER_PROPERTIES_SPEC_VERSION 1
+@extension("VK_KHR_driver_properties") define VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME "VK_KHR_driver_properties"
+
 // 199
 @extension("VK_NV_shader_subgroup_partitioned") define VK_NV_SHADER_SUBGROUP_PARTITIONED_SPEC_VERSION 1
 @extension("VK_NV_shader_subgroup_partitioned") define VK_NV_SHADER_SUBGROUP_PARTITIONED_EXTENSION_NAME "VK_NV_shader_subgroup_partitioned"
@@ -1763,6 +1775,12 @@
     VK_STRUCTURE_TYPE_MEMORY_HOST_POINTER_PROPERTIES_EXT                    = 1000178001,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT   = 1000178002,
 
+    //@extension("VK_KHR_shader_atomic_int64") // 181
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES_KHR  = 1000180000,
+
+    //@extension("VK_KHR_driver_properties") // 197
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR             = 1000196000,
+
     //@extension("VK_AMD_shader_core_properties") // 186
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_AMD        = 1000185000,
 
@@ -2264,6 +2282,19 @@
     VK_QUEUE_GLOBAL_PRIORITY_REALTIME_EXT                   = 1024,
 }
 
+@extension("VK_KHR_driver_properties") // 197
+enum VkDriverIdKHR {
+    VK_DRIVER_ID_AMD_PROPRIETARY_KHR                        = 1,
+    VK_DRIVER_ID_AMD_OPEN_SOURCE_KHR                        = 2,
+    VK_DRIVER_ID_MESA_RADV_KHR                              = 3,
+    VK_DRIVER_ID_NVIDIA_PROPRIETARY_KHR                     = 4,
+    VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS_KHR              = 5,
+    VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA_KHR                 = 6,
+    VK_DRIVER_ID_IMAGINATION_PROPRIETARY_KHR                = 7,
+    VK_DRIVER_ID_QUALCOMM_PROPRIETARY_KHR                   = 8,
+    VK_DRIVER_ID_ARM_PROPRIETARY_KHR                        = 9,
+}
+
 /////////////////
 //  Bitfields  //
 /////////////////
@@ -7214,6 +7245,14 @@
     VkDeviceSize                                    minImportedHostPointerAlignment
 }
 
+@extension("VK_KHR_shader_atomic_int64") // 181
+class VkPhysicalDeviceShaderAtomicInt64FeaturesKHR {
+    VkStructureType                                 sType
+    void*                                           pNext
+    VkBool32                                        shaderBufferInt64Atomics
+    VkBool32                                        shaderSharedInt64Atomics
+}
+
 @extension("VK_AMD_shader_core_properties") // 186
 class VkPhysicalDeviceShaderCorePropertiesAMD {
     VkStructureType                                 sType
@@ -7263,6 +7302,24 @@
     VkBool32                                        vertexAttributeInstanceRateZeroDivisor
 }
 
+@extension("VK_KHR_driver_properties") // 197
+class VkConformanceVersionKHR {
+    u8                                              major
+    u8                                              minor
+    u8                                              subminor
+    u8                                              patch
+}
+
+@extension("VK_KHR_driver_properties") // 197
+class VkPhysicalDeviceDriverPropertiesKHR {
+    VkStructureType                                 sType
+    void*                                           pNext
+    u32                                             driverID
+    char[VK_MAX_DRIVER_NAME_SIZE_KHR]               driverName
+    char[VK_MAX_DRIVER_INFO_SIZE_KHR]               driverInfo
+    VkConformanceVersionKHR                         conformanceVersion
+}
+
 @extension("VK_NV_compute_shader_derivatives") // 202
 class VkPhysicalDeviceComputeShaderDerivativesFeaturesNV {
     VkStructureType                                 sType
@@ -11168,42 +11225,42 @@
 
 @extension("VK_NVX_raytracing") // 166
 cmd void vkCmdBuildAccelerationStructureNVX(
-        VkCommandBuffer                         cmdBuf,
-        VkAccelerationStructureTypeNVX          type,
-        u32                                     instanceCount,
-        VkBuffer                                instanceData,
-        VkDeviceSize                            instanceOffset,
-        u32                                     geometryCount,
-        const VkGeometryNVX*                    pGeometries,
-        VkBuildAccelerationStructureFlagsNVX    flags,
-        VkBool32                                update,
-        VkAccelerationStructureNVX              dst,
-        VkAccelerationStructureNVX              src,
-        VkBuffer                                scratch,
-        VkDeviceSize                            scratchOffset) {
+        VkCommandBuffer                             commandBuffer,
+        VkAccelerationStructureTypeNVX              type,
+        u32                                         instanceCount,
+        VkBuffer                                    instanceData,
+        VkDeviceSize                                instanceOffset,
+        u32                                         geometryCount,
+        const VkGeometryNVX*                        pGeometries,
+        VkBuildAccelerationStructureFlagsNVX        flags,
+        VkBool32                                    update,
+        VkAccelerationStructureNVX                  dst,
+        VkAccelerationStructureNVX                  src,
+        VkBuffer                                    scratch,
+        VkDeviceSize                                scratchOffset) {
 }
 
 @extension("VK_NVX_raytracing") // 166
 cmd void vkCmdCopyAccelerationStructureNVX(
-        VkCommandBuffer                         cmdBuf,
-        VkAccelerationStructureNVX              dst,
-        VkAccelerationStructureNVX              src,
-        VkCopyAccelerationStructureModeNVX      mode) {
+        VkCommandBuffer                             commandBuffer,
+        VkAccelerationStructureNVX                  dst,
+        VkAccelerationStructureNVX                  src,
+        VkCopyAccelerationStructureModeNVX          mode) {
 }
 
 @extension("VK_NVX_raytracing") // 166
 cmd void vkCmdTraceRaysNVX(
-        VkCommandBuffer                         cmdBuf,
-        VkBuffer                                raygenShaderBindingTableBuffer,
-        VkDeviceSize                            raygenShaderBindingOffset,
-        VkBuffer                                missShaderBindingTableBuffer,
-        VkDeviceSize                            missShaderBindingOffset,
-        VkDeviceSize                            missShaderBindingStride,
-        VkBuffer                                hitShaderBindingTableBuffer,
-        VkDeviceSize                            hitShaderBindingOffset,
-        VkDeviceSize                            hitShaderBindingStride,
-        u32                                     width,
-        u32                                     height) {
+        VkCommandBuffer                             commandBuffer,
+        VkBuffer                                    raygenShaderBindingTableBuffer,
+        VkDeviceSize                                raygenShaderBindingOffset,
+        VkBuffer                                    missShaderBindingTableBuffer,
+        VkDeviceSize                                missShaderBindingOffset,
+        VkDeviceSize                                missShaderBindingStride,
+        VkBuffer                                    hitShaderBindingTableBuffer,
+        VkDeviceSize                                hitShaderBindingOffset,
+        VkDeviceSize                                hitShaderBindingStride,
+        u32                                         width,
+        u32                                         height) {
 }
 
 @extension("VK_NVX_raytracing") // 166
@@ -11219,38 +11276,38 @@
 
 @extension("VK_NVX_raytracing") // 166
 cmd VkResult vkGetRaytracingShaderHandlesNVX(
-        VkDevice                                device,
-        VkPipeline                              pipeline,
-        u32                                     firstGroup,
-        u32                                     groupCount,
-        platform.size_t                         dataSize,
-        void*                                   pData) {
+        VkDevice                                    device,
+        VkPipeline                                  pipeline,
+        u32                                         firstGroup,
+        u32                                         groupCount,
+        platform.size_t                             dataSize,
+        void*                                       pData) {
     return ?
 }
 
 @extension("VK_NVX_raytracing") // 166
 cmd VkResult vkGetAccelerationStructureHandleNVX(
-        VkDevice                                device,
-        VkAccelerationStructureNVX              accelerationStructure,
-        platform.size_t                         dataSize,
-        void*                                   pData) {
+        VkDevice                                    device,
+        VkAccelerationStructureNVX                  accelerationStructure,
+        platform.size_t                             dataSize,
+        void*                                       pData) {
     return ?
 }
 
 @extension("VK_NVX_raytracing") // 166
 cmd void vkCmdWriteAccelerationStructurePropertiesNVX(
-        VkCommandBuffer                         cmdBuf,
-        VkAccelerationStructureNVX              accelerationStructure,
-        VkQueryType                             queryType,
-        VkQueryPool                             queryPool,
-        u32                                     query) {
+        VkCommandBuffer                             commandBuffer,
+        VkAccelerationStructureNVX                  accelerationStructure,
+        VkQueryType                                 queryType,
+        VkQueryPool                                 queryPool,
+        u32                                         query) {
 }
 
 @extension("VK_NVX_raytracing") // 166
 cmd VkResult vkCompileDeferredNVX(
-        VkDevice                                device,
-        VkPipeline                              pipeline,
-        u32                                     shader) {
+        VkDevice                                    device,
+        VkPipeline                                  pipeline,
+        u32                                         shader) {
     return ?
 }
 
diff --git a/vulkan/include/vulkan/vulkan_core.h b/vulkan/include/vulkan/vulkan_core.h
index 2d1b3f5..39f4dc6 100644
--- a/vulkan/include/vulkan/vulkan_core.h
+++ b/vulkan/include/vulkan/vulkan_core.h
@@ -43,7 +43,7 @@
 #define VK_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3ff)
 #define VK_VERSION_PATCH(version) ((uint32_t)(version) & 0xfff)
 // Version of this file
-#define VK_HEADER_VERSION 85
+#define VK_HEADER_VERSION 86
 
 
 #define VK_NULL_HANDLE 0
@@ -427,10 +427,12 @@
     VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT = 1000178000,
     VK_STRUCTURE_TYPE_MEMORY_HOST_POINTER_PROPERTIES_EXT = 1000178001,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT = 1000178002,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES_KHR = 1000180000,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_AMD = 1000185000,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT = 1000190000,
     VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT = 1000190001,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT = 1000190002,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR = 1000196000,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COMPUTE_SHADER_DERIVATIVES_FEATURES_NV = 1000201000,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_NV = 1000202000,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_PROPERTIES_NV = 1000202001,
@@ -6044,6 +6046,60 @@
 
 
 
+#define VK_KHR_shader_atomic_int64 1
+#define VK_KHR_SHADER_ATOMIC_INT64_SPEC_VERSION 1
+#define VK_KHR_SHADER_ATOMIC_INT64_EXTENSION_NAME "VK_KHR_shader_atomic_int64"
+
+typedef struct VkPhysicalDeviceShaderAtomicInt64FeaturesKHR {
+    VkStructureType    sType;
+    void*              pNext;
+    VkBool32           shaderBufferInt64Atomics;
+    VkBool32           shaderSharedInt64Atomics;
+} VkPhysicalDeviceShaderAtomicInt64FeaturesKHR;
+
+
+
+#define VK_KHR_driver_properties 1
+#define VK_MAX_DRIVER_NAME_SIZE_KHR       256
+#define VK_MAX_DRIVER_INFO_SIZE_KHR       256
+#define VK_KHR_DRIVER_PROPERTIES_SPEC_VERSION 1
+#define VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME "VK_KHR_driver_properties"
+
+
+typedef enum VkDriverIdKHR {
+    VK_DRIVER_ID_AMD_PROPRIETARY_KHR = 1,
+    VK_DRIVER_ID_AMD_OPEN_SOURCE_KHR = 2,
+    VK_DRIVER_ID_MESA_RADV_KHR = 3,
+    VK_DRIVER_ID_NVIDIA_PROPRIETARY_KHR = 4,
+    VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS_KHR = 5,
+    VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA_KHR = 6,
+    VK_DRIVER_ID_IMAGINATION_PROPRIETARY_KHR = 7,
+    VK_DRIVER_ID_QUALCOMM_PROPRIETARY_KHR = 8,
+    VK_DRIVER_ID_ARM_PROPRIETARY_KHR = 9,
+    VK_DRIVER_ID_BEGIN_RANGE_KHR = VK_DRIVER_ID_AMD_PROPRIETARY_KHR,
+    VK_DRIVER_ID_END_RANGE_KHR = VK_DRIVER_ID_ARM_PROPRIETARY_KHR,
+    VK_DRIVER_ID_RANGE_SIZE_KHR = (VK_DRIVER_ID_ARM_PROPRIETARY_KHR - VK_DRIVER_ID_AMD_PROPRIETARY_KHR + 1),
+    VK_DRIVER_ID_MAX_ENUM_KHR = 0x7FFFFFFF
+} VkDriverIdKHR;
+
+typedef struct VkConformanceVersionKHR {
+    uint8_t    major;
+    uint8_t    minor;
+    uint8_t    subminor;
+    uint8_t    patch;
+} VkConformanceVersionKHR;
+
+typedef struct VkPhysicalDeviceDriverPropertiesKHR {
+    VkStructureType            sType;
+    void*                      pNext;
+    uint32_t                   driverID;
+    char                       driverName[VK_MAX_DRIVER_NAME_SIZE_KHR];
+    char                       driverInfo[VK_MAX_DRIVER_INFO_SIZE_KHR];
+    VkConformanceVersionKHR    conformanceVersion;
+} VkPhysicalDeviceDriverPropertiesKHR;
+
+
+
 #define VK_KHR_vulkan_memory_model 1
 #define VK_KHR_VULKAN_MEMORY_MODEL_SPEC_VERSION 2
 #define VK_KHR_VULKAN_MEMORY_MODEL_EXTENSION_NAME "VK_KHR_vulkan_memory_model"
@@ -8044,13 +8100,13 @@
 typedef void (VKAPI_PTR *PFN_vkGetAccelerationStructureMemoryRequirementsNVX)(VkDevice device, const VkAccelerationStructureMemoryRequirementsInfoNVX* pInfo, VkMemoryRequirements2KHR* pMemoryRequirements);
 typedef void (VKAPI_PTR *PFN_vkGetAccelerationStructureScratchMemoryRequirementsNVX)(VkDevice device, const VkAccelerationStructureMemoryRequirementsInfoNVX* pInfo, VkMemoryRequirements2KHR* pMemoryRequirements);
 typedef VkResult (VKAPI_PTR *PFN_vkBindAccelerationStructureMemoryNVX)(VkDevice device, uint32_t bindInfoCount, const VkBindAccelerationStructureMemoryInfoNVX* pBindInfos);
-typedef void (VKAPI_PTR *PFN_vkCmdBuildAccelerationStructureNVX)(VkCommandBuffer cmdBuf, VkAccelerationStructureTypeNVX type, uint32_t instanceCount, VkBuffer instanceData, VkDeviceSize instanceOffset, uint32_t geometryCount, const VkGeometryNVX* pGeometries, VkBuildAccelerationStructureFlagsNVX flags, VkBool32 update, VkAccelerationStructureNVX dst, VkAccelerationStructureNVX src, VkBuffer scratch, VkDeviceSize scratchOffset);
-typedef void (VKAPI_PTR *PFN_vkCmdCopyAccelerationStructureNVX)(VkCommandBuffer cmdBuf, VkAccelerationStructureNVX dst, VkAccelerationStructureNVX src, VkCopyAccelerationStructureModeNVX mode);
-typedef void (VKAPI_PTR *PFN_vkCmdTraceRaysNVX)(VkCommandBuffer cmdBuf, VkBuffer raygenShaderBindingTableBuffer, VkDeviceSize raygenShaderBindingOffset, VkBuffer missShaderBindingTableBuffer, VkDeviceSize missShaderBindingOffset, VkDeviceSize missShaderBindingStride, VkBuffer hitShaderBindingTableBuffer, VkDeviceSize hitShaderBindingOffset, VkDeviceSize hitShaderBindingStride, uint32_t width, uint32_t height);
+typedef void (VKAPI_PTR *PFN_vkCmdBuildAccelerationStructureNVX)(VkCommandBuffer commandBuffer, VkAccelerationStructureTypeNVX type, uint32_t instanceCount, VkBuffer instanceData, VkDeviceSize instanceOffset, uint32_t geometryCount, const VkGeometryNVX* pGeometries, VkBuildAccelerationStructureFlagsNVX flags, VkBool32 update, VkAccelerationStructureNVX dst, VkAccelerationStructureNVX src, VkBuffer scratch, VkDeviceSize scratchOffset);
+typedef void (VKAPI_PTR *PFN_vkCmdCopyAccelerationStructureNVX)(VkCommandBuffer commandBuffer, VkAccelerationStructureNVX dst, VkAccelerationStructureNVX src, VkCopyAccelerationStructureModeNVX mode);
+typedef void (VKAPI_PTR *PFN_vkCmdTraceRaysNVX)(VkCommandBuffer commandBuffer, VkBuffer raygenShaderBindingTableBuffer, VkDeviceSize raygenShaderBindingOffset, VkBuffer missShaderBindingTableBuffer, VkDeviceSize missShaderBindingOffset, VkDeviceSize missShaderBindingStride, VkBuffer hitShaderBindingTableBuffer, VkDeviceSize hitShaderBindingOffset, VkDeviceSize hitShaderBindingStride, uint32_t width, uint32_t height);
 typedef VkResult (VKAPI_PTR *PFN_vkCreateRaytracingPipelinesNVX)(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkRaytracingPipelineCreateInfoNVX* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines);
 typedef VkResult (VKAPI_PTR *PFN_vkGetRaytracingShaderHandlesNVX)(VkDevice device, VkPipeline pipeline, uint32_t firstGroup, uint32_t groupCount, size_t dataSize, void* pData);
 typedef VkResult (VKAPI_PTR *PFN_vkGetAccelerationStructureHandleNVX)(VkDevice device, VkAccelerationStructureNVX accelerationStructure, size_t dataSize, void* pData);
-typedef void (VKAPI_PTR *PFN_vkCmdWriteAccelerationStructurePropertiesNVX)(VkCommandBuffer cmdBuf, VkAccelerationStructureNVX accelerationStructure, VkQueryType queryType, VkQueryPool queryPool, uint32_t query);
+typedef void (VKAPI_PTR *PFN_vkCmdWriteAccelerationStructurePropertiesNVX)(VkCommandBuffer commandBuffer, VkAccelerationStructureNVX accelerationStructure, VkQueryType queryType, VkQueryPool queryPool, uint32_t query);
 typedef VkResult (VKAPI_PTR *PFN_vkCompileDeferredNVX)(VkDevice device, VkPipeline pipeline, uint32_t shader);
 
 #ifndef VK_NO_PROTOTYPES
@@ -8081,7 +8137,7 @@
     const VkBindAccelerationStructureMemoryInfoNVX* pBindInfos);
 
 VKAPI_ATTR void VKAPI_CALL vkCmdBuildAccelerationStructureNVX(
-    VkCommandBuffer                             cmdBuf,
+    VkCommandBuffer                             commandBuffer,
     VkAccelerationStructureTypeNVX              type,
     uint32_t                                    instanceCount,
     VkBuffer                                    instanceData,
@@ -8096,13 +8152,13 @@
     VkDeviceSize                                scratchOffset);
 
 VKAPI_ATTR void VKAPI_CALL vkCmdCopyAccelerationStructureNVX(
-    VkCommandBuffer                             cmdBuf,
+    VkCommandBuffer                             commandBuffer,
     VkAccelerationStructureNVX                  dst,
     VkAccelerationStructureNVX                  src,
     VkCopyAccelerationStructureModeNVX          mode);
 
 VKAPI_ATTR void VKAPI_CALL vkCmdTraceRaysNVX(
-    VkCommandBuffer                             cmdBuf,
+    VkCommandBuffer                             commandBuffer,
     VkBuffer                                    raygenShaderBindingTableBuffer,
     VkDeviceSize                                raygenShaderBindingOffset,
     VkBuffer                                    missShaderBindingTableBuffer,
@@ -8137,7 +8193,7 @@
     void*                                       pData);
 
 VKAPI_ATTR void VKAPI_CALL vkCmdWriteAccelerationStructurePropertiesNVX(
-    VkCommandBuffer                             cmdBuf,
+    VkCommandBuffer                             commandBuffer,
     VkAccelerationStructureNVX                  accelerationStructure,
     VkQueryType                                 queryType,
     VkQueryPool                                 queryPool,
diff --git a/vulkan/libvulkan/layers_extensions.cpp b/vulkan/libvulkan/layers_extensions.cpp
index b32977a..009b257 100644
--- a/vulkan/libvulkan/layers_extensions.cpp
+++ b/vulkan/libvulkan/layers_extensions.cpp
@@ -78,7 +78,7 @@
           native_bridge_(false),
           refcount_(0) {}
 
-    LayerLibrary(LayerLibrary&& other)
+    LayerLibrary(LayerLibrary&& other) noexcept
         : path_(std::move(other.path_)),
           filename_(std::move(other.filename_)),
           dlhandle_(other.dlhandle_),
@@ -545,7 +545,7 @@
     }
 }
 
-LayerRef::LayerRef(LayerRef&& other) : layer_(other.layer_) {
+LayerRef::LayerRef(LayerRef&& other) noexcept : layer_(other.layer_) {
     other.layer_ = nullptr;
 }
 
diff --git a/vulkan/libvulkan/layers_extensions.h b/vulkan/libvulkan/layers_extensions.h
index 07ac1a3..1dae456 100644
--- a/vulkan/libvulkan/layers_extensions.h
+++ b/vulkan/libvulkan/layers_extensions.h
@@ -27,7 +27,7 @@
 class LayerRef {
    public:
     explicit LayerRef(const Layer* layer);
-    LayerRef(LayerRef&& other);
+    LayerRef(LayerRef&& other) noexcept;
     ~LayerRef();
     LayerRef(const LayerRef&) = delete;
     LayerRef& operator=(const LayerRef&) = delete;
diff --git a/vulkan/vkjson/vkjson.cc b/vulkan/vkjson/vkjson.cc
index 6200383..f841862 100644
--- a/vulkan/vkjson/vkjson.cc
+++ b/vulkan/vkjson/vkjson.cc
@@ -544,6 +544,31 @@
 
 template <typename Visitor>
 inline bool Iterate(Visitor* visitor,
+                    VkJsonExtDriverProperties* properties) {
+  return visitor->Visit("driverPropertiesKHR",
+                        &properties->driver_properties_khr);
+}
+
+template <typename Visitor>
+inline bool Iterate(Visitor* visitor,
+                    VkPhysicalDeviceDriverPropertiesKHR* properties) {
+  return visitor->Visit("driverID", &properties->driverID) &&
+         visitor->Visit("driverName", &properties->driverName) &&
+         visitor->Visit("driverInfo", &properties->driverInfo) &&
+         visitor->Visit("conformanceVersion", &properties->conformanceVersion);
+}
+
+template <typename Visitor>
+inline bool Iterate(Visitor* visitor,
+                    VkConformanceVersionKHR* version) {
+  return visitor->Visit("major", &version->major) &&
+         visitor->Visit("minor", &version->minor) &&
+         visitor->Visit("subminor", &version->subminor) &&
+         visitor->Visit("patch", &version->patch);
+}
+
+template <typename Visitor>
+inline bool Iterate(Visitor* visitor,
                     VkJsonExtVariablePointerFeatures* features) {
   return visitor->Visit("variablePointerFeaturesKHR",
                         &features->variable_pointer_features_khr);
@@ -769,13 +794,19 @@
     case VK_API_VERSION_1_0:
       ret &= visitor->Visit("properties", &device->properties) &&
              visitor->Visit("features", &device->features) &&
-             visitor->Visit("VK_KHR_variable_pointers",
-                            &device->ext_variable_pointer_features) &&
              visitor->Visit("memory", &device->memory) &&
              visitor->Visit("queues", &device->queues) &&
              visitor->Visit("extensions", &device->extensions) &&
              visitor->Visit("layers", &device->layers) &&
              visitor->Visit("formats", &device->formats);
+      if (device->ext_driver_properties.reported) {
+        ret &= visitor->Visit("VK_KHR_driver_properties",
+                            &device->ext_driver_properties);
+      }
+      if (device->ext_variable_pointer_features.reported) {
+        ret &= visitor->Visit("VK_KHR_variable_pointers",
+                            &device->ext_variable_pointer_features);
+      }
   }
   return ret;
 }
diff --git a/vulkan/vkjson/vkjson.h b/vulkan/vkjson/vkjson.h
index 5e8428a..3373f19 100644
--- a/vulkan/vkjson/vkjson.h
+++ b/vulkan/vkjson/vkjson.h
@@ -46,11 +46,23 @@
   std::vector<VkExtensionProperties> extensions;
 };
 
+struct VkJsonExtDriverProperties {
+  VkJsonExtDriverProperties() {
+    reported = false;
+    memset(&driver_properties_khr, 0,
+           sizeof(VkPhysicalDeviceDriverPropertiesKHR));
+  }
+  bool reported;
+  VkPhysicalDeviceDriverPropertiesKHR driver_properties_khr;
+};
+
 struct VkJsonExtVariablePointerFeatures {
   VkJsonExtVariablePointerFeatures() {
+    reported = false;
     memset(&variable_pointer_features_khr, 0,
            sizeof(VkPhysicalDeviceVariablePointerFeaturesKHR));
   }
+  bool reported;
   VkPhysicalDeviceVariablePointerFeaturesKHR variable_pointer_features_khr;
 };
 
@@ -81,6 +93,7 @@
   }
   VkPhysicalDeviceProperties properties;
   VkPhysicalDeviceFeatures features;
+  VkJsonExtDriverProperties ext_driver_properties;
   VkJsonExtVariablePointerFeatures ext_variable_pointer_features;
   VkPhysicalDeviceMemoryProperties memory;
   std::vector<VkQueueFamilyProperties> queues;
diff --git a/vulkan/vkjson/vkjson_instance.cc b/vulkan/vkjson/vkjson_instance.cc
index db0450d..313d095 100644
--- a/vulkan/vkjson/vkjson_instance.cc
+++ b/vulkan/vkjson/vkjson_instance.cc
@@ -71,11 +71,16 @@
                              const char* const* instance_extensions) {
   VkJsonDevice device;
 
+  PFN_vkGetPhysicalDeviceProperties2KHR vkpGetPhysicalDeviceProperties2KHR =
+      nullptr;
   PFN_vkGetPhysicalDeviceFeatures2KHR vkpGetPhysicalDeviceFeatures2KHR =
       nullptr;
   if (instance != VK_NULL_HANDLE &&
       HasExtension("VK_KHR_get_physical_device_properties2",
                    instance_extension_count, instance_extensions)) {
+    vkpGetPhysicalDeviceProperties2KHR =
+        reinterpret_cast<PFN_vkGetPhysicalDeviceProperties2KHR>(
+            vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceProperties2KHR"));
     vkpGetPhysicalDeviceFeatures2KHR =
         reinterpret_cast<PFN_vkGetPhysicalDeviceFeatures2KHR>(
             vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceFeatures2KHR"));
@@ -98,15 +103,32 @@
                                      device.layers.data());
   }
 
-  vkGetPhysicalDeviceProperties(physical_device, &device.properties);
   if (HasExtension("VK_KHR_get_physical_device_properties2",
                    instance_extension_count, instance_extensions)) {
+    VkPhysicalDeviceProperties2KHR properties = {
+        VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR,
+        nullptr,
+        {} // properties
+    };
+    if (HasExtension("VK_KHR_driver_properties", device.extensions)) {
+      device.ext_driver_properties.reported = true;
+      device.ext_driver_properties.driver_properties_khr.sType =
+          VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR;
+      device.ext_driver_properties.driver_properties_khr.pNext =
+          properties.pNext;
+      properties.pNext =
+          &device.ext_driver_properties.driver_properties_khr;
+    }
+    vkpGetPhysicalDeviceProperties2KHR(physical_device, &properties);
+    device.properties = properties.properties;
+
     VkPhysicalDeviceFeatures2KHR features = {
         VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR,
         nullptr,
         {}  // features
     };
     if (HasExtension("VK_KHR_variable_pointers", device.extensions)) {
+      device.ext_variable_pointer_features.reported = true;
       device.ext_variable_pointer_features.variable_pointer_features_khr.sType =
           VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES_KHR;
       device.ext_variable_pointer_features.variable_pointer_features_khr.pNext =
@@ -117,6 +139,7 @@
     vkpGetPhysicalDeviceFeatures2KHR(physical_device, &features);
     device.features = features.features;
   } else {
+    vkGetPhysicalDeviceProperties(physical_device, &device.properties);
     vkGetPhysicalDeviceFeatures(physical_device, &device.features);
   }
   vkGetPhysicalDeviceMemoryProperties(physical_device, &device.memory);