Merge "SF: Adding callback to Scheduler for setting refresh rate to 60 and 90."
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 8a05c43..47c4f62 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1701,7 +1701,7 @@
     printf("*** See dumpstate-board.txt entry ***\n");
 }
 
-static void ShowUsageAndExit(int exit_code = 1) {
+static void ShowUsage() {
     fprintf(stderr,
             "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-o file] [-d] [-p] "
             "[-z]] [-s] [-S] [-q] [-B] [-P] [-R] [-V version]\n"
@@ -1721,12 +1721,6 @@
             "  -R: take bugreport in remote mode (requires -o, -z, -d and -B, "
             "shouldn't be used with -P)\n"
             "  -v: prints the dumpstate header and exit\n");
-    exit(exit_code);
-}
-
-static void ExitOnInvalidArgs() {
-    fprintf(stderr, "invalid combination of args\n");
-    ShowUsageAndExit();
 }
 
 static void register_sig_handler() {
@@ -2523,17 +2517,18 @@
 
     switch (status) {
         case Dumpstate::RunStatus::OK:
-            return 0;
-            // TODO(b/111441001): Exit directly in the following cases.
+            exit(0);
         case Dumpstate::RunStatus::HELP:
-            ShowUsageAndExit(0 /* exit code */);
-            break;
+            ShowUsage();
+            exit(0);
         case Dumpstate::RunStatus::INVALID_INPUT:
-            ExitOnInvalidArgs();
-            break;
+            fprintf(stderr, "Invalid combination of args\n");
+            ShowUsage();
+            exit(1);
         case Dumpstate::RunStatus::ERROR:
-            exit(-1);
-            break;
+            exit(2);
+        default:
+            fprintf(stderr, "Unknown status: %d\n", status);
+            exit(2);
     }
-    return 0;
 }
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index 1b69dfd..05655c1 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -23,7 +23,11 @@
         "include_apex",
     ],
 
-    cflags: ["-Wall", "-Wextra", "-Werror"],
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+    ],
 
     srcs: [
         "ibinder.cpp",
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index ee7132f..f0d25f7 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -87,6 +87,11 @@
     AStatus_getStatus;
     AStatus_isOk;
     AStatus_newOk;
+    ABinderProcess_joinThreadPool; # apex
+    ABinderProcess_setThreadPoolMaxThreadCount; # apex
+    ABinderProcess_startThreadPool; # apex
+    AServiceManager_addService; # apex
+    AServiceManager_getService; # apex
   local:
     *;
 };
diff --git a/libs/binder/ndk/scripts/init_map.sh b/libs/binder/ndk/scripts/init_map.sh
index 1f74e43..3529b72 100755
--- a/libs/binder/ndk/scripts/init_map.sh
+++ b/libs/binder/ndk/scripts/init_map.sh
@@ -10,6 +10,10 @@
     grep -oP "AParcel_[a-zA-Z0-9_]+(?=\()" include_ndk/android/binder_parcel.h;
     grep -oP "AStatus_[a-zA-Z0-9_]+(?=\()" include_ndk/android/binder_status.h;
 } | sort | uniq | awk '{ print "    " $0 ";"; }'
+{
+    grep -oP "AServiceManager_[a-zA-Z0-9_]+(?=\()" include_apex/android/binder_manager.h;
+    grep -oP "ABinderProcess_[a-zA-Z0-9_]+(?=\()" include_apex/android/binder_process.h;
+} | sort | uniq | awk '{ print "    " $0 "; # apex"; }'
 echo "  local:"
 echo "    *;"
 echo "};"
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index d1c732b..3521e89 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -121,6 +121,7 @@
     ],
 
     shared_libs: [
+        "android.frameworks.bufferhub@1.0",
         "android.hardware.graphics.common@1.1",
         "libbase",
         "libsync",
@@ -153,6 +154,7 @@
                 "BufferHubProducer.cpp",
             ],
             exclude_shared_libs: [
+                "android.frameworks.bufferhub@1.0",
                 "libbufferhub",
                 "libbufferhubqueue",
                 "libpdx_default_transport",
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index 956465c..d089bf6 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -77,6 +77,7 @@
     ],
 
     shared_libs: [
+        "android.frameworks.bufferhub@1.0",
         "android.hardware.graphics.allocator@2.0",
         "android.hardware.graphics.common@1.2",
         "android.hardware.graphics.mapper@2.0",
@@ -93,7 +94,6 @@
         "libutils",
         "libutilscallstack",
         "liblog",
-        "libpdx_default_transport",  // TODO(b/112338294): Remove this once BufferHub moved to use Binder.
     ],
 
     export_shared_lib_headers: [
@@ -121,6 +121,7 @@
                 "libnativewindow_headers",
             ],
             exclude_shared_libs: [
+                "android.frameworks.bufferhub@1.0",
                 "libpdx_default_transport",
             ],
         },
@@ -148,9 +149,6 @@
         "libhardware_headers",
         "libui_headers",
     ],
-
-    // TODO(b/117568153): Temporarily opt out using libcrt.
-    no_libcrt: true,
 }
 
 cc_library_headers {
diff --git a/libs/ui/BufferHubBuffer.cpp b/libs/ui/BufferHubBuffer.cpp
index 1184960..c70f188 100644
--- a/libs/ui/BufferHubBuffer.cpp
+++ b/libs/ui/BufferHubBuffer.cpp
@@ -14,150 +14,190 @@
  * 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 <poll.h>
 
 #include <android-base/unique_fd.h>
+#include <android/frameworks/bufferhub/1.0/IBufferHub.h>
+#include <log/log.h>
 #include <ui/BufferHubBuffer.h>
 #include <ui/BufferHubDefs.h>
+#include <utils/Trace.h>
 
-using android::base::unique_fd;
-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;
+using ::android::base::unique_fd;
+using ::android::BufferHubDefs::AnyClientAcquired;
+using ::android::BufferHubDefs::AnyClientGained;
+using ::android::BufferHubDefs::IsClientAcquired;
+using ::android::BufferHubDefs::IsClientGained;
+using ::android::BufferHubDefs::IsClientPosted;
+using ::android::BufferHubDefs::IsClientReleased;
+using ::android::frameworks::bufferhub::V1_0::BufferHubStatus;
+using ::android::frameworks::bufferhub::V1_0::BufferTraits;
+using ::android::frameworks::bufferhub::V1_0::IBufferClient;
+using ::android::frameworks::bufferhub::V1_0::IBufferHub;
+using ::android::hardware::hidl_handle;
+using ::android::hardware::graphics::common::V1_2::HardwareBufferDescription;
 
 namespace android {
 
-namespace {
-
-// TODO(b/112338294): Remove this string literal after refactoring BufferHub
-// to use Binder.
-static constexpr char kBufferHubClientPath[] = "system/buffer_hub/client";
-
-using BufferHubDefs::AnyClientAcquired;
-using BufferHubDefs::AnyClientGained;
-using BufferHubDefs::IsClientAcquired;
-using BufferHubDefs::IsClientGained;
-using BufferHubDefs::IsClientPosted;
-using BufferHubDefs::IsClientReleased;
-using BufferHubDefs::kHighBitsMask;
-
-} // 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();
+std::unique_ptr<BufferHubBuffer> BufferHubBuffer::Create(uint32_t width, uint32_t height,
+                                                         uint32_t layerCount, uint32_t format,
+                                                         uint64_t usage, size_t userMetadataSize) {
+    auto buffer = std::unique_ptr<BufferHubBuffer>(
+            new BufferHubBuffer(width, height, layerCount, format, usage, userMetadataSize));
+    return buffer->IsValid() ? std::move(buffer) : nullptr;
 }
 
-LocalChannelHandle BufferHubClient::TakeChannelHandle() {
-    if (IsConnected()) {
-        return std::move(GetChannelHandle());
-    } else {
-        return {};
+std::unique_ptr<BufferHubBuffer> BufferHubBuffer::Import(const native_handle_t* token) {
+    if (token == nullptr) {
+        ALOGE("%s: token cannot be nullptr!", __FUNCTION__);
+        return nullptr;
     }
+
+    auto buffer = std::unique_ptr<BufferHubBuffer>(new BufferHubBuffer(token));
+    return buffer->IsValid() ? std::move(buffer) : nullptr;
 }
 
 BufferHubBuffer::BufferHubBuffer(uint32_t width, uint32_t height, uint32_t layerCount,
-                                 uint32_t format, uint64_t usage, size_t mUserMetadataSize) {
+                                 uint32_t format, uint64_t usage, size_t userMetadataSize) {
     ATRACE_CALL();
-    ALOGD("%s: width=%u height=%u layerCount=%u, format=%u usage=%" PRIx64 " mUserMetadataSize=%zu",
-          __FUNCTION__, width, height, layerCount, format, usage, mUserMetadataSize);
+    ALOGD("%s: width=%u height=%u layerCount=%u, format=%u "
+          "usage=%" PRIx64 " mUserMetadataSize=%zu",
+          __FUNCTION__, width, height, layerCount, format, usage, userMetadataSize);
 
-    auto status =
-            mClient.InvokeRemoteMethod<DetachedBufferRPC::Create>(width, height, layerCount, format,
-                                                                  usage, mUserMetadataSize);
-    if (!status) {
-        ALOGE("%s: Failed to create detached buffer: %s", __FUNCTION__,
-              status.GetErrorMessage().c_str());
-        mClient.Close(-status.error());
+    sp<IBufferHub> bufferhub = IBufferHub::getService();
+    if (bufferhub.get() == nullptr) {
+        ALOGE("%s: BufferHub service not found!", __FUNCTION__);
+        return;
     }
 
-    const int ret = ImportGraphicBuffer();
-    if (ret < 0) {
-        ALOGE("%s: Failed to import buffer: %s", __FUNCTION__, strerror(-ret));
-        mClient.Close(ret);
+    AHardwareBuffer_Desc aDesc = {width, height,         layerCount,   format,
+                                  usage, /*stride=*/0UL, /*rfu0=*/0UL, /*rfu1=*/0ULL};
+    HardwareBufferDescription desc;
+    memcpy(&desc, &aDesc, sizeof(HardwareBufferDescription));
+
+    BufferHubStatus ret;
+    sp<IBufferClient> client;
+    BufferTraits bufferTraits;
+    IBufferHub::allocateBuffer_cb alloc_cb = [&](const auto& status, const auto& outClient,
+                                                 const auto& traits) {
+        ret = status;
+        client = std::move(outClient);
+        bufferTraits = std::move(traits);
+    };
+
+    if (!bufferhub->allocateBuffer(desc, static_cast<uint32_t>(userMetadataSize), alloc_cb)
+                 .isOk()) {
+        ALOGE("%s: allocateBuffer transaction failed!", __FUNCTION__);
+        return;
+    } else if (ret != BufferHubStatus::NO_ERROR) {
+        ALOGE("%s: allocateBuffer failed with error %u.", __FUNCTION__, ret);
+        return;
+    } else if (client == nullptr) {
+        ALOGE("%s: allocateBuffer got null BufferClient.", __FUNCTION__);
+        return;
+    }
+
+    const int importRet = initWithBufferTraits(bufferTraits);
+    if (importRet < 0) {
+        ALOGE("%s: Failed to import buffer: %s", __FUNCTION__, strerror(-importRet));
+        client->close();
+    }
+    mBufferClient = std::move(client);
+}
+
+BufferHubBuffer::BufferHubBuffer(const native_handle_t* token) {
+    sp<IBufferHub> bufferhub = IBufferHub::getService();
+    if (bufferhub.get() == nullptr) {
+        ALOGE("%s: BufferHub service not found!", __FUNCTION__);
+        return;
+    }
+
+    BufferHubStatus ret;
+    sp<IBufferClient> client;
+    BufferTraits bufferTraits;
+    IBufferHub::importBuffer_cb import_cb = [&](const auto& status, const auto& outClient,
+                                                const auto& traits) {
+        ret = status;
+        client = std::move(outClient);
+        bufferTraits = std::move(traits);
+    };
+
+    // hidl_handle(native_handle_t*) simply creates a raw pointer reference withouth ownership
+    // transfer.
+    if (!bufferhub->importBuffer(hidl_handle(token), import_cb).isOk()) {
+        ALOGE("%s: importBuffer transaction failed!", __FUNCTION__);
+        return;
+    } else if (ret != BufferHubStatus::NO_ERROR) {
+        ALOGE("%s: importBuffer failed with error %u.", __FUNCTION__, ret);
+        return;
+    } else if (client == nullptr) {
+        ALOGE("%s: importBuffer got null BufferClient.", __FUNCTION__);
+        return;
+    }
+
+    const int importRet = initWithBufferTraits(bufferTraits);
+    if (importRet < 0) {
+        ALOGE("%s: Failed to import buffer: %s", __FUNCTION__, strerror(-importRet));
+        client->close();
+    }
+    mBufferClient = std::move(client);
+}
+
+BufferHubBuffer::~BufferHubBuffer() {
+    // Close buffer client to avoid possible race condition: user could first duplicate and hold
+    // token with the original buffer gone, and then try to import the token. The close function
+    // will explicitly invalidate the token to avoid this.
+    if (mBufferClient != nullptr) {
+        if (!mBufferClient->close().isOk()) {
+            ALOGE("%s: close BufferClient transaction failed!", __FUNCTION__);
+        }
     }
 }
 
-BufferHubBuffer::BufferHubBuffer(LocalChannelHandle mChannelHandle)
-      : mClient(std::move(mChannelHandle)) {
-    const int ret = ImportGraphicBuffer();
-    if (ret < 0) {
-        ALOGE("%s: Failed to import buffer: %s", __FUNCTION__, strerror(-ret));
-        mClient.Close(ret);
-    }
-}
-
-int BufferHubBuffer::ImportGraphicBuffer() {
+int BufferHubBuffer::initWithBufferTraits(const BufferTraits& bufferTraits) {
     ATRACE_CALL();
 
-    auto status = mClient.InvokeRemoteMethod<DetachedBufferRPC::Import>();
-    if (!status) {
-        ALOGE("%s: Failed to import GraphicBuffer: %s", __FUNCTION__,
-              status.GetErrorMessage().c_str());
-        return -status.error();
+    if (bufferTraits.bufferInfo.getNativeHandle() == nullptr) {
+        ALOGE("%s: missing buffer info handle.", __FUNCTION__);
+        return -EINVAL;
     }
 
-    BufferTraits<LocalHandle> bufferTraits = status.take();
-    if (bufferTraits.id() < 0) {
-        ALOGE("%s: Received an invalid id!", __FUNCTION__);
-        return -EIO;
+    if (bufferTraits.bufferHandle.getNativeHandle() == nullptr) {
+        ALOGE("%s: missing gralloc handle.", __FUNCTION__);
+        return -EINVAL;
     }
 
-    // Stash the buffer id to replace the value in mId.
-    const int bufferId = bufferTraits.id();
+    int bufferId = bufferTraits.bufferInfo->data[1];
+    if (bufferId < 0) {
+        ALOGE("%s: Received an invalid (negative) id!", __FUNCTION__);
+        return -EINVAL;
+    }
 
-    // Import the metadata.
-    LocalHandle metadataHandle = bufferTraits.take_metadata_handle();
-    unique_fd metadataFd(metadataHandle.Release());
-    mMetadata = BufferHubMetadata::Import(std::move(metadataFd));
+    uint32_t clientBitMask;
+    memcpy(&clientBitMask, &bufferTraits.bufferInfo->data[2], sizeof(clientBitMask));
+    if (clientBitMask == 0U) {
+        ALOGE("%s: Received a invalid client state mask!", __FUNCTION__);
+        return -EINVAL;
+    }
+
+    // Import the metadata. Dup since hidl_handle owns the fd
+    unique_fd ashmemFd(dup(bufferTraits.bufferInfo->data[0]));
+    mMetadata = BufferHubMetadata::Import(std::move(ashmemFd));
 
     if (!mMetadata.IsValid()) {
         ALOGE("%s: invalid metadata.", __FUNCTION__);
-        return -ENOMEM;
+        return -EINVAL;
     }
 
-    if (mMetadata.metadata_size() != bufferTraits.metadata_size()) {
-        ALOGE("%s: metadata buffer too small: %zu, expected: %" PRIu64 ".", __FUNCTION__,
-              mMetadata.metadata_size(), bufferTraits.metadata_size());
-        return -ENOMEM;
+    uint32_t userMetadataSize;
+    memcpy(&userMetadataSize, &bufferTraits.bufferInfo->data[3], sizeof(userMetadataSize));
+    if (mMetadata.user_metadata_size() != userMetadataSize) {
+        ALOGE("%s: user metadata size not match: expected %u, actual %zu.", __FUNCTION__,
+              userMetadataSize, mMetadata.user_metadata_size());
+        return -EINVAL;
     }
 
-    size_t metadataSize = static_cast<size_t>(bufferTraits.metadata_size());
+    size_t metadataSize = static_cast<size_t>(mMetadata.metadata_size());
     if (metadataSize < BufferHubDefs::kMetadataHeaderSize) {
         ALOGE("%s: metadata too small: %zu", __FUNCTION__, metadataSize);
         return -EINVAL;
@@ -178,24 +218,14 @@
 
     // 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();
+    mBufferHandle = std::move(bufferTraits.bufferHandle);
+    memcpy(&mBufferDesc, &bufferTraits.bufferDesc, sizeof(AHardwareBuffer_Desc));
 
-    // Populate buffer desc based on buffer traits.
-    mBufferDesc.width = bufferTraits.width();
-    mBufferDesc.height = bufferTraits.height();
-    mBufferDesc.layers = bufferTraits.layer_count();
-    mBufferDesc.format = bufferTraits.format();
-    mBufferDesc.usage = bufferTraits.usage();
-    mBufferDesc.stride = bufferTraits.stride();
-    mBufferDesc.rfu0 = 0U;
-    mBufferDesc.rfu1 = 0U;
-
-    // If all imports succeed, replace the previous buffer and id.
     mId = bufferId;
-    mClientStateMask = bufferTraits.client_state_mask();
+    mClientStateMask = clientBitMask;
 
     // TODO(b/112012161) Set up shared fences.
-    ALOGD("%s: id=%d, buffer_state=%" PRIx32 ".", __FUNCTION__, id(),
+    ALOGD("%s: id=%d, buffer_state=%" PRIx32 ".", __FUNCTION__, mId,
           buffer_state_->load(std::memory_order_acquire));
     return 0;
 }
@@ -225,7 +255,7 @@
 
 int BufferHubBuffer::Post() {
     uint32_t current_buffer_state = buffer_state_->load(std::memory_order_acquire);
-    uint32_t updated_buffer_state = (~mClientStateMask) & kHighBitsMask;
+    uint32_t updated_buffer_state = (~mClientStateMask) & BufferHubDefs::kHighBitsMask;
     do {
         if (!IsClientGained(current_buffer_state, mClientStateMask)) {
             ALOGE("%s: Cannot post a buffer that is not gained by this client. buffer_id=%d "
@@ -283,24 +313,42 @@
     return 0;
 }
 
-int BufferHubBuffer::Poll(int timeoutMs) {
-    ATRACE_CALL();
-
-    pollfd p = {mClient.event_fd(), POLLIN, 0};
-    return poll(&p, 1, timeoutMs);
+bool BufferHubBuffer::IsValid() const {
+    // TODO(b/68770788): check eventFd once implemented
+    return mBufferHandle.getNativeHandle() != nullptr && mId >= 0 && mClientStateMask != 0U &&
+            mMetadata.IsValid() && mBufferClient != nullptr;
 }
 
-Status<LocalChannelHandle> BufferHubBuffer::Duplicate() {
-    ATRACE_CALL();
-    ALOGD("%s: id=%d.", __FUNCTION__, mId);
+// TODO(b/68770788): implement Poll() once we have event fd
+int BufferHubBuffer::Poll(int /* timeoutMs */) {
+    return -ENOSYS;
+}
 
-    auto statusOrHandle = mClient.InvokeRemoteMethod<DetachedBufferRPC::Duplicate>();
-
-    if (!statusOrHandle.ok()) {
-        ALOGE("%s: Failed to duplicate buffer (id=%d): %s.", __FUNCTION__, mId,
-              statusOrHandle.GetErrorMessage().c_str());
+native_handle_t* BufferHubBuffer::Duplicate() {
+    if (mBufferClient == nullptr) {
+        ALOGE("%s: missing BufferClient!", __FUNCTION__);
+        return nullptr;
     }
-    return statusOrHandle;
+
+    hidl_handle token;
+    BufferHubStatus ret;
+    IBufferClient::duplicate_cb dup_cb = [&](const auto& outToken, const auto& status) {
+        token = std::move(outToken);
+        ret = status;
+    };
+
+    if (!mBufferClient->duplicate(dup_cb).isOk()) {
+        ALOGE("%s: duplicate transaction failed!", __FUNCTION__);
+        return nullptr;
+    } else if (ret != BufferHubStatus::NO_ERROR) {
+        ALOGE("%s: duplicate failed with error %u.", __FUNCTION__, ret);
+        return nullptr;
+    } else if (token.getNativeHandle() == nullptr) {
+        ALOGE("%s: duplicate got null token.", __FUNCTION__);
+        return nullptr;
+    }
+
+    return native_handle_clone(token.getNativeHandle());
 }
 
 } // namespace android
diff --git a/libs/ui/include/ui/BufferHubBuffer.h b/libs/ui/include/ui/BufferHubBuffer.h
index 90dd391..44dfa95 100644
--- a/libs/ui/include/ui/BufferHubBuffer.h
+++ b/libs/ui/include/ui/BufferHubBuffer.h
@@ -17,73 +17,43 @@
 #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/native_handle_wrapper.h>
-#pragma clang diagnostic pop
-
+#include <android/frameworks/bufferhub/1.0/IBufferClient.h>
 #include <android/hardware_buffer.h>
+#include <cutils/native_handle.h>
 #include <ui/BufferHubDefs.h>
 #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.
+    // Allocates a standalone BufferHubBuffer.
     static std::unique_ptr<BufferHubBuffer> Create(uint32_t width, uint32_t height,
                                                    uint32_t layerCount, uint32_t format,
-                                                   uint64_t usage, size_t userMetadataSize) {
-        return std::unique_ptr<BufferHubBuffer>(
-                new BufferHubBuffer(width, height, layerCount, format, usage, userMetadataSize));
-    }
+                                                   uint64_t usage, size_t userMetadataSize);
 
-    // 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)));
-    }
+    // Imports the given token to a BufferHubBuffer. Not taking ownership of the token. Caller
+    // should close and destroy the token after calling this function regardless of output.
+    // TODO(b/122543147): use a movable wrapper for token
+    static std::unique_ptr<BufferHubBuffer> Import(const native_handle_t* token);
 
     BufferHubBuffer(const BufferHubBuffer&) = delete;
     void operator=(const BufferHubBuffer&) = delete;
 
+    virtual ~BufferHubBuffer();
+
     // Gets ID of the buffer client. All BufferHubBuffer clients derived from the same buffer in
-    // bufferhubd share the same buffer id.
+    // BufferHub share the same buffer id.
     int id() const { return mId; }
 
-    // Returns the buffer description, which is guaranteed to be faithful values from bufferhubd.
+    // Returns the buffer description, which is guaranteed to be faithful values from BufferHub.
     const AHardwareBuffer_Desc& desc() const { return mBufferDesc; }
 
-    const native_handle_t* DuplicateHandle() { return mBufferHandle.DuplicateHandle(); }
+    // Duplicate the underlying Gralloc buffer handle. Caller is responsible to free the handle
+    // after use.
+    native_handle_t* DuplicateHandle() {
+        return native_handle_clone(mBufferHandle.getNativeHandle());
+    }
 
     // Returns the current value of MetadataHeader::buffer_state.
     uint32_t buffer_state() {
@@ -96,12 +66,12 @@
 
     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 BufferClient is still alive.
+    bool IsConnected() const { return mBufferClient->ping().isOk(); }
 
-    // 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 true if the buffer is valid: non-null buffer handle, valid id, valid client bit mask,
+    // valid metadata and valid buffer client
+    bool IsValid() const;
 
     // Gains the buffer for exclusive write permission. Read permission is implied once a buffer is
     // gained.
@@ -124,33 +94,27 @@
     // current cycle of the usage of the buffer.
     int Release();
 
-    // 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);
 
-    // 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();
+    // Creates a token that stands for this BufferHubBuffer client and could be used for Import to
+    // create another BufferHubBuffer. The new BufferHubBuffer will share the same underlying
+    // gralloc buffer and ashmem region for metadata. Note that the caller owns the token and
+    // should free it after use.
+    // Returns a valid token on success, nullptr on failure.
+    // TODO(b/122543147): use a movable wrapper for token
+    native_handle_t* Duplicate();
 
 private:
     BufferHubBuffer(uint32_t width, uint32_t height, uint32_t layerCount, uint32_t format,
                     uint64_t usage, size_t userMetadataSize);
 
-    BufferHubBuffer(pdx::LocalChannelHandle mChannelHandle);
+    BufferHubBuffer(const native_handle_t* token);
 
-    int ImportGraphicBuffer();
+    int initWithBufferTraits(const frameworks::bufferhub::V1_0::BufferTraits& bufferTraits);
 
     // Global id for the buffer that is consistent across processes.
-    int mId = -1;
+    int mId = 0;
 
     // Client state mask of this BufferHubBuffer object. It is unique amoung all
     // clients/users of the buffer.
@@ -159,8 +123,8 @@
     // Stores ground truth of the buffer.
     AHardwareBuffer_Desc mBufferDesc;
 
-    // Wrapps the gralloc buffer handle of this buffer.
-    dvr::NativeHandleWrapper<pdx::LocalHandle> mBufferHandle;
+    // Wraps the gralloc buffer handle of this buffer.
+    hardware::hidl_handle mBufferHandle;
 
     // An ashmem-based metadata object. The same shared memory are mapped to the
     // bufferhubd daemon and all buffer clients.
@@ -170,8 +134,8 @@
     std::atomic<uint32_t>* fence_state_ = nullptr;
     std::atomic<uint32_t>* active_clients_bit_mask_ = nullptr;
 
-    // PDX backend.
-    BufferHubClient mClient;
+    // HwBinder backend
+    sp<frameworks::bufferhub::V1_0::IBufferClient> mBufferClient;
 };
 
 } // namespace android
diff --git a/libs/ui/include/ui/BufferHubDefs.h b/libs/ui/include/ui/BufferHubDefs.h
index d259fef..069f0dc 100644
--- a/libs/ui/include/ui/BufferHubDefs.h
+++ b/libs/ui/include/ui/BufferHubDefs.h
@@ -158,6 +158,29 @@
 static_assert(sizeof(MetadataHeader) == 128, "Unexpected MetadataHeader size");
 static constexpr size_t kMetadataHeaderSize = sizeof(MetadataHeader);
 
+/**
+ * android.frameworks.bufferhub@1.0::BufferTraits.bufferInfo is an opaque handle. See
+ * https://cs.corp.google.com/android/frameworks/hardware/interfaces/bufferhub/1.0/types.hal for
+ * more details about android.frameworks.bufferhub@1.0::BufferTraits.
+ *
+ * This definition could be changed, but implementation of BufferHubService::buildBufferInfo
+ * (frameworks/native/services/bufferhub), VtsHalBufferHubV1_0TargetTest
+ * (frameworks/hardware/interfaces/bufferhub) and BufferHubBuffer::readBufferTraits (libui) will
+ * also need to be updated.
+ *
+ * It's definition should follow the following format:
+ * {
+ *   NumFds = 1,
+ *   NumInts = 3,
+ *   data[0] = Ashmem fd for BufferHubMetadata,
+ *   data[1] = buffer id,
+ *   data[2] = client state bit mask,
+ *   data[3] = user metadata size,
+ * }
+ */
+static constexpr int kBufferInfoNumFds = 1;
+static constexpr int kBufferInfoNumInts = 3;
+
 } // namespace BufferHubDefs
 
 } // namespace android
diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp
index a670b3c..665469e 100644
--- a/libs/ui/tests/Android.bp
+++ b/libs/ui/tests/Android.bp
@@ -31,12 +31,14 @@
 cc_test {
     name: "GraphicBuffer_test",
     header_libs: [
-        "libbufferhub_headers",
         "libdvr_headers",
         "libnativewindow_headers",
     ],
     shared_libs: [
-        "libpdx_default_transport",
+        "android.frameworks.bufferhub@1.0",
+        "libcutils",
+        "libhidlbase",
+        "libhwbinder",
         "libui",
         "libutils",
     ],
@@ -47,7 +49,6 @@
 cc_test {
     name: "BufferHub_test",
     header_libs: [
-        "libbufferhub_headers",
         "libdvr_headers",
         "libnativewindow_headers",
     ],
@@ -60,7 +61,6 @@
         "libhidlbase",
         "libhwbinder",
         "liblog",
-        "libpdx_default_transport",
         "libui",
         "libutils"
     ],
diff --git a/libs/ui/tests/BufferHubBuffer_test.cpp b/libs/ui/tests/BufferHubBuffer_test.cpp
index 69b9590..cd744cd 100644
--- a/libs/ui/tests/BufferHubBuffer_test.cpp
+++ b/libs/ui/tests/BufferHubBuffer_test.cpp
@@ -16,10 +16,9 @@
 
 #define LOG_TAG "BufferHubBufferTest"
 
-#include <android/frameworks/bufferhub/1.0/IBufferClient.h>
-#include <android/frameworks/bufferhub/1.0/IBufferHub.h>
 #include <android/hardware_buffer.h>
 #include <cutils/native_handle.h>
+#include <gmock/gmock.h>
 #include <gtest/gtest.h>
 #include <hidl/ServiceManagement.h>
 #include <hwbinder/IPCThreadState.h>
@@ -29,36 +28,38 @@
 
 namespace {
 
+using ::android::BufferHubDefs::AnyClientAcquired;
+using ::android::BufferHubDefs::AnyClientGained;
+using ::android::BufferHubDefs::AnyClientPosted;
+using ::android::BufferHubDefs::IsBufferReleased;
+using ::android::BufferHubDefs::IsClientAcquired;
+using ::android::BufferHubDefs::IsClientGained;
+using ::android::BufferHubDefs::IsClientPosted;
+using ::android::BufferHubDefs::IsClientReleased;
+using ::android::BufferHubDefs::kMetadataHeaderSize;
+using ::testing::IsNull;
+using ::testing::NotNull;
+
 const int kWidth = 640;
 const int kHeight = 480;
 const int kLayerCount = 1;
 const int kFormat = HAL_PIXEL_FORMAT_RGBA_8888;
 const int kUsage = 0;
-const size_t kUserMetadataSize = 0;
-
-using BufferHubDefs::AnyClientAcquired;
-using BufferHubDefs::AnyClientGained;
-using BufferHubDefs::AnyClientPosted;
-using BufferHubDefs::IsBufferReleased;
-using BufferHubDefs::IsClientAcquired;
-using BufferHubDefs::IsClientGained;
-using BufferHubDefs::IsClientPosted;
-using BufferHubDefs::IsClientReleased;
-using BufferHubDefs::kFirstClientBitMask;
-using BufferHubDefs::kMetadataHeaderSize;
-using frameworks::bufferhub::V1_0::BufferHubStatus;
-using frameworks::bufferhub::V1_0::IBufferClient;
-using frameworks::bufferhub::V1_0::IBufferHub;
-using hardware::hidl_handle;
-using hardware::graphics::common::V1_2::HardwareBufferDescription;
-using hidl::base::V1_0::IBase;
-using pdx::LocalChannelHandle;
+const AHardwareBuffer_Desc kDesc = {kWidth, kHeight,        kLayerCount,  kFormat,
+                                    kUsage, /*stride=*/0UL, /*rfu0=*/0UL, /*rfu1=*/0ULL};
+const size_t kUserMetadataSize = 1;
 
 class BufferHubBufferTest : public ::testing::Test {
 protected:
     void SetUp() override { android::hardware::ProcessState::self()->startThreadPool(); }
 };
 
+bool cmpAHardwareBufferDesc(const AHardwareBuffer_Desc& desc, const AHardwareBuffer_Desc& other) {
+    // Not comparing stride because it's unknown before allocation
+    return desc.format == other.format && desc.height == other.height &&
+            desc.layers == other.layers && desc.usage == other.usage && desc.width == other.width;
+}
+
 class BufferHubBufferStateTransitionTest : public BufferHubBufferTest {
 protected:
     void SetUp() override {
@@ -78,91 +79,126 @@
 
 void BufferHubBufferStateTransitionTest::CreateTwoClientsOfABuffer() {
     b1 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat, kUsage, kUserMetadataSize);
+    ASSERT_THAT(b1, NotNull());
     b1ClientMask = b1->client_state_mask();
     ASSERT_NE(b1ClientMask, 0U);
-    auto statusOrHandle = b1->Duplicate();
-    ASSERT_TRUE(statusOrHandle);
-    LocalChannelHandle h2 = statusOrHandle.take();
-    b2 = BufferHubBuffer::Import(std::move(h2));
+
+    native_handle_t* token = b1->Duplicate();
+    ASSERT_THAT(token, NotNull());
+
+    // TODO(b/122543147): use a movalbe wrapper for token
+    b2 = BufferHubBuffer::Import(token);
+    native_handle_close(token);
+    native_handle_delete(token);
+    ASSERT_THAT(b2, NotNull());
+
     b2ClientMask = b2->client_state_mask();
     ASSERT_NE(b2ClientMask, 0U);
     ASSERT_NE(b2ClientMask, b1ClientMask);
 }
 
-TEST_F(BufferHubBufferTest, CreateBufferHubBufferFails) {
+TEST_F(BufferHubBufferTest, CreateBufferFails) {
     // Buffer Creation will fail: BLOB format requires height to be 1.
     auto b1 = BufferHubBuffer::Create(kWidth, /*height=*/2, kLayerCount,
                                       /*format=*/HAL_PIXEL_FORMAT_BLOB, kUsage, kUserMetadataSize);
 
-    EXPECT_FALSE(b1->IsConnected());
-    EXPECT_FALSE(b1->IsValid());
+    EXPECT_THAT(b1, IsNull());
 
     // Buffer Creation will fail: user metadata size too large.
     auto b2 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat, kUsage,
                                       /*userMetadataSize=*/std::numeric_limits<size_t>::max());
 
-    EXPECT_FALSE(b2->IsConnected());
-    EXPECT_FALSE(b2->IsValid());
+    EXPECT_THAT(b2, IsNull());
 
     // Buffer Creation will fail: user metadata size too large.
     const size_t userMetadataSize = std::numeric_limits<size_t>::max() - kMetadataHeaderSize;
     auto b3 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat, kUsage,
                                       userMetadataSize);
 
-    EXPECT_FALSE(b3->IsConnected());
-    EXPECT_FALSE(b3->IsValid());
+    EXPECT_THAT(b3, IsNull());
 }
 
-TEST_F(BufferHubBufferTest, CreateBufferHubBuffer) {
+TEST_F(BufferHubBufferTest, CreateBuffer) {
     auto b1 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat, kUsage,
                                       kUserMetadataSize);
+    ASSERT_THAT(b1, NotNull());
     EXPECT_TRUE(b1->IsConnected());
     EXPECT_TRUE(b1->IsValid());
-    EXPECT_NE(b1->id(), 0);
+    EXPECT_TRUE(cmpAHardwareBufferDesc(b1->desc(), kDesc));
+    EXPECT_EQ(b1->user_metadata_size(), kUserMetadataSize);
 }
 
-TEST_F(BufferHubBufferTest, DuplicateBufferHubBuffer) {
+TEST_F(BufferHubBufferTest, DuplicateAndImportBuffer) {
     auto b1 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat, kUsage,
                                       kUserMetadataSize);
-    int id1 = b1->id();
-    uint32_t bufferStateMask1 = b1->client_state_mask();
-    EXPECT_NE(bufferStateMask1, 0U);
+    ASSERT_THAT(b1, NotNull());
     EXPECT_TRUE(b1->IsValid());
-    EXPECT_EQ(b1->user_metadata_size(), kUserMetadataSize);
 
-    auto statusOrHandle = b1->Duplicate();
-    EXPECT_TRUE(statusOrHandle);
+    native_handle_t* token = b1->Duplicate();
+    EXPECT_TRUE(token);
 
     // The detached buffer should still be valid.
     EXPECT_TRUE(b1->IsConnected());
     EXPECT_TRUE(b1->IsValid());
 
-    // Gets the channel handle for the duplicated buffer.
-    LocalChannelHandle h2 = statusOrHandle.take();
-    EXPECT_TRUE(h2.valid());
+    std::unique_ptr<BufferHubBuffer> b2 = BufferHubBuffer::Import(token);
+    native_handle_close(token);
+    native_handle_delete(token);
 
-    std::unique_ptr<BufferHubBuffer> b2 = BufferHubBuffer::Import(std::move(h2));
-    EXPECT_FALSE(h2.valid());
-    ASSERT_TRUE(b2 != nullptr);
+    ASSERT_THAT(b2, NotNull());
     EXPECT_TRUE(b2->IsValid());
-    EXPECT_EQ(b2->user_metadata_size(), kUserMetadataSize);
 
-    int id2 = b2->id();
-    uint32_t bufferStateMask2 = b2->client_state_mask();
-    EXPECT_NE(bufferStateMask2, 0U);
+    EXPECT_TRUE(cmpAHardwareBufferDesc(b1->desc(), b2->desc()));
+    EXPECT_EQ(b1->user_metadata_size(), b2->user_metadata_size());
 
     // These two buffer instances are based on the same physical buffer under the
     // hood, so they should share the same id.
-    EXPECT_EQ(id1, id2);
+    EXPECT_EQ(b1->id(), b2->id());
     // We use client_state_mask() to tell those two instances apart.
-    EXPECT_NE(bufferStateMask1, bufferStateMask2);
+    EXPECT_NE(b1->client_state_mask(), b2->client_state_mask());
 
     // Both buffer instances should be in released state currently.
     EXPECT_TRUE(IsBufferReleased(b1->buffer_state()));
     EXPECT_TRUE(IsBufferReleased(b2->buffer_state()));
+}
 
-    // TODO(b/112338294): rewrite test after migration
-    return;
+TEST_F(BufferHubBufferTest, ImportFreedBuffer) {
+    auto b1 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat, kUsage,
+                                      kUserMetadataSize);
+    ASSERT_THAT(b1, NotNull());
+    EXPECT_TRUE(b1->IsValid());
+
+    native_handle_t* token = b1->Duplicate();
+    EXPECT_TRUE(token);
+
+    // Explicitly destroy b1. Backend buffer should be freed and token becomes invalid
+    b1.reset();
+
+    // TODO(b/122543147): use a movalbe wrapper for token
+    std::unique_ptr<BufferHubBuffer> b2 = BufferHubBuffer::Import(token);
+    native_handle_close(token);
+    native_handle_delete(token);
+
+    // Import should fail with INVALID_TOKEN
+    EXPECT_THAT(b2, IsNull());
+}
+
+// nullptr must not crash the service
+TEST_F(BufferHubBufferTest, ImportNullToken) {
+    auto b1 = BufferHubBuffer::Import(nullptr);
+    EXPECT_THAT(b1, IsNull());
+}
+
+// TODO(b/118180214): remove the comment after ag/5856474 landed
+// This test has a very little chance to fail (number of existing tokens / 2 ^ 32)
+TEST_F(BufferHubBufferTest, ImportInvalidToken) {
+    native_handle_t* token = native_handle_create(/*numFds=*/0, /*numInts=*/1);
+    token->data[0] = 0;
+
+    auto b1 = BufferHubBuffer::Import(token);
+    native_handle_delete(token);
+
+    EXPECT_THAT(b1, IsNull());
 }
 
 TEST_F(BufferHubBufferStateTransitionTest, GainBuffer_fromReleasedState) {
@@ -357,13 +393,20 @@
     std::unique_ptr<BufferHubBuffer> b1 =
             BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat, kUsage,
                                     kUserMetadataSize);
+    ASSERT_THAT(b1, NotNull());
     ASSERT_EQ(b1->Gain(), 0);
 
     // Create a consumer of the buffer and test if the consumer can acquire the
     // buffer if producer posts.
-    auto statusOrHandle = b1->Duplicate();
-    ASSERT_TRUE(statusOrHandle);
-    std::unique_ptr<BufferHubBuffer> b2 = BufferHubBuffer::Import(std::move(statusOrHandle.take()));
+    // TODO(b/122543147): use a movalbe wrapper for token
+    native_handle_t* token = b1->Duplicate();
+    ASSERT_TRUE(token);
+
+    std::unique_ptr<BufferHubBuffer> b2 = BufferHubBuffer::Import(token);
+    native_handle_close(token);
+    native_handle_delete(token);
+
+    ASSERT_THAT(b2, NotNull());
     ASSERT_NE(b1->client_state_mask(), b2->client_state_mask());
 
     ASSERT_EQ(b1->Post(), 0);
@@ -380,13 +423,20 @@
 
     // Create a consumer of the buffer and test if the consumer can acquire the
     // buffer if producer posts.
-    auto statusOrHandle = b1->Duplicate();
-    ASSERT_TRUE(statusOrHandle);
-    std::unique_ptr<BufferHubBuffer> b2 = BufferHubBuffer::Import(std::move(statusOrHandle.take()));
+    // TODO(b/122543147): use a movalbe wrapper for token
+    native_handle_t* token = b1->Duplicate();
+    ASSERT_TRUE(token);
+
+    std::unique_ptr<BufferHubBuffer> b2 = BufferHubBuffer::Import(token);
+    native_handle_close(token);
+    native_handle_delete(token);
+
+    ASSERT_THAT(b2, NotNull());
     ASSERT_NE(b1->client_state_mask(), b2->client_state_mask());
 
     EXPECT_EQ(b2->Acquire(), 0);
 }
 
 } // namespace
+
 } // namespace android
diff --git a/libs/ui/tests/GraphicBuffer_test.cpp b/libs/ui/tests/GraphicBuffer_test.cpp
index 81ab3ac..5b46454 100644
--- a/libs/ui/tests/GraphicBuffer_test.cpp
+++ b/libs/ui/tests/GraphicBuffer_test.cpp
@@ -39,7 +39,7 @@
     std::unique_ptr<BufferHubBuffer> b1 =
             BufferHubBuffer::Create(kTestWidth, kTestHeight, kTestLayerCount, kTestFormat,
                                     kTestUsage, /*userMetadataSize=*/0);
-    EXPECT_NE(b1, nullptr);
+    ASSERT_NE(b1, nullptr);
     EXPECT_TRUE(b1->IsValid());
 
     sp<GraphicBuffer> gb(new GraphicBuffer(std::move(b1)));
diff --git a/libs/vr/libbufferhub/buffer_hub-test.cpp b/libs/vr/libbufferhub/buffer_hub-test.cpp
index 487a604..ed5a992 100644
--- a/libs/vr/libbufferhub/buffer_hub-test.cpp
+++ b/libs/vr/libbufferhub/buffer_hub-test.cpp
@@ -5,7 +5,6 @@
 #include <private/dvr/producer_buffer.h>
 #include <sys/epoll.h>
 #include <sys/eventfd.h>
-#include <ui/BufferHubBuffer.h>
 #include <ui/BufferHubDefs.h>
 
 #include <mutex>
@@ -20,9 +19,6 @@
     return result;                            \
   })()
 
-using android::BufferHubBuffer;
-using android::GraphicBuffer;
-using android::sp;
 using android::BufferHubDefs::AnyClientAcquired;
 using android::BufferHubDefs::AnyClientGained;
 using android::BufferHubDefs::AnyClientPosted;
@@ -31,19 +27,15 @@
 using android::BufferHubDefs::IsClientPosted;
 using android::BufferHubDefs::IsClientReleased;
 using android::BufferHubDefs::kFirstClientBitMask;
-using android::BufferHubDefs::kMetadataHeaderSize;
 using android::dvr::ConsumerBuffer;
 using android::dvr::ProducerBuffer;
-using android::pdx::LocalChannelHandle;
 using android::pdx::LocalHandle;
 using android::pdx::Status;
 
 const int kWidth = 640;
 const int kHeight = 480;
-const int kLayerCount = 1;
 const int kFormat = HAL_PIXEL_FORMAT_RGBA_8888;
 const int kUsage = 0;
-const size_t kUserMetadataSize = 0;
 // Maximum number of consumers for the buffer that only has one producer in the
 // test.
 const size_t kMaxConsumerCount =
@@ -808,7 +800,7 @@
   // TODO(b/112338294) rewrite test after migration
   return;
 
-  std::unique_ptr<ProducerBuffer> p = ProducerBuffer::Create(
+  /* std::unique_ptr<ProducerBuffer> p = ProducerBuffer::Create(
       kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
   std::unique_ptr<ConsumerBuffer> c =
       ConsumerBuffer::Import(p->CreateConsumer());
@@ -876,49 +868,14 @@
   EXPECT_TRUE(d->IsConnected());
   EXPECT_TRUE(d->IsValid());
 
-  EXPECT_EQ(d->id(), p_id);
-}
-
-TEST_F(LibBufferHubTest, TestCreateBufferHubBufferFails) {
-  // Buffer Creation will fail: BLOB format requires height to be 1.
-  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 = BufferHubBuffer::Create(
-      kWidth, kHeight, kLayerCount, kFormat, kUsage,
-      /*user_metadata_size=*/std::numeric_limits<size_t>::max());
-
-  EXPECT_FALSE(b2->IsConnected());
-  EXPECT_FALSE(b2->IsValid());
-
-  // Buffer Creation will fail: user metadata size too large.
-  auto b3 = BufferHubBuffer::Create(
-      kWidth, kHeight, kLayerCount, kFormat, kUsage,
-      /*user_metadata_size=*/std::numeric_limits<size_t>::max() -
-          kMetadataHeaderSize);
-
-  EXPECT_FALSE(b3->IsConnected());
-  EXPECT_FALSE(b3->IsValid());
-}
-
-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);
+  EXPECT_EQ(d->id(), p_id); */
 }
 
 TEST_F(LibBufferHubTest, TestDetach) {
   // TODO(b/112338294) rewrite test after migration
   return;
 
-  std::unique_ptr<ProducerBuffer> p1 = ProducerBuffer::Create(
+  /* std::unique_ptr<ProducerBuffer> p1 = ProducerBuffer::Create(
       kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
   ASSERT_TRUE(p1.get() != nullptr);
   int p1_id = p1->id();
@@ -936,47 +893,5 @@
   EXPECT_FALSE(h1.valid());
   EXPECT_TRUE(b1->IsValid());
   int b1_id = b1->id();
-  EXPECT_EQ(b1_id, p1_id);
-}
-
-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);
-  EXPECT_NE(b1->client_state_mask(), 0U);
-
-  auto status_or_handle = b1->Duplicate();
-  EXPECT_TRUE(status_or_handle);
-
-  // The detached buffer should still be valid.
-  EXPECT_TRUE(b1->IsConnected());
-  EXPECT_TRUE(b1->IsValid());
-
-  // Gets the channel handle for the duplicated buffer.
-  LocalChannelHandle h2 = status_or_handle.take();
-  EXPECT_TRUE(h2.valid());
-
-  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);
-  EXPECT_NE(b2->client_state_mask(), 0U);
-
-  int b2_id = b2->id();
-
-  // These two buffer instances are based on the same physical buffer under the
-  // hood, so they should share the same id.
-  EXPECT_EQ(b1_id, b2_id);
-  // We use client_state_mask() to tell those two instances apart.
-  EXPECT_NE(b1->client_state_mask(), b2->client_state_mask());
-
-  // Both buffer instances should be in gained state.
-  EXPECT_TRUE(IsBufferReleased(b1->buffer_state()));
-  EXPECT_TRUE(IsBufferReleased(b2->buffer_state()));
-
-  // TODO(b/112338294) rewrite test after migration
-  return;
+  EXPECT_EQ(b1_id, p1_id); */
 }
diff --git a/services/bufferhub/BufferHubIdGenerator.cpp b/services/bufferhub/BufferHubIdGenerator.cpp
index 6444a03..2c12f0e 100644
--- a/services/bufferhub/BufferHubIdGenerator.cpp
+++ b/services/bufferhub/BufferHubIdGenerator.cpp
@@ -15,6 +15,7 @@
  */
 
 #include <bufferhub/BufferHubIdGenerator.h>
+#include <log/log.h>
 
 namespace android {
 namespace frameworks {
@@ -22,20 +23,18 @@
 namespace V1_0 {
 namespace implementation {
 
-constexpr uint32_t BufferHubIdGenerator::kInvalidId;
-
 BufferHubIdGenerator& BufferHubIdGenerator::getInstance() {
     static BufferHubIdGenerator generator;
 
     return generator;
 }
 
-uint32_t BufferHubIdGenerator::getId() {
+int BufferHubIdGenerator::getId() {
     std::lock_guard<std::mutex> lock(mIdsInUseMutex);
 
     do {
-        if (++mLastId >= std::numeric_limits<uint32_t>::max()) {
-            mLastId = kInvalidId + 1;
+        if (++mLastId >= std::numeric_limits<int>::max()) {
+            mLastId = 0;
         }
     } while (mIdsInUse.find(mLastId) != mIdsInUse.end());
 
@@ -43,15 +42,14 @@
     return mLastId;
 }
 
-bool BufferHubIdGenerator::freeId(uint32_t id) {
+void BufferHubIdGenerator::freeId(int id) {
     std::lock_guard<std::mutex> lock(mIdsInUseMutex);
     auto iter = mIdsInUse.find(id);
     if (iter != mIdsInUse.end()) {
         mIdsInUse.erase(iter);
-        return true;
+    } else {
+        ALOGW("%s: Cannot free nonexistent id #%d", __FUNCTION__, id);
     }
-
-    return false;
 }
 
 } // namespace implementation
diff --git a/services/bufferhub/BufferHubService.cpp b/services/bufferhub/BufferHubService.cpp
index 43235f2..ad49cd6 100644
--- a/services/bufferhub/BufferHubService.cpp
+++ b/services/bufferhub/BufferHubService.cpp
@@ -25,6 +25,7 @@
 #include <log/log.h>
 #include <openssl/hmac.h>
 #include <system/graphics-base.h>
+#include <ui/BufferHubDefs.h>
 
 using ::android::BufferHubDefs::MetadataHeader;
 using ::android::hardware::Void;
@@ -64,10 +65,12 @@
     std::lock_guard<std::mutex> lock(mClientSetMutex);
     mClientSet.emplace(client);
 
+    hidl_handle bufferInfo =
+            buildBufferInfo(node->id(), node->AddNewActiveClientsBitToMask(),
+                            node->user_metadata_size(), node->metadata().ashmem_fd());
     BufferTraits bufferTraits = {/*bufferDesc=*/description,
                                  /*bufferHandle=*/hidl_handle(node->buffer_handle()),
-                                 // TODO(b/116681016): return real data to client
-                                 /*bufferInfo=*/hidl_handle()};
+                                 /*bufferInfo=*/bufferInfo};
 
     _hidl_cb(/*status=*/BufferHubStatus::NO_ERROR, /*bufferClient=*/client,
              /*bufferTraits=*/bufferTraits);
@@ -151,10 +154,12 @@
     HardwareBufferDescription bufferDesc;
     memcpy(&bufferDesc, &node->buffer_desc(), sizeof(HardwareBufferDescription));
 
+    hidl_handle bufferInfo =
+            buildBufferInfo(node->id(), clientStateMask, node->user_metadata_size(),
+                            node->metadata().ashmem_fd());
     BufferTraits bufferTraits = {/*bufferDesc=*/bufferDesc,
                                  /*bufferHandle=*/hidl_handle(node->buffer_handle()),
-                                 // TODO(b/116681016): return real data to client
-                                 /*bufferInfo=*/hidl_handle()};
+                                 /*bufferInfo=*/bufferInfo};
 
     _hidl_cb(/*status=*/BufferHubStatus::NO_ERROR, /*bufferClient=*/client,
              /*bufferTraits=*/bufferTraits);
@@ -336,6 +341,26 @@
     }
 }
 
+// Implementation of this function should be consistent with the definition of bufferInfo handle in
+// ui/BufferHubDefs.h.
+hidl_handle BufferHubService::buildBufferInfo(int bufferId, uint32_t clientBitMask,
+                                              uint32_t userMetadataSize, const int metadataFd) {
+    native_handle_t* infoHandle = native_handle_create(BufferHubDefs::kBufferInfoNumFds,
+                                                       BufferHubDefs::kBufferInfoNumInts);
+
+    infoHandle->data[0] = dup(metadataFd);
+    infoHandle->data[1] = bufferId;
+    // Use memcpy to convert to int without missing digit.
+    // TOOD(b/121345852): use bit_cast to unpack bufferInfo when C++20 becomes available.
+    memcpy(&infoHandle->data[2], &clientBitMask, sizeof(clientBitMask));
+    memcpy(&infoHandle->data[3], &userMetadataSize, sizeof(userMetadataSize));
+
+    hidl_handle bufferInfo;
+    bufferInfo.setTo(infoHandle, /*shouldOwn=*/true);
+
+    return bufferInfo;
+}
+
 void BufferHubService::removeTokenByClient(const BufferClient* client) {
     std::lock_guard<std::mutex> lock(mTokenMutex);
     auto iter = mTokenMap.begin();
diff --git a/services/bufferhub/BufferNode.cpp b/services/bufferhub/BufferNode.cpp
index da19a6f..5106390 100644
--- a/services/bufferhub/BufferNode.cpp
+++ b/services/bufferhub/BufferNode.cpp
@@ -30,7 +30,7 @@
 
 // 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, uint32_t id)
+                       uint64_t usage, size_t user_metadata_size, int id)
       : mId(id) {
     uint32_t out_stride = 0;
     // graphicBufferId is not used in GraphicBufferAllocator::allocate
@@ -73,12 +73,8 @@
     }
 
     // Free the id, if valid
-    if (id() != BufferHubIdGenerator::kInvalidId) {
-        if (BufferHubIdGenerator::getInstance().freeId(id())) {
-            ALOGI("%s: id #%u is freed.", __FUNCTION__, id());
-        } else {
-            ALOGE("%s: Cannot free nonexistent id #%u", __FUNCTION__, id());
-        }
+    if (mId >= 0) {
+        BufferHubIdGenerator::getInstance().freeId(mId);
     }
 }
 
diff --git a/services/bufferhub/include/bufferhub/BufferHubIdGenerator.h b/services/bufferhub/include/bufferhub/BufferHubIdGenerator.h
index b51fcda..ef7c077 100644
--- a/services/bufferhub/include/bufferhub/BufferHubIdGenerator.h
+++ b/services/bufferhub/include/bufferhub/BufferHubIdGenerator.h
@@ -28,30 +28,28 @@
 namespace V1_0 {
 namespace implementation {
 
-// A thread-safe incremental uint32_t id generator.
+// A thread-safe, non-negative, incremental, int id generator.
 class BufferHubIdGenerator {
 public:
-    // 0 is considered invalid
-    static constexpr uint32_t kInvalidId = 0U;
-
     // Get the singleton instance of this class
     static BufferHubIdGenerator& getInstance();
 
-    // Gets next available id. If next id is greater than std::numeric_limits<uint32_t>::max() (2 ^
-    // 32 - 1), it will try to get an id start from 1 again.
-    uint32_t getId();
+    // Gets next available id. If next id is greater than std::numeric_limits<int32_t>::max(), it
+    // will try to get an id start from 0 again.
+    int getId();
 
-    // Free a specific id. Return true on freed, false on not found.
-    bool freeId(uint32_t id);
+    // Free a specific id.
+    void freeId(int id);
 
 private:
     BufferHubIdGenerator() = default;
     ~BufferHubIdGenerator() = default;
 
+    // Start from -1 so all valid ids will be >= 0
+    int mLastId = -1;
+
     std::mutex mIdsInUseMutex;
-    // Start from kInvalidID to avoid generating it.
-    uint32_t mLastId = kInvalidId;
-    std::set<uint32_t> mIdsInUse GUARDED_BY(mIdsInUseMutex);
+    std::set<int> mIdsInUse GUARDED_BY(mIdsInUseMutex);
 };
 
 } // namespace implementation
diff --git a/services/bufferhub/include/bufferhub/BufferHubService.h b/services/bufferhub/include/bufferhub/BufferHubService.h
index 0195bcf..23e664e 100644
--- a/services/bufferhub/include/bufferhub/BufferHubService.h
+++ b/services/bufferhub/include/bufferhub/BufferHubService.h
@@ -57,6 +57,10 @@
     void onClientClosed(const BufferClient* client);
 
 private:
+    // Helper function to build BufferTraits.bufferInfo handle
+    hidl_handle buildBufferInfo(int bufferId, uint32_t clientBitMask, uint32_t userMetadataSize,
+                                const int metadataFd);
+
     // Helper function to remove all the token belongs to a specific client.
     void removeTokenByClient(const BufferClient* client);
 
diff --git a/services/bufferhub/include/bufferhub/BufferNode.h b/services/bufferhub/include/bufferhub/BufferNode.h
index cf56c33..b7a195b 100644
--- a/services/bufferhub/include/bufferhub/BufferNode.h
+++ b/services/bufferhub/include/bufferhub/BufferNode.h
@@ -16,15 +16,14 @@
 public:
     // 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,
-               uint32_t id = BufferHubIdGenerator::kInvalidId);
+               uint64_t usage, size_t user_metadata_size, int id = -1);
 
     ~BufferNode();
 
     // Returns whether the object holds a valid metadata.
     bool IsValid() const { return metadata_.IsValid(); }
 
-    uint32_t id() const { return mId; }
+    int id() const { return mId; }
 
     size_t user_metadata_size() const { return metadata_.user_metadata_size(); }
 
@@ -64,10 +63,10 @@
     // Metadata in shared memory.
     BufferHubMetadata metadata_;
 
-    // A system-unique id generated by bufferhub from 1 to std::numeric_limits<uint32_t>::max().
-    // BufferNodes not created by bufferhub will have id = 0, meaning "not specified".
-    // TODO(b/118891412): remove default id = 0 and update comments after pdx is no longer in use
-    const uint32_t mId = 0;
+    // A system-unique id generated by bufferhub from 0 to std::numeric_limits<int>::max().
+    // BufferNodes not created by bufferhub will have id < 0, meaning "not specified".
+    // TODO(b/118891412): remove default id = -1 and update comments after pdx is no longer in use
+    const int mId = -1;
 
     // The following variables are atomic variables in metadata_ that are visible
     // to Bn object and Bp objects. Please find more info in
diff --git a/services/bufferhub/tests/BufferHubIdGenerator_test.cpp b/services/bufferhub/tests/BufferHubIdGenerator_test.cpp
index fe01013..fb6de0d 100644
--- a/services/bufferhub/tests/BufferHubIdGenerator_test.cpp
+++ b/services/bufferhub/tests/BufferHubIdGenerator_test.cpp
@@ -15,25 +15,28 @@
 };
 
 TEST_F(BufferHubIdGeneratorTest, TestGenerateAndFreeID) {
-    uint32_t id = mIdGenerator->getId();
-    EXPECT_NE(id, BufferHubIdGenerator::kInvalidId);
+    int id = mIdGenerator->getId();
+    EXPECT_GE(id, 0);
 
-    EXPECT_TRUE(mIdGenerator->freeId(id));
-    EXPECT_FALSE(mIdGenerator->freeId(id));
+    mIdGenerator->freeId(id);
 }
 
 TEST_F(BufferHubIdGeneratorTest, TestGenerateUniqueIncrementalID) {
     // 10 IDs should not overflow the UniqueIdGenerator to cause a roll back to start, so the
     // resulting IDs should still keep incresing.
-    const size_t kTestSize = 10U;
-    uint32_t ids[kTestSize];
-    for (size_t i = 0UL; i < kTestSize; ++i) {
+    const int kTestSize = 10;
+    int ids[kTestSize];
+    for (int i = 0; i < kTestSize; ++i) {
         ids[i] = mIdGenerator->getId();
-        EXPECT_NE(ids[i], BufferHubIdGenerator::kInvalidId);
+        EXPECT_GE(ids[i], 0);
         if (i >= 1) {
             EXPECT_GT(ids[i], ids[i - 1]);
         }
     }
+
+    for (int i = 0; i < kTestSize; ++i) {
+        mIdGenerator->freeId(ids[i]);
+    }
 }
 
 } // namespace
diff --git a/services/displayservice/include/displayservice/DisplayEventReceiver.h b/services/displayservice/include/displayservice/DisplayEventReceiver.h
index 5d569b6..042a054 100644
--- a/services/displayservice/include/displayservice/DisplayEventReceiver.h
+++ b/services/displayservice/include/displayservice/DisplayEventReceiver.h
@@ -45,7 +45,7 @@
     using FwkReceiver = ::android::DisplayEventReceiver;
 
     struct AttachedEvent : LooperCallback {
-        AttachedEvent(const sp<IEventCallback> &callback);
+        explicit AttachedEvent(const sp<IEventCallback> &callback);
         ~AttachedEvent();
 
         bool detach();
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index a6d3b75..efea408 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -2691,7 +2691,7 @@
             event.initialize(args->deviceId, args->source, args->displayId,
                     args->action, args->actionButton,
                     args->flags, args->edgeFlags, args->metaState, args->buttonState,
-                    MotionClassification::NONE, 0, 0, args->xPrecision, args->yPrecision,
+                    args->classification, 0, 0, args->xPrecision, args->yPrecision,
                     args->downTime, args->eventTime,
                     args->pointerCount, args->pointerProperties, args->pointerCoords);
 
@@ -3175,7 +3175,7 @@
             }
 
             if (mFocusedDisplayId == displayId) {
-                onFocusChangedLocked(newFocusedWindowHandle);
+                onFocusChangedLocked(oldFocusedWindowHandle, newFocusedWindowHandle);
             }
 
         }
@@ -3293,7 +3293,7 @@
             // Sanity check
             sp<InputWindowHandle> newFocusedWindowHandle =
                     getValueByKey(mFocusedWindowHandlesByDisplay, displayId);
-            onFocusChangedLocked(newFocusedWindowHandle);
+            onFocusChangedLocked(oldFocusedWindowHandle, newFocusedWindowHandle);
 
             if (newFocusedWindowHandle == nullptr) {
                 ALOGW("Focused display #%" PRId32 " does not have a focused window.", displayId);
@@ -3374,11 +3374,6 @@
     mLooper->wake();
 }
 
-bool InputDispatcher::transferTouchFocus(const sp<InputChannel>& fromChannel,
-        const sp<InputChannel>& toChannel) {
-    return transferTouchFocus(fromChannel->getToken(), toChannel->getToken());
-}
-
 bool InputDispatcher::transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken) {
     if (fromToken == toToken) {
 #if DEBUG_FOCUS
@@ -3392,14 +3387,14 @@
 
         sp<InputWindowHandle> fromWindowHandle = getWindowHandleLocked(fromToken);
         sp<InputWindowHandle> toWindowHandle = getWindowHandleLocked(toToken);
-#if DEBUG_FOCUS
-        ALOGD("transferTouchFocus: fromWindowHandle=%s, toWindowHandle=%s",
-            fromWindowHandle->getName().c_str(), toWindowHandle->getName().c_str());
-#endif
         if (fromWindowHandle == nullptr || toWindowHandle == nullptr) {
             ALOGW("Cannot transfer focus because from or to window not found.");
             return false;
         }
+#if DEBUG_FOCUS
+        ALOGD("transferTouchFocus: fromWindowHandle=%s, toWindowHandle=%s",
+            fromWindowHandle->getName().c_str(), toWindowHandle->getName().c_str());
+#endif
         if (fromWindowHandle->getInfo()->displayId != toWindowHandle->getInfo()->displayId) {
 #if DEBUG_FOCUS
             ALOGD("Cannot transfer focus because windows are on different displays.");
@@ -3860,11 +3855,14 @@
     commandEntry->connection = connection;
 }
 
-void InputDispatcher::onFocusChangedLocked(const sp<InputWindowHandle>& newFocus) {
-    sp<IBinder> token = newFocus != nullptr ? newFocus->getToken() : nullptr;
+void InputDispatcher::onFocusChangedLocked(const sp<InputWindowHandle>& oldFocus,
+        const sp<InputWindowHandle>& newFocus) {
+    sp<IBinder> oldToken = oldFocus != nullptr ? oldFocus->getToken() : nullptr;
+    sp<IBinder> newToken = newFocus != nullptr ? newFocus->getToken() : nullptr;
     CommandEntry* commandEntry = postCommandLocked(
             & InputDispatcher::doNotifyFocusChangedLockedInterruptible);
-    commandEntry->token = token;
+    commandEntry->oldToken = oldToken;
+    commandEntry->newToken = newToken;
 }
 
 void InputDispatcher::onANRLocked(
@@ -3926,9 +3924,10 @@
 
 void InputDispatcher::doNotifyFocusChangedLockedInterruptible(
         CommandEntry* commandEntry) {
-    sp<IBinder> token = commandEntry->token;
+    sp<IBinder> oldToken = commandEntry->oldToken;
+    sp<IBinder> newToken = commandEntry->newToken;
     mLock.unlock();
-    mPolicy->notifyFocusChanged(token);
+    mPolicy->notifyFocusChanged(oldToken, newToken);
     mLock.lock();
 }
 
diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h
index ecd5cb9..49de6f3 100644
--- a/services/inputflinger/InputDispatcher.h
+++ b/services/inputflinger/InputDispatcher.h
@@ -217,7 +217,7 @@
 
     /* Notifies the system that an input channel is unrecoverably broken. */
     virtual void notifyInputChannelBroken(const sp<IBinder>& token) = 0;
-    virtual void notifyFocusChanged(const sp<IBinder>& token) = 0;
+    virtual void notifyFocusChanged(const sp<IBinder>& oldToken, const sp<IBinder>& newToken) = 0;
 
     /* Gets the input dispatcher configuration. */
     virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) = 0;
@@ -349,9 +349,6 @@
      */
     virtual bool transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken) = 0;
 
-    virtual bool transferTouchFocus(const sp<InputChannel>& fromChannel,
-            const sp<InputChannel>& toChannel) = 0;
-
     /* Registers input channels that may be used as targets for input events.
      * If inputWindowHandle is null, and displayId is not ADISPLAY_ID_NONE,
      * the channel will receive a copy of all input events form the specific displayId.
@@ -416,8 +413,6 @@
     virtual void setInputFilterEnabled(bool enabled);
 
     virtual bool transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken);
-    virtual bool transferTouchFocus(const sp<InputChannel>& fromChannel,
-            const sp<InputChannel>& toChannel);
 
     virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel,
             int32_t displayId);
@@ -633,7 +628,8 @@
         uint32_t seq;
         bool handled;
         sp<InputChannel> inputChannel;
-        sp<IBinder> token;
+        sp<IBinder> oldToken;
+        sp<IBinder> newToken;
     };
 
     // Generic queue implementation.
@@ -1163,7 +1159,8 @@
             nsecs_t currentTime, const sp<Connection>& connection, uint32_t seq, bool handled);
     void onDispatchCycleBrokenLocked(
             nsecs_t currentTime, const sp<Connection>& connection);
-    void onFocusChangedLocked(const sp<InputWindowHandle>& newFocus);
+    void onFocusChangedLocked(const sp<InputWindowHandle>& oldFocus,
+            const sp<InputWindowHandle>& newFocus);
     void onANRLocked(
             nsecs_t currentTime, const sp<InputApplicationHandle>& applicationHandle,
             const sp<InputWindowHandle>& windowHandle,
diff --git a/services/inputflinger/InputListener.cpp b/services/inputflinger/InputListener.cpp
index b4eb370..b349c73 100644
--- a/services/inputflinger/InputListener.cpp
+++ b/services/inputflinger/InputListener.cpp
@@ -71,8 +71,8 @@
 NotifyMotionArgs::NotifyMotionArgs(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId,
         uint32_t source, int32_t displayId, uint32_t policyFlags,
         int32_t action, int32_t actionButton, int32_t flags, int32_t metaState,
-        int32_t buttonState, int32_t edgeFlags, uint32_t deviceTimestamp,
-        uint32_t pointerCount,
+        int32_t buttonState, MotionClassification classification,
+        int32_t edgeFlags, uint32_t deviceTimestamp, uint32_t pointerCount,
         const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
         float xPrecision, float yPrecision, nsecs_t downTime,
         const std::vector<TouchVideoFrame>& videoFrames) :
@@ -80,7 +80,7 @@
         displayId(displayId), policyFlags(policyFlags),
         action(action), actionButton(actionButton),
         flags(flags), metaState(metaState), buttonState(buttonState),
-        edgeFlags(edgeFlags), deviceTimestamp(deviceTimestamp),
+        classification(classification), edgeFlags(edgeFlags), deviceTimestamp(deviceTimestamp),
         pointerCount(pointerCount),
         xPrecision(xPrecision), yPrecision(yPrecision), downTime(downTime),
         videoFrames(videoFrames) {
@@ -95,7 +95,7 @@
         source(other.source), displayId(other.displayId), policyFlags(other.policyFlags),
         action(other.action), actionButton(other.actionButton), flags(other.flags),
         metaState(other.metaState), buttonState(other.buttonState),
-        edgeFlags(other.edgeFlags),
+        classification(other.classification), edgeFlags(other.edgeFlags),
         deviceTimestamp(other.deviceTimestamp), pointerCount(other.pointerCount),
         xPrecision(other.xPrecision), yPrecision(other.yPrecision), downTime(other.downTime),
         videoFrames(other.videoFrames) {
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index 33bf163..2b31f6e 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -2834,7 +2834,8 @@
                 NotifyMotionArgs releaseArgs(mContext->getNextSequenceNum(), when, getDeviceId(),
                         mSource, displayId, policyFlags,
                         AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, 0,
-                        metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
+                        metaState, buttonState,
+                        MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
                         /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
                         mXPrecision, mYPrecision, downTime, /* videoFrames */ {});
                 getListener()->notifyMotion(&releaseArgs);
@@ -2843,7 +2844,7 @@
 
         NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource,
                 displayId, policyFlags, motionEventAction, 0, 0, metaState, currentButtonState,
-                AMOTION_EVENT_EDGE_FLAG_NONE,
+                MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
                 /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
                 mXPrecision, mYPrecision, downTime, /* videoFrames */ {});
         getListener()->notifyMotion(&args);
@@ -2855,7 +2856,8 @@
                 buttonState |= actionButton;
                 NotifyMotionArgs pressArgs(mContext->getNextSequenceNum(), when, getDeviceId(),
                         mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_BUTTON_PRESS,
-                        actionButton, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
+                        actionButton, 0, metaState, buttonState,
+                        MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
                         /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
                         mXPrecision, mYPrecision, downTime, /* videoFrames */ {});
                 getListener()->notifyMotion(&pressArgs);
@@ -2869,7 +2871,8 @@
                 && (mSource == AINPUT_SOURCE_MOUSE)) {
             NotifyMotionArgs hoverArgs(mContext->getNextSequenceNum(), when, getDeviceId(),
                     mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0,
-                    metaState, currentButtonState, AMOTION_EVENT_EDGE_FLAG_NONE,
+                    metaState, currentButtonState,
+                    MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
                     /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
                     mXPrecision, mYPrecision, downTime, /* videoFrames */ {});
             getListener()->notifyMotion(&hoverArgs);
@@ -2883,7 +2886,7 @@
             NotifyMotionArgs scrollArgs(mContext->getNextSequenceNum(), when, getDeviceId(),
                     mSource, displayId, policyFlags,
                     AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, currentButtonState,
-                    AMOTION_EVENT_EDGE_FLAG_NONE,
+                    MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
                     /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
                     mXPrecision, mYPrecision, downTime, /* videoFrames */ {});
             getListener()->notifyMotion(&scrollArgs);
@@ -3014,8 +3017,8 @@
 
         NotifyMotionArgs scrollArgs(mContext->getNextSequenceNum(), when, getDeviceId(),
                 mSource, displayId, policyFlags,
-                AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, 0,
-                AMOTION_EVENT_EDGE_FLAG_NONE,
+                AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, /* buttonState */ 0,
+                MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
                 /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
                 0, 0, 0, /* videoFrames */ {});
         getListener()->notifyMotion(&scrollArgs);
@@ -5413,7 +5416,7 @@
         NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
                 mSource, displayId, policyFlags,
                 AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0,
-                metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
+                metaState, buttonState, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
                 /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
                 0, 0, mPointerGesture.downTime, /* videoFrames */ {});
         getListener()->notifyMotion(&args);
@@ -6338,8 +6341,8 @@
         // Send up.
         NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
                 mSource, displayId, policyFlags,
-                AMOTION_EVENT_ACTION_UP, 0, 0, metaState, mLastRawState.buttonState, 0,
-                /* deviceTimestamp */ 0,
+                AMOTION_EVENT_ACTION_UP, 0, 0, metaState, mLastRawState.buttonState,
+                MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0,
                 1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords,
                 mOrientedXPrecision, mOrientedYPrecision,
                 mPointerSimple.downTime, /* videoFrames */ {});
@@ -6352,8 +6355,8 @@
         // Send hover exit.
         NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
                 mSource, displayId, policyFlags,
-                AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState, mLastRawState.buttonState, 0,
-                /* deviceTimestamp */ 0,
+                AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState, mLastRawState.buttonState,
+                MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0,
                 1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords,
                 mOrientedXPrecision, mOrientedYPrecision,
                 mPointerSimple.downTime, /* videoFrames */ {});
@@ -6368,7 +6371,8 @@
             // Send down.
             NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
                     mSource, displayId, policyFlags,
-                    AMOTION_EVENT_ACTION_DOWN, 0, 0, metaState, mCurrentRawState.buttonState, 0,
+                    AMOTION_EVENT_ACTION_DOWN, 0, 0, metaState, mCurrentRawState.buttonState,
+                    MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
                     /* deviceTimestamp */ 0,
                     1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
                     mOrientedXPrecision, mOrientedYPrecision,
@@ -6379,8 +6383,8 @@
         // Send move.
         NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
                 mSource, displayId, policyFlags,
-                AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, mCurrentRawState.buttonState, 0,
-                /* deviceTimestamp */ 0,
+                AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, mCurrentRawState.buttonState,
+                MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0,
                 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
                 mOrientedXPrecision, mOrientedYPrecision,
                 mPointerSimple.downTime, /* videoFrames */ {});
@@ -6395,8 +6399,8 @@
             NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
                     mSource, displayId, policyFlags,
                     AMOTION_EVENT_ACTION_HOVER_ENTER, 0, 0, metaState,
-                    mCurrentRawState.buttonState, 0,
-                    /* deviceTimestamp */ 0,
+                    mCurrentRawState.buttonState, MotionClassification::NONE,
+                    AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0,
                     1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
                     mOrientedXPrecision, mOrientedYPrecision,
                     mPointerSimple.downTime, /* videoFrames */ {});
@@ -6407,8 +6411,8 @@
         NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
                 mSource, displayId, policyFlags,
                 AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
-                mCurrentRawState.buttonState, 0,
-                /* deviceTimestamp */ 0,
+                mCurrentRawState.buttonState, MotionClassification::NONE,
+                AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0,
                 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
                 mOrientedXPrecision, mOrientedYPrecision,
                 mPointerSimple.downTime, /* videoFrames */ {});
@@ -6429,8 +6433,8 @@
 
         NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
                 mSource, displayId, policyFlags,
-                AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, mCurrentRawState.buttonState, 0,
-                /* deviceTimestamp */ 0,
+                AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, mCurrentRawState.buttonState,
+                MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0,
                 1, &mPointerSimple.currentProperties, &pointerCoords,
                 mOrientedXPrecision, mOrientedYPrecision,
                 mPointerSimple.downTime, /* videoFrames */ {});
@@ -6497,8 +6501,8 @@
     std::vector<TouchVideoFrame> frames = mDevice->getEventHub()->getVideoFrames(deviceId);
     NotifyMotionArgs args(mContext->getNextSequenceNum(), when, deviceId,
             source, displayId, policyFlags,
-            action, actionButton, flags, metaState, buttonState, edgeFlags,
-            deviceTimestamp, pointerCount, pointerProperties, pointerCoords,
+            action, actionButton, flags, metaState, buttonState, MotionClassification::NONE,
+            edgeFlags, deviceTimestamp, pointerCount, pointerProperties, pointerCoords,
             xPrecision, yPrecision, downTime, std::move(frames));
     getListener()->notifyMotion(&args);
 }
@@ -7422,9 +7426,9 @@
 
     NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
             AINPUT_SOURCE_JOYSTICK, ADISPLAY_ID_NONE, policyFlags,
-            AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
-            /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
-            0, 0, 0, /* videoFrames */ {});
+            AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, MotionClassification::NONE,
+            AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, 1,
+            &pointerProperties, &pointerCoords, 0, 0, 0, /* videoFrames */ {});
     getListener()->notifyMotion(&args);
 }
 
diff --git a/services/inputflinger/include/InputListener.h b/services/inputflinger/include/InputListener.h
index 2442cc0..53247a0 100644
--- a/services/inputflinger/include/InputListener.h
+++ b/services/inputflinger/include/InputListener.h
@@ -99,6 +99,10 @@
     int32_t flags;
     int32_t metaState;
     int32_t buttonState;
+    /**
+     * Classification of the current touch gesture
+     */
+    MotionClassification classification;
     int32_t edgeFlags;
     /**
      * A timestamp in the input device's time base, not the platform's.
@@ -120,7 +124,7 @@
     NotifyMotionArgs(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId, uint32_t source,
             int32_t displayId, uint32_t policyFlags,
             int32_t action, int32_t actionButton, int32_t flags,
-            int32_t metaState, int32_t buttonState,
+            int32_t metaState, int32_t buttonState, MotionClassification classification,
             int32_t edgeFlags, uint32_t deviceTimestamp, uint32_t pointerCount,
             const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
             float xPrecision, float yPrecision, nsecs_t downTime,
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 704c13a..7553a68 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -63,7 +63,7 @@
     virtual void notifyInputChannelBroken(const sp<IBinder>&) {
     }
 
-    virtual void notifyFocusChanged(const sp<IBinder>&) {
+    virtual void notifyFocusChanged(const sp<IBinder>&, const sp<IBinder>&) {
     }
 
     virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) {
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 4e4d7dd..4eafeac 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -176,7 +176,7 @@
 
     if (!blackOutLayer) {
         // TODO: we could be more subtle with isFixedSize()
-        const bool useFiltering = needsFiltering(renderArea) || isFixedSize();
+        const bool useFiltering = needsFiltering() || renderArea.needsFiltering() || isFixedSize();
 
         // Query the texture matrix given our current filtering mode.
         float textureMatrix[16];
@@ -597,8 +597,11 @@
     return true;
 }
 
-bool BufferLayer::needsFiltering(const RenderArea& renderArea) const {
-    return mNeedsFiltering || renderArea.needsFiltering();
+bool BufferLayer::needsFiltering() const {
+    const auto displayFrame = getBE().compositionInfo.hwc.displayFrame;
+    const auto sourceCrop = getBE().compositionInfo.hwc.sourceCrop;
+    return mNeedsFiltering || sourceCrop.getHeight() != displayFrame.getHeight() ||
+            sourceCrop.getWidth() != displayFrame.getWidth();
 }
 
 void BufferLayer::drawWithOpenGL(const RenderArea& renderArea, bool useIdentityTransform) const {
@@ -623,7 +626,6 @@
      */
     const Rect bounds{computeBounds()}; // Rounds from FloatRect
 
-    ui::Transform t = getTransform();
     Rect win = bounds;
     const int bufferWidth = getBufferSize(s).getWidth();
     const int bufferHeight = getBufferSize(s).getHeight();
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index be16cf5..e3b7f2f 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -167,9 +167,11 @@
     // from GLES
     const uint32_t mTextureName;
 
+    bool mRefreshPending{false};
+
 private:
-    // needsLinearFiltering - true if this surface's state requires filtering
-    bool needsFiltering(const RenderArea& renderArea) const;
+    // Returns true if this layer requires filtering
+    bool needsFiltering() const;
 
     // drawing
     void drawWithOpenGL(const RenderArea& renderArea, bool useIdentityTransform) const;
@@ -184,8 +186,6 @@
     // The texture used to draw the layer in GLES composition mode
     mutable renderengine::Texture mTexture;
 
-    bool mRefreshPending{false};
-
     Rect getBufferSize(const State& s) const override;
 };
 
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 5a61122..42021d1 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -352,6 +352,14 @@
 // Interface implementation for BufferLayerConsumer::ContentsChangedListener
 // -----------------------------------------------------------------------
 
+void BufferQueueLayer::fakeVsync() {
+    mRefreshPending = false;
+    bool ignored = false;
+    latchBuffer(ignored, systemTime(), Fence::NO_FENCE);
+    usleep(16000);
+    releasePendingBuffer(systemTime());
+}
+
 void BufferQueueLayer::onFrameAvailable(const BufferItem& item) {
     // Add this buffer from our internal queue tracker
     { // Autolock scope
@@ -390,10 +398,7 @@
     // If this layer is orphaned, then we run a fake vsync pulse so that
     // dequeueBuffer doesn't block indefinitely.
     if (isRemovedFromCurrentState()) {
-        bool ignored = false;
-        latchBuffer(ignored, systemTime(), Fence::NO_FENCE);
-        usleep(16000);
-        releasePendingBuffer(systemTime());
+        fakeVsync();
     } else {
         mFlinger->signalLayerUpdate();
     }
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index ae0b705..d7c3f6a 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -137,6 +137,8 @@
     // thread-safe
     std::atomic<int32_t> mQueuedFrames{0};
     std::atomic<bool> mSidebandStreamChanged{false};
+
+    void fakeVsync();
 };
 
 } // namespace android