bufferhubd: Implement more DetachedBuffer logic
1/ Separate DetachedBuffer related logic into a dedicated subclass of
BufferHubRPC. This actually is the right thing to do as it utilizes
the PDX's client/service programming pattern better.
2/ Add IsValid() check for the DetachedBufferChannel object.
3/ Add BufferHubClient to handle general PDX operations.
4/ Add DetachedBuffer which composites a BufferHubClient.
5/ Fully functional logic of allocating a DetachedBuffer, converting it
to a BufferHub-backed GraphicBuffer, then converting it back to a
DetachedBuffer.
Bug: 38137191
Bug: 70046255
Bug: 70912269
Test: buffer_hub-test
Change-Id: I81bf9259cbbaeb29a6df2769363b5a03464e7864
diff --git a/services/vr/bufferhubd/buffer_hub.cpp b/services/vr/bufferhubd/buffer_hub.cpp
index e4e19c7..72bf6f2 100644
--- a/services/vr/bufferhubd/buffer_hub.cpp
+++ b/services/vr/bufferhubd/buffer_hub.cpp
@@ -6,6 +6,7 @@
#include <utils/Trace.h>
#include <iomanip>
+#include <memory>
#include <sstream>
#include <string>
#include <thread>
@@ -13,6 +14,7 @@
#include <pdx/default_transport/service_endpoint.h>
#include <private/dvr/bufferhub_rpc.h>
#include "consumer_channel.h"
+#include "detached_buffer_channel.h"
#include "producer_channel.h"
#include "producer_queue_channel.h"
@@ -245,6 +247,11 @@
*this, &BufferHubService::OnCreateBuffer, message);
return {};
+ case DetachedBufferRPC::Create::Opcode:
+ DispatchRemoteMethod<DetachedBufferRPC::Create>(
+ *this, &BufferHubService::OnCreateDetachedBuffer, message);
+ return {};
+
case BufferHubRPC::CreateProducerQueue::Opcode:
DispatchRemoteMethod<BufferHubRPC::CreateProducerQueue>(
*this, &BufferHubService::OnCreateProducerQueue, message);
@@ -295,6 +302,43 @@
}
}
+pdx::Status<void> BufferHubService::OnCreateDetachedBuffer(
+ pdx::Message& message, uint32_t width, uint32_t height,
+ uint32_t layer_count, uint32_t format, uint64_t usage,
+ size_t user_metadata_size) {
+ // Use the producer channel id as the global buffer id.
+ const int buffer_id = message.GetChannelId();
+ ALOGD_IF(TRACE,
+ "BufferHubService::OnCreateDetachedBuffer: buffer_id=%d width=%u "
+ "height=%u layer_count=%u format=%u usage=%" PRIx64
+ " user_metadata_size=%zu",
+ buffer_id, width, height, layer_count, format, usage,
+ user_metadata_size);
+
+ // See if this channel is already attached to a buffer.
+ if (const auto channel = message.GetChannel<BufferHubChannel>()) {
+ ALOGE(
+ "BufferHubService::OnCreateDetachedBuffer: Buffer already created: "
+ "buffer=%d",
+ buffer_id);
+ return ErrorStatus(EALREADY);
+ }
+
+ std::unique_ptr<DetachedBufferChannel> channel =
+ DetachedBufferChannel::Create(this, buffer_id, width, height, layer_count,
+ format, usage, user_metadata_size);
+ if (!channel) {
+ ALOGE(
+ "BufferHubService::OnCreateDetachedBuffer: Failed to allocate buffer, "
+ "buffer=%d.",
+ buffer_id);
+ return ErrorStatus(ENOMEM);
+ }
+
+ message.SetChannel(std::move(channel));
+ return {};
+}
+
Status<QueueInfo> BufferHubService::OnCreateProducerQueue(
pdx::Message& message, const ProducerQueueConfig& producer_config,
const UsagePolicy& usage_policy) {
diff --git a/services/vr/bufferhubd/buffer_hub.h b/services/vr/bufferhubd/buffer_hub.h
index e04967a..e47ffa3 100644
--- a/services/vr/bufferhubd/buffer_hub.h
+++ b/services/vr/bufferhubd/buffer_hub.h
@@ -147,6 +147,11 @@
pdx::Status<void> OnCreateBuffer(pdx::Message& message, uint32_t width,
uint32_t height, uint32_t format,
uint64_t usage, size_t meta_size_bytes);
+ pdx::Status<void> OnCreateDetachedBuffer(pdx::Message& message,
+ uint32_t width, uint32_t height,
+ uint32_t layer_count,
+ uint32_t format, uint64_t usage,
+ size_t user_metadata_size);
pdx::Status<QueueInfo> OnCreateProducerQueue(
pdx::Message& message, const ProducerQueueConfig& producer_config,
const UsagePolicy& usage_policy);
diff --git a/services/vr/bufferhubd/detached_buffer_channel.cpp b/services/vr/bufferhubd/detached_buffer_channel.cpp
index edb2111..4f4160a 100644
--- a/services/vr/bufferhubd/detached_buffer_channel.cpp
+++ b/services/vr/bufferhubd/detached_buffer_channel.cpp
@@ -1,5 +1,6 @@
#include "detached_buffer_channel.h"
+using android::pdx::BorrowedHandle;
using android::pdx::ErrorStatus;
using android::pdx::Message;
using android::pdx::RemoteChannelHandle;
@@ -17,7 +18,49 @@
: BufferHubChannel(service, buffer_id, channel_id, kDetachedBufferType),
buffer_(std::move(buffer)),
metadata_buffer_(std::move(metadata_buffer)),
- user_metadata_size_(user_metadata_size) {}
+ 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;
+ }
+}
BufferHubChannel::BufferInfo DetachedBufferChannel::GetBufferInfo() const {
return BufferInfo(buffer_id(), /*consumer_count=*/0, buffer_.width(),
@@ -33,8 +76,13 @@
bool DetachedBufferChannel::HandleMessage(Message& message) {
ATRACE_NAME("DetachedBufferChannel::HandleMessage");
switch (message.GetOp()) {
- case BufferHubRPC::DetachedBufferPromote::Opcode:
- DispatchRemoteMethod<BufferHubRPC::DetachedBufferPromote>(
+ 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;
@@ -43,6 +91,20 @@
}
}
+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(),
+ /*buffer_state_bit=*/0,
+ BorrowedHandle{},
+ BorrowedHandle{}};
+}
+
Status<RemoteChannelHandle> DetachedBufferChannel::OnPromote(
Message& /*message*/) {
ATRACE_NAME("DetachedBufferChannel::OnPromote");
diff --git a/services/vr/bufferhubd/detached_buffer_channel.h b/services/vr/bufferhubd/detached_buffer_channel.h
index 7ce4aed..079ba72 100644
--- a/services/vr/bufferhubd/detached_buffer_channel.h
+++ b/services/vr/bufferhubd/detached_buffer_channel.h
@@ -3,20 +3,25 @@
#include "buffer_hub.h"
-// #include <pdx/channel_handle.h>
-// #include <pdx/file_handle.h>
-// #include <pdx/rpc/buffer_wrapper.h>
-// #include <private/dvr/ion_buffer.h>
+#include <pdx/channel_handle.h>
+#include <pdx/file_handle.h>
namespace android {
namespace dvr {
class DetachedBufferChannel : public BufferHubChannel {
public:
- // Creates a detached buffer.
- DetachedBufferChannel(BufferHubService* service, int buffer_id,
- int channel_id, IonBuffer buffer,
- IonBuffer metadata_buffer, size_t user_metadata_size);
+ 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_; }
@@ -27,6 +32,19 @@
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.
diff --git a/services/vr/bufferhubd/producer_channel.cpp b/services/vr/bufferhubd/producer_channel.cpp
index c38c12b..a753168 100644
--- a/services/vr/bufferhubd/producer_channel.cpp
+++ b/services/vr/bufferhubd/producer_channel.cpp
@@ -377,11 +377,17 @@
return ErrorStatus(-ret);
};
- auto channel = std::make_shared<DetachedBufferChannel>(
- service(), buffer_id(), channel_id, std::move(buffer_),
- std::move(metadata_buffer_), user_metadata_size_);
+ std::unique_ptr<DetachedBufferChannel> channel =
+ DetachedBufferChannel::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);
+ }
- const auto channel_status = service()->SetChannel(channel_id, channel);
+ 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.