Implement DetachedBuffer::Promote

1/ This enables a BufferHub-backed DetachedBuffer to be promoted into
   the ProducerBuffer.
2/ Add DetachedBuffer::IsConnected in addition to
   DetachedBuffer::IsValid.
3/ Cleaned up some using pdx:: namespace statements.

Bug: 69982239
Bug: 69981968
Bug: 70046255
Test: buffer_hub-test
Change-Id: I6ee99507b190d142647455532cdce0c2c780b2b0
diff --git a/services/vr/bufferhubd/buffer_hub.cpp b/services/vr/bufferhubd/buffer_hub.cpp
index 72bf6f2..e57c8ed 100644
--- a/services/vr/bufferhubd/buffer_hub.cpp
+++ b/services/vr/bufferhubd/buffer_hub.cpp
@@ -266,6 +266,14 @@
       SetChannel(channel->channel_id(), nullptr);
       return {};
 
+    case DetachedBufferRPC::Promote::Opcode:
+      // In addition to the message handler in the DetachedBufferChannel'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.
+      SetChannel(channel->channel_id(), nullptr);
+      return {};
+
     default:
       return DefaultHandleMessage(message);
   }
diff --git a/services/vr/bufferhubd/detached_buffer_channel.cpp b/services/vr/bufferhubd/detached_buffer_channel.cpp
index 4f4160a..a5cf68d 100644
--- a/services/vr/bufferhubd/detached_buffer_channel.cpp
+++ b/services/vr/bufferhubd/detached_buffer_channel.cpp
@@ -1,4 +1,5 @@
 #include "detached_buffer_channel.h"
+#include "producer_channel.h"
 
 using android::pdx::BorrowedHandle;
 using android::pdx::ErrorStatus;
@@ -62,6 +63,14 @@
   }
 }
 
+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(),
@@ -106,13 +115,44 @@
 }
 
 Status<RemoteChannelHandle> DetachedBufferChannel::OnPromote(
-    Message& /*message*/) {
+    Message& message) {
   ATRACE_NAME("DetachedBufferChannel::OnPromote");
   ALOGD_IF(TRACE, "DetachedBufferChannel::OnPromote: buffer_id=%d",
            buffer_id());
 
-  // TODO(b/69982239): Implement the logic to promote a detached buffer.
-  return ErrorStatus(ENOSYS);
+  // 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
diff --git a/services/vr/bufferhubd/detached_buffer_channel.h b/services/vr/bufferhubd/detached_buffer_channel.h
index 079ba72..8b6dab8 100644
--- a/services/vr/bufferhubd/detached_buffer_channel.h
+++ b/services/vr/bufferhubd/detached_buffer_channel.h
@@ -11,6 +11,8 @@
 
 class DetachedBufferChannel : public BufferHubChannel {
  public:
+  ~DetachedBufferChannel() override;
+
   template <typename... Args>
   static std::unique_ptr<DetachedBufferChannel> Create(Args&&... args) {
     auto buffer = std::unique_ptr<DetachedBufferChannel>(
diff --git a/services/vr/bufferhubd/producer_channel.cpp b/services/vr/bufferhubd/producer_channel.cpp
index a753168..b6977aa 100644
--- a/services/vr/bufferhubd/producer_channel.cpp
+++ b/services/vr/bufferhubd/producer_channel.cpp
@@ -35,6 +35,30 @@
 
 }  // namespace
 
+ProducerChannel::ProducerChannel(BufferHubService* service, int buffer_id,
+                                 int channel_id, IonBuffer buffer,
+                                 IonBuffer metadata_buffer,
+                                 size_t user_metadata_size, int* error)
+    : BufferHubChannel(service, buffer_id, channel_id, kProducerType),
+      buffer_(std::move(buffer)),
+      metadata_buffer_(std::move(metadata_buffer)),
+      user_metadata_size_(user_metadata_size),
+      metadata_buf_size_(BufferHubDefs::kMetadataHeaderSize +
+                         user_metadata_size) {
+  if (!buffer_.IsValid()) {
+    ALOGE("ProducerChannel::ProducerChannel: Invalid buffer.");
+    *error = -EINVAL;
+    return;
+  }
+  if (!metadata_buffer_.IsValid()) {
+    ALOGE("ProducerChannel::ProducerChannel: Invalid metadata buffer.");
+    *error = -EINVAL;
+    return;
+  }
+
+  *error = InitializeBuffer();
+}
+
 ProducerChannel::ProducerChannel(BufferHubService* service, int channel_id,
                                  uint32_t width, uint32_t height,
                                  uint32_t layer_count, uint32_t format,
@@ -63,13 +87,16 @@
     return;
   }
 
+  *error = InitializeBuffer();
+}
+
+int ProducerChannel::InitializeBuffer() {
   void* metadata_ptr = nullptr;
   if (int ret = metadata_buffer_.Lock(BufferHubDefs::kMetadataUsage, /*x=*/0,
                                       /*y=*/0, metadata_buf_size_,
                                       /*height=*/1, &metadata_ptr)) {
     ALOGE("ProducerChannel::ProducerChannel: Failed to lock metadata.");
-    *error = -ret;
-    return;
+    return ret;
   }
   metadata_header_ =
       reinterpret_cast<BufferHubDefs::MetadataHeader*>(metadata_ptr);
@@ -85,15 +112,13 @@
   release_fence_fd_.Reset(epoll_create1(EPOLL_CLOEXEC));
   if (!acquire_fence_fd_ || !release_fence_fd_) {
     ALOGE("ProducerChannel::ProducerChannel: Failed to create shared fences.");
-    *error = -EIO;
-    return;
+    return -EIO;
   }
 
   dummy_fence_fd_.Reset(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
   if (!dummy_fence_fd_) {
     ALOGE("ProducerChannel::ProducerChannel: Failed to create dummy fences.");
-    *error = -EIO;
-    return;
+    return EIO;
   }
 
   epoll_event event;
@@ -105,12 +130,25 @@
         "ProducerChannel::ProducerChannel: Failed to modify the shared "
         "release fence to include the dummy fence: %s",
         strerror(errno));
-    *error = -EIO;
-    return;
+    return -EIO;
   }
 
   // Success.
-  *error = 0;
+  return 0;
+}
+
+std::unique_ptr<ProducerChannel> ProducerChannel::Create(
+    BufferHubService* service, int buffer_id, int channel_id, IonBuffer buffer,
+    IonBuffer metadata_buffer, size_t user_metadata_size) {
+  int error = 0;
+  std::unique_ptr<ProducerChannel> producer(new ProducerChannel(
+      service, buffer_id, channel_id, std::move(buffer),
+      std::move(metadata_buffer), user_metadata_size, &error));
+
+  if (error < 0)
+    return nullptr;
+  else
+    return producer;
 }
 
 Status<std::shared_ptr<ProducerChannel>> ProducerChannel::Create(
diff --git a/services/vr/bufferhubd/producer_channel.h b/services/vr/bufferhubd/producer_channel.h
index de9ff31..67fdf15 100644
--- a/services/vr/bufferhubd/producer_channel.h
+++ b/services/vr/bufferhubd/producer_channel.h
@@ -30,6 +30,12 @@
   template <typename T>
   using BufferWrapper = pdx::rpc::BufferWrapper<T>;
 
+  static std::unique_ptr<ProducerChannel> Create(BufferHubService* service,
+                                                 int buffer_id, int channel_id,
+                                                 IonBuffer buffer,
+                                                 IonBuffer metadata_buffer,
+                                                 size_t user_metadata_size);
+
   static pdx::Status<std::shared_ptr<ProducerChannel>> Create(
       BufferHubService* service, int channel_id, uint32_t width,
       uint32_t height, uint32_t layer_count, uint32_t format, uint64_t usage,
@@ -92,10 +98,14 @@
   pdx::LocalHandle release_fence_fd_;
   pdx::LocalHandle dummy_fence_fd_;
 
+  ProducerChannel(BufferHubService* service, int buffer_id, int channel_id,
+                  IonBuffer buffer, IonBuffer metadata_buffer,
+                  size_t user_metadata_size, int* error);
   ProducerChannel(BufferHubService* service, int channel, uint32_t width,
                   uint32_t height, uint32_t layer_count, uint32_t format,
                   uint64_t usage, size_t user_metadata_size, int* error);
 
+  int InitializeBuffer();
   pdx::Status<BufferDescription<BorrowedHandle>> OnGetBuffer(Message& message);
   pdx::Status<void> OnProducerPost(Message& message, LocalFence acquire_fence);
   pdx::Status<LocalFence> OnProducerGain(Message& message);