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/libs/vr/libbufferhub/buffer_hub-test.cpp b/libs/vr/libbufferhub/buffer_hub-test.cpp
index 660a200..2302828 100644
--- a/libs/vr/libbufferhub/buffer_hub-test.cpp
+++ b/libs/vr/libbufferhub/buffer_hub-test.cpp
@@ -2,8 +2,10 @@
#include <poll.h>
#include <private/dvr/buffer_hub_client.h>
#include <private/dvr/bufferhub_rpc.h>
+#include <private/dvr/detached_buffer.h>
#include <sys/epoll.h>
#include <sys/eventfd.h>
+#include <ui/DetachedBufferHandle.h>
#include <mutex>
#include <thread>
@@ -17,22 +19,28 @@
return result; \
})()
+using android::sp;
+using android::GraphicBuffer;
using android::dvr::BufferConsumer;
using android::dvr::BufferHubDefs::kConsumerStateMask;
+using android::dvr::BufferHubDefs::kMetadataHeaderSize;
using android::dvr::BufferHubDefs::kProducerStateBit;
using android::dvr::BufferHubDefs::IsBufferGained;
using android::dvr::BufferHubDefs::IsBufferPosted;
using android::dvr::BufferHubDefs::IsBufferAcquired;
using android::dvr::BufferHubDefs::IsBufferReleased;
using android::dvr::BufferProducer;
+using android::dvr::DetachedBuffer;
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;
const uint64_t kContext = 42;
const size_t kMaxConsumerCount = 63;
const int kPollTimeoutMs = 100;
@@ -730,6 +738,7 @@
DvrNativeBufferMetadata metadata;
LocalHandle invalid_fence;
+ int p_id = p->id();
// Detach in posted state should fail.
EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence));
@@ -753,8 +762,8 @@
s1 = p->Detach();
EXPECT_TRUE(s1);
- LocalChannelHandle detached_buffer = s1.take();
- EXPECT_TRUE(detached_buffer.valid());
+ LocalChannelHandle handle = s1.take();
+ EXPECT_TRUE(handle.valid());
// Both producer and consumer should have hangup.
EXPECT_GT(RETRY_EINTR(p->Poll(kPollTimeoutMs)), 0);
@@ -779,4 +788,80 @@
// ConsumerChannel::HandleMessage as the socket is still open but the producer
// is gone.
EXPECT_EQ(s3.error(), EPIPE);
+
+ // Detached buffer handle can be use to construct a new DetachedBuffer object.
+ auto d = DetachedBuffer::Import(std::move(handle));
+ EXPECT_FALSE(handle.valid());
+ EXPECT_TRUE(d->IsValid());
+
+ ASSERT_TRUE(d->buffer() != nullptr);
+ EXPECT_EQ(d->buffer()->initCheck(), 0);
+ EXPECT_EQ(d->id(), p_id);
+}
+
+TEST_F(LibBufferHubTest, TestCreateDetachedBufferFails) {
+ // Buffer Creation will fail: BLOB format requires height to be 1.
+ auto b1 = DetachedBuffer::Create(kWidth, /*height=2*/2, kLayerCount,
+ /*format=*/HAL_PIXEL_FORMAT_BLOB, kUsage,
+ kUserMetadataSize);
+
+ EXPECT_FALSE(b1->IsValid());
+ EXPECT_TRUE(b1->buffer() == nullptr);
+
+ // Buffer Creation will fail: user metadata size too large.
+ auto b2 = DetachedBuffer::Create(
+ kWidth, kHeight, kLayerCount, kFormat, kUsage,
+ /*user_metadata_size=*/std::numeric_limits<size_t>::max());
+
+ EXPECT_FALSE(b2->IsValid());
+ EXPECT_TRUE(b2->buffer() == nullptr);
+
+ // Buffer Creation will fail: user metadata size too large.
+ auto b3 = DetachedBuffer::Create(
+ kWidth, kHeight, kLayerCount, kFormat, kUsage,
+ /*user_metadata_size=*/std::numeric_limits<size_t>::max() -
+ kMetadataHeaderSize);
+
+ EXPECT_FALSE(b3->IsValid());
+ EXPECT_TRUE(b3->buffer() == nullptr);
+}
+
+TEST_F(LibBufferHubTest, TestCreateDetachedBuffer) {
+ auto b1 = DetachedBuffer::Create(kWidth, kHeight, kLayerCount, kFormat,
+ kUsage, kUserMetadataSize);
+ int b1_id = b1->id();
+
+ EXPECT_TRUE(b1->IsValid());
+ ASSERT_TRUE(b1->buffer() != nullptr);
+ EXPECT_NE(b1->id(), 0);
+ EXPECT_EQ(b1->buffer()->initCheck(), 0);
+ EXPECT_FALSE(b1->buffer()->isDetachedBuffer());
+
+ // Takes a standalone GraphicBuffer which still holds on an
+ // PDX::LocalChannelHandle towards BufferHub.
+ sp<GraphicBuffer> g1 = b1->TakeGraphicBuffer();
+ ASSERT_TRUE(g1 != nullptr);
+ EXPECT_TRUE(g1->isDetachedBuffer());
+
+ EXPECT_FALSE(b1->IsValid());
+ EXPECT_TRUE(b1->buffer() == nullptr);
+
+ sp<GraphicBuffer> g2 = b1->TakeGraphicBuffer();
+ ASSERT_TRUE(g2 == nullptr);
+
+ auto h1 = g1->takeDetachedBufferHandle();
+ ASSERT_TRUE(h1 != nullptr);
+ ASSERT_TRUE(h1->isValid());
+ EXPECT_FALSE(g1->isDetachedBuffer());
+
+ auto b2 = DetachedBuffer::Import(std::move(h1->handle()));
+ ASSERT_FALSE(h1->isValid());
+ EXPECT_TRUE(b2->IsValid());
+
+ ASSERT_TRUE(b2->buffer() != nullptr);
+ EXPECT_EQ(b2->buffer()->initCheck(), 0);
+
+ // The newly created DetachedBuffer should share the original buffer_id.
+ EXPECT_EQ(b2->id(), b1_id);
+ EXPECT_FALSE(b2->buffer()->isDetachedBuffer());
}