Move core data structure of DetachedBuffer into BufferNode

1/ Supports mutiple DetachedBuffer(s) to be created from a single
BufferNode.
2/ Separate core data structure and logic (i.e. BufferNode) out of the
IPC layer (i.e. DetachedBufferChannel).
3/ DetachedBufferChannel will be renamed to BufferChannel in future
and becomes the universal backend of GraphicBuffer. Thus we are naming
the new class BufferNode instead of DetachedBufferNode.
4/ Move BufferHubDefs out of bufferhub_rpc.h, as BufferHubDefs is not
directly related to the PDX IPCm echanism.

Bug: 112011098
Bug: 112012812
Bug: 111976433
Bug: 70046255
Test: buffer_hub-test
Change-Id: Ieba19329a0e823c78f21611462dedacdad3aab85
diff --git a/libs/vr/libbufferhub/buffer_hub-test.cpp b/libs/vr/libbufferhub/buffer_hub-test.cpp
index e247398..2a962b5 100644
--- a/libs/vr/libbufferhub/buffer_hub-test.cpp
+++ b/libs/vr/libbufferhub/buffer_hub-test.cpp
@@ -945,3 +945,35 @@
   EXPECT_EQ(b1_id, p2_id);
   EXPECT_TRUE(IsBufferGained(p2->buffer_state()));
 }
+
+TEST_F(LibBufferHubTest, TestDuplicateDetachedBuffer) {
+  auto b1 = DetachedBuffer::Create(kWidth, kHeight, kLayerCount, kFormat,
+                                   kUsage, kUserMetadataSize);
+  int b1_id = b1->id();
+  EXPECT_TRUE(b1->IsValid());
+
+  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<DetachedBuffer> b2 = DetachedBuffer::Import(std::move(h2));
+  EXPECT_FALSE(h2.valid());
+  ASSERT_TRUE(b2 != nullptr);
+  int b2_id = b2->id();
+
+  // The duplicated buffer should inherit the same buffer id.
+  EXPECT_EQ(b1_id, b2_id);
+
+  // Promote the detached buffer should fail as b1 is no longer the exclusive
+  // owner of the buffer..
+  status_or_handle = b1->Promote();
+  EXPECT_FALSE(status_or_handle.ok());
+  EXPECT_EQ(status_or_handle.error(), EINVAL);
+}
diff --git a/libs/vr/libbufferhub/detached_buffer.cpp b/libs/vr/libbufferhub/detached_buffer.cpp
index 6fae16d..60f11e2 100644
--- a/libs/vr/libbufferhub/detached_buffer.cpp
+++ b/libs/vr/libbufferhub/detached_buffer.cpp
@@ -104,6 +104,20 @@
   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;
+}
+
 sp<GraphicBuffer> DetachedBuffer::TakeGraphicBuffer() {
   if (!client_.IsValid() || !buffer_.buffer()) {
     ALOGE("DetachedBuffer::TakeGraphicBuffer: Invalid buffer.");
diff --git a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h
new file mode 100644
index 0000000..8b2bf91
--- /dev/null
+++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h
@@ -0,0 +1,89 @@
+#ifndef ANDROID_DVR_BUFFER_HUB_DEFS_H_
+#define ANDROID_DVR_BUFFER_HUB_DEFS_H_
+
+#include <dvr/dvr_api.h>
+#include <hardware/gralloc.h>
+
+#include <atomic>
+
+namespace android {
+namespace dvr {
+
+namespace BufferHubDefs {
+
+static constexpr uint32_t kMetadataFormat = HAL_PIXEL_FORMAT_BLOB;
+static constexpr uint32_t kMetadataUsage =
+    GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN;
+
+// Single producuer multiple (up to 63) consumers ownership signal.
+// 64-bit atomic unsigned int.
+//
+// MSB           LSB
+//  |             |
+//  v             v
+// [P|C62|...|C1|C0]
+// Gain'ed state:     [0|..|0|0] -> Exclusively Writable.
+// Post'ed state:     [1|..|0|0]
+// Acquired'ed state: [1|..|X|X] -> At least one bit is set in lower 63 bits
+// Released'ed state: [0|..|X|X] -> At least one bit is set in lower 63 bits
+static constexpr uint64_t kProducerStateBit = 1ULL << 63;
+static constexpr uint64_t kConsumerStateMask = (1ULL << 63) - 1;
+
+static inline void ModifyBufferState(std::atomic<uint64_t>* buffer_state,
+                                     uint64_t clear_mask, uint64_t set_mask) {
+  uint64_t old_state;
+  uint64_t new_state;
+  do {
+    old_state = buffer_state->load();
+    new_state = (old_state & ~clear_mask) | set_mask;
+  } while (!buffer_state->compare_exchange_weak(old_state, new_state));
+}
+
+static inline bool IsBufferGained(uint64_t state) { return state == 0; }
+
+static inline bool IsBufferPosted(uint64_t state,
+                                  uint64_t consumer_bit = kConsumerStateMask) {
+  return (state & kProducerStateBit) && !(state & consumer_bit);
+}
+
+static inline bool IsBufferAcquired(uint64_t state) {
+  return (state & kProducerStateBit) && (state & kConsumerStateMask);
+}
+
+static inline bool IsBufferReleased(uint64_t state) {
+  return !(state & kProducerStateBit) && (state & kConsumerStateMask);
+}
+
+static inline uint64_t FindNextClearedBit(uint64_t bits) {
+  return ~bits - (~bits & (~bits - 1));
+}
+
+static inline uint64_t FindFirstClearedBit() {
+  return FindNextClearedBit(kProducerStateBit);
+}
+
+struct __attribute__((packed, aligned(8))) MetadataHeader {
+  // Internal data format, which can be updated as long as the size, padding and
+  // field alignment of the struct is consistent within the same ABI. As this
+  // part is subject for future updates, it's not stable cross Android version,
+  // so don't have it visible from outside of the Android platform (include Apps
+  // and vendor HAL).
+  std::atomic<uint64_t> buffer_state;
+  std::atomic<uint64_t> fence_state;
+  uint64_t queue_index;
+
+  // Public data format, which should be updated with caution. See more details
+  // in dvr_api.h
+  DvrNativeBufferMetadata metadata;
+};
+
+static_assert(sizeof(MetadataHeader) == 128, "Unexpected MetadataHeader size");
+static constexpr size_t kMetadataHeaderSize = sizeof(MetadataHeader);
+
+}  // namespace BufferHubDefs
+
+}  // 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 088a235..e163216 100644
--- a/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
+++ b/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
@@ -1,11 +1,11 @@
 #ifndef ANDROID_DVR_BUFFERHUB_RPC_H_
 #define ANDROID_DVR_BUFFERHUB_RPC_H_
 
+#include "buffer_hub_defs.h"
+
 #include <cutils/native_handle.h>
-#include <sys/types.h>
 #include <ui/BufferQueueDefs.h>
 
-#include <dvr/dvr_api.h>
 #include <pdx/channel_handle.h>
 #include <pdx/file_handle.h>
 #include <pdx/rpc/remote_method.h>
@@ -15,71 +15,6 @@
 namespace android {
 namespace dvr {
 
-namespace BufferHubDefs {
-
-static constexpr uint32_t kMetadataFormat = HAL_PIXEL_FORMAT_BLOB;
-static constexpr uint32_t kMetadataUsage =
-    GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN;
-
-// Single producuer multiple (up to 63) consumers ownership signal.
-// 64-bit atomic unsigned int.
-//
-// MSB           LSB
-//  |             |
-//  v             v
-// [P|C62|...|C1|C0]
-// Gain'ed state:     [0|..|0|0] -> Exclusively Writable.
-// Post'ed state:     [1|..|0|0]
-// Acquired'ed state: [1|..|X|X] -> At least one bit is set in lower 63 bits
-// Released'ed state: [0|..|X|X] -> At least one bit is set in lower 63 bits
-static constexpr uint64_t kProducerStateBit = 1ULL << 63;
-static constexpr uint64_t kConsumerStateMask = (1ULL << 63) - 1;
-
-static inline void ModifyBufferState(std::atomic<uint64_t>* buffer_state,
-                                     uint64_t clear_mask, uint64_t set_mask) {
-  uint64_t old_state;
-  uint64_t new_state;
-  do {
-    old_state = buffer_state->load();
-    new_state = (old_state & ~clear_mask) | set_mask;
-  } while (!buffer_state->compare_exchange_weak(old_state, new_state));
-}
-
-static inline bool IsBufferGained(uint64_t state) { return state == 0; }
-
-static inline bool IsBufferPosted(uint64_t state,
-                                  uint64_t consumer_bit = kConsumerStateMask) {
-  return (state & kProducerStateBit) && !(state & consumer_bit);
-}
-
-static inline bool IsBufferAcquired(uint64_t state) {
-  return (state & kProducerStateBit) && (state & kConsumerStateMask);
-}
-
-static inline bool IsBufferReleased(uint64_t state) {
-  return !(state & kProducerStateBit) && (state & kConsumerStateMask);
-}
-
-struct __attribute__((packed, aligned(8))) MetadataHeader {
-  // Internal data format, which can be updated as long as the size, padding and
-  // field alignment of the struct is consistent within the same ABI. As this
-  // part is subject for future updates, it's not stable cross Android version,
-  // so don't have it visible from outside of the Android platform (include Apps
-  // and vendor HAL).
-  std::atomic<uint64_t> buffer_state;
-  std::atomic<uint64_t> fence_state;
-  uint64_t queue_index;
-
-  // Public data format, which should be updated with caution. See more details
-  // in dvr_api.h
-  DvrNativeBufferMetadata metadata;
-};
-
-static_assert(sizeof(MetadataHeader) == 128, "Unexpected MetadataHeader size");
-static constexpr size_t kMetadataHeaderSize = sizeof(MetadataHeader);
-
-}  // namespace BufferHubDefs
-
 template <typename FileHandleType>
 class NativeBufferHandle {
  public:
@@ -450,6 +385,7 @@
     kOpCreate = kOpDetachedBufferBase,
     kOpImport,
     kOpPromote,
+    kOpDuplicate,
   };
 
  public:
@@ -459,8 +395,9 @@
                          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, Promote);
+  PDX_REMOTE_API(API, Create, Import, Promote, Duplicate);
 };
 
 }  // namespace dvr
diff --git a/libs/vr/libbufferhub/include/private/dvr/detached_buffer.h b/libs/vr/libbufferhub/include/private/dvr/detached_buffer.h
index 6d0b502..376b53e 100644
--- a/libs/vr/libbufferhub/include/private/dvr/detached_buffer.h
+++ b/libs/vr/libbufferhub/include/private/dvr/detached_buffer.h
@@ -57,6 +57,9 @@
   // 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();
+
   // Takes the underlying graphic buffer out of this DetachedBuffer. This call
   // immediately invalidates this DetachedBuffer object and transfers the
   // underlying pdx::LocalChannelHandle into the GraphicBuffer.
diff --git a/services/vr/bufferhubd/Android.bp b/services/vr/bufferhubd/Android.bp
index 6122846..499a8f6 100644
--- a/services/vr/bufferhubd/Android.bp
+++ b/services/vr/bufferhubd/Android.bp
@@ -13,11 +13,12 @@
 // limitations under the License.
 
 sourceFiles = [
+    "buffer_channel.cpp",
     "buffer_hub.cpp",
+    "buffer_node.cpp",
     "bufferhubd.cpp",
     "consumer_channel.cpp",
     "producer_channel.cpp",
-    "detached_buffer_channel.cpp",
     "consumer_queue_channel.cpp",
     "producer_queue_channel.cpp",
 ]
diff --git a/services/vr/bufferhubd/buffer_channel.cpp b/services/vr/bufferhubd/buffer_channel.cpp
new file mode 100644
index 0000000..2150d62
--- /dev/null
+++ b/services/vr/bufferhubd/buffer_channel.cpp
@@ -0,0 +1,206 @@
+#include "buffer_channel.h"
+#include "producer_channel.h"
+
+using android::pdx::BorrowedHandle;
+using android::pdx::ErrorStatus;
+using android::pdx::Message;
+using android::pdx::RemoteChannelHandle;
+using android::pdx::Status;
+using android::pdx::rpc::DispatchRemoteMethod;
+
+namespace android {
+namespace dvr {
+
+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_state_bit_(BufferHubDefs::FindFirstClearedBit()) {
+  buffer_node_->set_buffer_state_bit(buffer_state_bit_);
+}
+
+BufferChannel::BufferChannel(BufferHubService* service, int buffer_id,
+                             uint32_t width, uint32_t height,
+                             uint32_t layer_count, uint32_t format,
+                             uint64_t usage, size_t user_metadata_size)
+    : BufferHubChannel(service, buffer_id, buffer_id, kDetachedBufferType),
+      buffer_node_(std::make_shared<BufferNode>(
+          width, height, layer_count, format, usage, user_metadata_size)),
+      buffer_state_bit_(BufferHubDefs::FindFirstClearedBit()) {
+  buffer_node_->set_buffer_state_bit(buffer_state_bit_);
+}
+
+BufferChannel::BufferChannel(BufferHubService* service, int buffer_id,
+                             int channel_id,
+                             std::shared_ptr<BufferNode> buffer_node,
+                             uint64_t buffer_state_bit)
+    : BufferHubChannel(service, buffer_id, channel_id, kDetachedBufferType),
+      buffer_node_(buffer_node),
+      buffer_state_bit_(buffer_state_bit) {
+  buffer_node_->set_buffer_state_bit(buffer_state_bit_);
+}
+
+BufferChannel::~BufferChannel() {
+  ALOGD_IF(TRACE, "BufferChannel::~BufferChannel: channel_id=%d buffer_id=%d.",
+           channel_id(), buffer_id());
+  Hangup();
+}
+
+BufferHubChannel::BufferInfo BufferChannel::GetBufferInfo() const {
+  return BufferInfo(
+      buffer_id(), /*consumer_count=*/0, buffer_node_->buffer().width(),
+      buffer_node_->buffer().height(), buffer_node_->buffer().layer_count(),
+      buffer_node_->buffer().format(), buffer_node_->buffer().usage(),
+      /*pending_count=*/0, /*state=*/0, /*signaled_mask=*/0,
+      /*index=*/0);
+}
+
+void BufferChannel::HandleImpulse(Message& /*message*/) {
+  ATRACE_NAME("BufferChannel::HandleImpulse");
+}
+
+bool BufferChannel::HandleMessage(Message& message) {
+  ATRACE_NAME("BufferChannel::HandleMessage");
+  switch (message.GetOp()) {
+    case DetachedBufferRPC::Import::Opcode:
+      DispatchRemoteMethod<DetachedBufferRPC::Import>(
+          *this, &BufferChannel::OnImport, message);
+      return true;
+
+    case DetachedBufferRPC::Duplicate::Opcode:
+      DispatchRemoteMethod<DetachedBufferRPC::Duplicate>(
+          *this, &BufferChannel::OnDuplicate, message);
+      return true;
+
+    case DetachedBufferRPC::Promote::Opcode:
+      DispatchRemoteMethod<DetachedBufferRPC::Promote>(
+          *this, &BufferChannel::OnPromote, message);
+      return true;
+
+    default:
+      return false;
+  }
+}
+
+Status<BufferDescription<BorrowedHandle>> BufferChannel::OnImport(
+    Message& /*message*/) {
+  ATRACE_NAME("BufferChannel::OnImport");
+  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{}};
+}
+
+Status<RemoteChannelHandle> BufferChannel::OnDuplicate(
+    Message& message) {
+  ATRACE_NAME("BufferChannel::OnDuplicate");
+  ALOGD_IF(TRACE, "BufferChannel::OnDuplicate: buffer=%d.",
+           buffer_id());
+
+  int channel_id;
+  auto status = message.PushChannel(0, nullptr, &channel_id);
+  if (!status) {
+    ALOGE(
+        "BufferChannel::OnDuplicate: Failed to push buffer channel: %s",
+        status.GetErrorMessage().c_str());
+    return ErrorStatus(ENOMEM);
+  }
+
+  // Try find the next buffer state bit which has not been claimed by any
+  // other buffers yet.
+  uint64_t buffer_state_bit =
+      BufferHubDefs::FindNextClearedBit(buffer_node_->active_buffer_bit_mask() |
+                                        BufferHubDefs::kProducerStateBit);
+  if (buffer_state_bit == 0ULL) {
+    ALOGE(
+        "BufferChannel::OnDuplicate: reached the maximum mumber of channels "
+        "per buffer node: 63.");
+    return ErrorStatus(E2BIG);
+  }
+
+  auto channel =
+      std::shared_ptr<BufferChannel>(new BufferChannel(
+          service(), buffer_id(), channel_id, buffer_node_, buffer_state_bit));
+  if (!channel) {
+    ALOGE("BufferChannel::OnDuplicate: Invalid buffer.");
+    return ErrorStatus(EINVAL);
+  }
+
+  const auto channel_status =
+      service()->SetChannel(channel_id, std::move(channel));
+  if (!channel_status) {
+    // Technically, this should never fail, as we just pushed the channel. Note
+    // that LOG_FATAL will be stripped out in non-debug build.
+    LOG_FATAL(
+        "BufferChannel::OnDuplicate: Failed to set new buffer channel: %s.",
+        channel_status.GetErrorMessage().c_str());
+  }
+
+  return status;
+}
+
+Status<RemoteChannelHandle> BufferChannel::OnPromote(
+    Message& message) {
+  ATRACE_NAME("BufferChannel::OnPromote");
+  ALOGD_IF(TRACE, "BufferChannel::OnPromote: buffer_id=%d", buffer_id());
+
+  // Check whether this is the channel exclusive owner of the buffer_node_.
+  if (buffer_state_bit_ != buffer_node_->active_buffer_bit_mask()) {
+    ALOGE(
+        "BufferChannel::OnPromote: Cannot promote this BufferChannel as its "
+        "BufferNode is shared between multiple channels. This channel's  state "
+        "bit=0x%" PRIx64 ", acitve_buffer_bit_mask=0x%" PRIx64 ".",
+        buffer_state_bit_, buffer_node_->active_buffer_bit_mask());
+    return ErrorStatus(EINVAL);
+  }
+
+  // Note that the new ProducerChannel will have different channel_id, but
+  // inherits the buffer_id from the DetachedBuffer.
+  int channel_id;
+  auto status = message.PushChannel(0, nullptr, &channel_id);
+  if (!status) {
+    ALOGE(
+        "BufferChannel::OnPromote: Failed to push ProducerChannel: %s.",
+        status.GetErrorMessage().c_str());
+    return ErrorStatus(ENOMEM);
+  }
+
+  IonBuffer buffer = std::move(buffer_node_->buffer());
+  IonBuffer metadata_buffer = std::move(buffer_node_->metadata_buffer());
+  size_t user_metadata_size = buffer_node_->user_metadata_size();
+
+  std::unique_ptr<ProducerChannel> channel = ProducerChannel::Create(
+      service(), buffer_id(), channel_id, std::move(buffer),
+      std::move(metadata_buffer), user_metadata_size);
+  if (!channel) {
+    ALOGE(
+        "BufferChannel::OnPromote: Failed to create ProducerChannel from a "
+        "BufferChannel, buffer_id=%d.",
+        buffer_id());
+  }
+
+  const auto channel_status =
+      service()->SetChannel(channel_id, std::move(channel));
+  if (!channel_status) {
+    // Technically, this should never fail, as we just pushed the channel. Note
+    // that LOG_FATAL will be stripped out in non-debug build.
+    LOG_FATAL(
+        "BufferChannel::OnPromote: Failed to set new producer buffer channel: "
+        "%s.",
+        channel_status.GetErrorMessage().c_str());
+  }
+
+  return status;
+}
+
+}  // namespace dvr
+}  // namespace android
diff --git a/services/vr/bufferhubd/buffer_channel.h b/services/vr/bufferhubd/buffer_channel.h
new file mode 100644
index 0000000..ac99a73
--- /dev/null
+++ b/services/vr/bufferhubd/buffer_channel.h
@@ -0,0 +1,66 @@
+#ifndef ANDROID_DVR_BUFFERHUBD_BUFFER_CHANNEL_H_
+#define ANDROID_DVR_BUFFERHUBD_BUFFER_CHANNEL_H_
+
+#include "buffer_hub.h"
+#include "buffer_node.h"
+
+#include <pdx/channel_handle.h>
+#include <pdx/file_handle.h>
+
+namespace android {
+namespace dvr {
+
+class BufferChannel : public BufferHubChannel {
+ public:
+  ~BufferChannel() override;
+
+  template <typename... Args>
+  static std::unique_ptr<BufferChannel> Create(Args&&... args) {
+    auto buffer = std::unique_ptr<BufferChannel>(
+        new BufferChannel(std::forward<Args>(args)...));
+    return buffer->IsValid() ? std::move(buffer) : nullptr;
+  }
+
+  // Returns whether the object holds a valid graphic buffer.
+  bool IsValid() const {
+    return buffer_node_ != nullptr && buffer_node_->IsValid();
+  }
+
+  // Captures buffer info for use by BufferHubService::DumpState().
+  BufferInfo GetBufferInfo() const override;
+
+  bool HandleMessage(pdx::Message& message) override;
+  void HandleImpulse(pdx::Message& message) override;
+
+ 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);
+
+  // Allocates a new detached buffer.
+  BufferChannel(BufferHubService* service, int buffer_id, uint32_t width,
+                uint32_t height, uint32_t layer_count, uint32_t format,
+                uint64_t usage, size_t user_metadata_size);
+
+  // Creates a detached buffer from an existing BufferNode.
+  BufferChannel(BufferHubService* service, int buffer_id, int channel_id,
+                std::shared_ptr<BufferNode> buffer_node,
+                uint64_t buffer_state_bit);
+
+  pdx::Status<BufferDescription<pdx::BorrowedHandle>> OnImport(
+      pdx::Message& message);
+  pdx::Status<pdx::RemoteChannelHandle> OnDuplicate(pdx::Message& message);
+  pdx::Status<pdx::RemoteChannelHandle> OnPromote(pdx::Message& message);
+
+  // The concrete implementation of the Buffer object.
+  std::shared_ptr<BufferNode> buffer_node_;
+
+  // The state bit of this buffer. Must be one the lower 63 bits.
+  uint64_t buffer_state_bit_;
+};
+
+}  // namespace dvr
+}  // namespace android
+
+#endif  // ANDROID_DVR_BUFFERHUBD_BUFFER_CHANNEL_H_
diff --git a/services/vr/bufferhubd/buffer_hub.cpp b/services/vr/bufferhubd/buffer_hub.cpp
index e57c8ed..c0ee31b 100644
--- a/services/vr/bufferhubd/buffer_hub.cpp
+++ b/services/vr/bufferhubd/buffer_hub.cpp
@@ -13,8 +13,8 @@
 
 #include <pdx/default_transport/service_endpoint.h>
 #include <private/dvr/bufferhub_rpc.h>
+#include "buffer_channel.h"
 #include "consumer_channel.h"
-#include "detached_buffer_channel.h"
 #include "producer_channel.h"
 #include "producer_queue_channel.h"
 
@@ -267,7 +267,7 @@
       return {};
 
     case DetachedBufferRPC::Promote::Opcode:
-      // In addition to the message handler in the DetachedBufferChannel's
+      // In addition to the message handler in the BufferChannel's
       // HandleMessage method, we also need to invalid the channel. Note that
       // this has to be done after HandleMessage returns to make sure the IPC
       // request has went back to the client first.
@@ -332,9 +332,9 @@
     return ErrorStatus(EALREADY);
   }
 
-  std::unique_ptr<DetachedBufferChannel> channel =
-      DetachedBufferChannel::Create(this, buffer_id, width, height, layer_count,
-                                    format, usage, user_metadata_size);
+  std::unique_ptr<BufferChannel> channel =
+      BufferChannel::Create(this, buffer_id, width, height, layer_count, format,
+                            usage, user_metadata_size);
   if (!channel) {
     ALOGE(
         "BufferHubService::OnCreateDetachedBuffer: Failed to allocate buffer, "
diff --git a/services/vr/bufferhubd/buffer_node.cpp b/services/vr/bufferhubd/buffer_node.cpp
new file mode 100644
index 0000000..de22bba
--- /dev/null
+++ b/services/vr/bufferhubd/buffer_node.cpp
@@ -0,0 +1,53 @@
+#include "buffer_node.h"
+
+#include <private/dvr/buffer_hub_defs.h>
+
+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) {}
+
+// 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;
+  }
+
+  if (int ret = buffer_.Alloc(width, height, layer_count, format, usage)) {
+    ALOGE(
+        "DetachedBufferChannel::DetachedBufferChannel: Failed to allocate "
+        "buffer: %s",
+        strerror(-ret));
+    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;
+  }
+}
+
+}  // namespace dvr
+}  // namespace android
diff --git a/services/vr/bufferhubd/buffer_node.h b/services/vr/bufferhubd/buffer_node.h
new file mode 100644
index 0000000..4bcf4e3
--- /dev/null
+++ b/services/vr/bufferhubd/buffer_node.h
@@ -0,0 +1,55 @@
+#ifndef ANDROID_DVR_BUFFERHUBD_BUFFER_NODE_H_
+#define ANDROID_DVR_BUFFERHUBD_BUFFER_NODE_H_
+
+#include <private/dvr/ion_buffer.h>
+
+namespace android {
+namespace dvr {
+
+class BufferNode {
+ 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);
+
+  // 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();
+  }
+
+  size_t user_metadata_size() const { return 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.
+  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_; }
+
+ private:
+  // Gralloc buffer handles.
+  IonBuffer buffer_;
+  IonBuffer metadata_buffer_;
+
+  // Size of user requested metadata.
+  const size_t user_metadata_size_;
+
+  // 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.
+  uint64_t active_buffer_bit_mask_ = 0ULL;
+};
+
+}  // namespace dvr
+}  // namespace android
+
+#endif  // ANDROID_DVR_BUFFERHUBD_BUFFER_NODE_H_
diff --git a/services/vr/bufferhubd/detached_buffer_channel.cpp b/services/vr/bufferhubd/detached_buffer_channel.cpp
deleted file mode 100644
index 3061805..0000000
--- a/services/vr/bufferhubd/detached_buffer_channel.cpp
+++ /dev/null
@@ -1,160 +0,0 @@
-#include "detached_buffer_channel.h"
-#include "producer_channel.h"
-
-using android::pdx::BorrowedHandle;
-using android::pdx::ErrorStatus;
-using android::pdx::Message;
-using android::pdx::RemoteChannelHandle;
-using android::pdx::Status;
-using android::pdx::rpc::DispatchRemoteMethod;
-
-namespace android {
-namespace dvr {
-
-DetachedBufferChannel::DetachedBufferChannel(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_(std::move(buffer)),
-      metadata_buffer_(std::move(metadata_buffer)),
-      user_metadata_size_(user_metadata_size) {
-}
-
-DetachedBufferChannel::DetachedBufferChannel(BufferHubService* service,
-                                             int buffer_id, uint32_t width,
-                                             uint32_t height,
-                                             uint32_t layer_count,
-                                             uint32_t format, uint64_t usage,
-                                             size_t user_metadata_size)
-    : BufferHubChannel(service, buffer_id, buffer_id, kDetachedBufferType),
-      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;
-  }
-
-  if (int ret = buffer_.Alloc(width, height, layer_count, format, usage)) {
-    ALOGE(
-        "DetachedBufferChannel::DetachedBufferChannel: Failed to allocate "
-        "buffer: %s",
-        strerror(-ret));
-    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;
-  }
-}
-
-DetachedBufferChannel::~DetachedBufferChannel() {
-  ALOGD_IF(TRACE,
-           "DetachedBufferChannel::~DetachedBufferChannel: channel_id=%d "
-           "buffer_id=%d.",
-           channel_id(), buffer_id());
-  Hangup();
-}
-
-BufferHubChannel::BufferInfo DetachedBufferChannel::GetBufferInfo() const {
-  return BufferInfo(buffer_id(), /*consumer_count=*/0, buffer_.width(),
-                    buffer_.height(), buffer_.layer_count(), buffer_.format(),
-                    buffer_.usage(), /*pending_count=*/0, /*state=*/0,
-                    /*signaled_mask=*/0, /*index=*/0);
-}
-
-void DetachedBufferChannel::HandleImpulse(Message& /*message*/) {
-  ATRACE_NAME("DetachedBufferChannel::HandleImpulse");
-}
-
-bool DetachedBufferChannel::HandleMessage(Message& message) {
-  ATRACE_NAME("DetachedBufferChannel::HandleMessage");
-  switch (message.GetOp()) {
-    case DetachedBufferRPC::Import::Opcode:
-      DispatchRemoteMethod<DetachedBufferRPC::Import>(
-          *this, &DetachedBufferChannel::OnImport, message);
-      return true;
-
-    case DetachedBufferRPC::Promote::Opcode:
-      DispatchRemoteMethod<DetachedBufferRPC::Promote>(
-          *this, &DetachedBufferChannel::OnPromote, message);
-      return true;
-
-    default:
-      return false;
-  }
-}
-
-Status<BufferDescription<BorrowedHandle>> DetachedBufferChannel::OnImport(
-    Message& /*message*/) {
-  ATRACE_NAME("DetachedBufferChannel::OnGetBuffer");
-  ALOGD_IF(TRACE, "DetachedBufferChannel::OnGetBuffer: buffer=%d.",
-           buffer_id());
-
-  return BufferDescription<BorrowedHandle>{buffer_,
-                                           metadata_buffer_,
-                                           buffer_id(),
-                                           channel_id(),
-                                           /*buffer_state_bit=*/0,
-                                           BorrowedHandle{},
-                                           BorrowedHandle{}};
-}
-
-Status<RemoteChannelHandle> DetachedBufferChannel::OnPromote(
-    Message& message) {
-  ATRACE_NAME("DetachedBufferChannel::OnPromote");
-  ALOGD_IF(TRACE, "DetachedBufferChannel::OnPromote: buffer_id=%d",
-           buffer_id());
-
-  // Note that the new ProducerChannel will have different channel_id, but
-  // inherits the buffer_id from the DetachedBuffer.
-  int channel_id;
-  auto status = message.PushChannel(0, nullptr, &channel_id);
-  if (!status) {
-    ALOGE(
-        "DetachedBufferChannel::OnPromote: Failed to push ProducerChannel: %s.",
-        status.GetErrorMessage().c_str());
-    return ErrorStatus(ENOMEM);
-  }
-
-  std::unique_ptr<ProducerChannel> channel = ProducerChannel::Create(
-      service(), buffer_id(), channel_id, std::move(buffer_),
-      std::move(metadata_buffer_), user_metadata_size_);
-  if (!channel) {
-    ALOGE(
-        "DetachedBufferChannel::OnPromote: Failed to create ProducerChannel "
-        "from a DetachedBufferChannel, buffer_id=%d.",
-        buffer_id());
-  }
-
-  const auto channel_status =
-      service()->SetChannel(channel_id, std::move(channel));
-  if (!channel_status) {
-    // Technically, this should never fail, as we just pushed the channel. Note
-    // that LOG_FATAL will be stripped out in non-debug build.
-    LOG_FATAL(
-        "DetachedBufferChannel::OnPromote: Failed to set new producer buffer "
-        "channel: %s.",
-        channel_status.GetErrorMessage().c_str());
-  }
-
-  return status;
-}
-
-}  // namespace dvr
-}  // namespace android
diff --git a/services/vr/bufferhubd/detached_buffer_channel.h b/services/vr/bufferhubd/detached_buffer_channel.h
deleted file mode 100644
index 8b6dab8..0000000
--- a/services/vr/bufferhubd/detached_buffer_channel.h
+++ /dev/null
@@ -1,63 +0,0 @@
-#ifndef ANDROID_DVR_BUFFERHUBD_DETACHED_BUFFER_CHANNEL_H_
-#define ANDROID_DVR_BUFFERHUBD_DETACHED_BUFFER_CHANNEL_H_
-
-#include "buffer_hub.h"
-
-#include <pdx/channel_handle.h>
-#include <pdx/file_handle.h>
-
-namespace android {
-namespace dvr {
-
-class DetachedBufferChannel : public BufferHubChannel {
- public:
-  ~DetachedBufferChannel() override;
-
-  template <typename... Args>
-  static std::unique_ptr<DetachedBufferChannel> Create(Args&&... args) {
-    auto buffer = std::unique_ptr<DetachedBufferChannel>(
-        new DetachedBufferChannel(std::forward<Args>(args)...));
-    return buffer->IsValid() ? std::move(buffer) : nullptr;
-  }
-
-  // Returns whether the object holds a valid graphic buffer.
-  bool IsValid() const {
-    return buffer_.IsValid() && metadata_buffer_.IsValid();
-  }
-
-  size_t user_metadata_size() const { return user_metadata_size_; }
-
-  // Captures buffer info for use by BufferHubService::DumpState().
-  BufferInfo GetBufferInfo() const override;
-
-  bool HandleMessage(pdx::Message& message) override;
-  void HandleImpulse(pdx::Message& message) override;
-
- private:
-  // Creates a detached buffer from existing IonBuffers.
-  DetachedBufferChannel(BufferHubService* service, int buffer_id,
-                        int channel_id, IonBuffer buffer,
-                        IonBuffer metadata_buffer, size_t user_metadata_size);
-
-  // Allocates a new detached buffer.
-  DetachedBufferChannel(BufferHubService* service, int buffer_id,
-                        uint32_t width, uint32_t height, uint32_t layer_count,
-                        uint32_t format, uint64_t usage,
-                        size_t user_metadata_size);
-
-  pdx::Status<BufferDescription<pdx::BorrowedHandle>> OnImport(
-      pdx::Message& message);
-  pdx::Status<pdx::RemoteChannelHandle> OnPromote(pdx::Message& message);
-
-  // Gralloc buffer handles.
-  IonBuffer buffer_;
-  IonBuffer metadata_buffer_;
-
-  // Size of user requested metadata.
-  const size_t user_metadata_size_;
-};
-
-}  // namespace dvr
-}  // namespace android
-
-#endif  // ANDROID_DVR_BUFFERHUBD_DETACHED_BUFFER_CHANNEL_H_
diff --git a/services/vr/bufferhubd/producer_channel.cpp b/services/vr/bufferhubd/producer_channel.cpp
index 97af660..19d48f2 100644
--- a/services/vr/bufferhubd/producer_channel.cpp
+++ b/services/vr/bufferhubd/producer_channel.cpp
@@ -12,8 +12,8 @@
 #include <thread>
 
 #include <private/dvr/bufferhub_rpc.h>
+#include "buffer_channel.h"
 #include "consumer_channel.h"
-#include "detached_buffer_channel.h"
 
 using android::pdx::BorrowedHandle;
 using android::pdx::ErrorStatus;
@@ -27,14 +27,6 @@
 namespace android {
 namespace dvr {
 
-namespace {
-
-static inline uint64_t FindNextClearedBit(uint64_t bits) {
-  return ~bits - (~bits & (~bits - 1));
-}
-
-}  // namespace
-
 ProducerChannel::ProducerChannel(BufferHubService* service, int buffer_id,
                                  int channel_id, IonBuffer buffer,
                                  IonBuffer metadata_buffer,
@@ -270,7 +262,7 @@
 
   // Try find the next consumer state bit which has not been claimed by any
   // consumer yet.
-  uint64_t consumer_state_bit = FindNextClearedBit(
+  uint64_t consumer_state_bit = BufferHubDefs::FindNextClearedBit(
       active_consumer_bit_mask_ | orphaned_consumer_bit_mask_ |
       BufferHubDefs::kProducerStateBit);
   if (consumer_state_bit == 0ULL) {
@@ -419,10 +411,9 @@
     return ErrorStatus(-ret);
   };
 
-  std::unique_ptr<DetachedBufferChannel> channel =
-      DetachedBufferChannel::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_),
+      std::move(metadata_buffer_), user_metadata_size_);
   if (!channel) {
     ALOGE("ProducerChannel::OnProducerDetach: Invalid buffer.");
     return ErrorStatus(EINVAL);