Loading libs/vr/libbufferhub/Android.bp +6 −0 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ sourceFiles = [ "buffer_hub_client.cpp", "buffer_hub_rpc.cpp", "detached_buffer.cpp", "ion_buffer.cpp", ] Loading Loading @@ -59,6 +60,11 @@ cc_library { vndk: { enabled: true, }, target: { vendor: { exclude_srcs: ["detached_buffer.cpp"], }, }, } cc_test { Loading libs/vr/libbufferhub/buffer_hub-test.cpp +87 −2 Original line number Diff line number Diff line Loading @@ -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> Loading @@ -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; Loading Loading @@ -730,6 +738,7 @@ TEST_F(LibBufferHubTest, TestDetachBufferFromProducer) { DvrNativeBufferMetadata metadata; LocalHandle invalid_fence; int p_id = p->id(); // Detach in posted state should fail. EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence)); Loading @@ -753,8 +762,8 @@ TEST_F(LibBufferHubTest, TestDetachBufferFromProducer) { 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); Loading @@ -779,4 +788,80 @@ TEST_F(LibBufferHubTest, TestDetachBufferFromProducer) { // 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()); } libs/vr/libbufferhub/buffer_hub_client.cpp +20 −0 Original line number Diff line number Diff line Loading @@ -15,10 +15,30 @@ using android::pdx::LocalChannelHandle; using android::pdx::LocalHandle; using android::pdx::Status; using android::pdx::default_transport::ClientChannel; using android::pdx::default_transport::ClientChannelFactory; namespace android { namespace dvr { BufferHubClient::BufferHubClient() : Client(ClientChannelFactory::Create(BufferHubRPC::kClientPath)) {} BufferHubClient::BufferHubClient(LocalChannelHandle channel_handle) : Client(ClientChannel::Create(std::move(channel_handle))) {} bool BufferHubClient::IsValid() const { return IsConnected() && GetChannelHandle().valid(); } LocalChannelHandle BufferHubClient::TakeChannelHandle() { if (IsConnected()) { return std::move(GetChannelHandle()); } else { return {}; } } BufferHubBuffer::BufferHubBuffer(LocalChannelHandle channel_handle) : Client{pdx::default_transport::ClientChannel::Create( std::move(channel_handle))}, Loading libs/vr/libbufferhub/detached_buffer.cpp 0 → 100644 +104 −0 Original line number Diff line number Diff line #include <private/dvr/detached_buffer.h> #include <pdx/file_handle.h> #include <ui/DetachedBufferHandle.h> using android::pdx::LocalHandle; namespace android { namespace dvr { DetachedBuffer::DetachedBuffer(uint32_t width, uint32_t height, uint32_t layer_count, uint32_t format, uint64_t usage, size_t user_metadata_size) { ATRACE_NAME("DetachedBuffer::DetachedBuffer"); ALOGD_IF(TRACE, "DetachedBuffer::DetachedBuffer: width=%u height=%u layer_count=%u, " "format=%u usage=%" PRIx64 " user_metadata_size=%zu", width, height, layer_count, format, usage, user_metadata_size); auto status = client_.InvokeRemoteMethod<DetachedBufferRPC::Create>( width, height, layer_count, format, usage, user_metadata_size); if (!status) { ALOGE( "DetachedBuffer::DetachedBuffer: Failed to create detached buffer: %s", status.GetErrorMessage().c_str()); client_.Close(-status.error()); } const int ret = ImportGraphicBuffer(); if (ret < 0) { ALOGE("DetachedBuffer::DetachedBuffer: Failed to import buffer: %s", strerror(-ret)); client_.Close(ret); } } DetachedBuffer::DetachedBuffer(LocalChannelHandle channel_handle) : client_(std::move(channel_handle)) { const int ret = ImportGraphicBuffer(); if (ret < 0) { ALOGE("DetachedBuffer::DetachedBuffer: Failed to import buffer: %s", strerror(-ret)); client_.Close(ret); } } int DetachedBuffer::ImportGraphicBuffer() { ATRACE_NAME("DetachedBuffer::DetachedBuffer"); auto status = client_.InvokeRemoteMethod<DetachedBufferRPC::Import>(); if (!status) { ALOGE("DetachedBuffer::DetachedBuffer: Failed to import GraphicBuffer: %s", status.GetErrorMessage().c_str()); return -status.error(); } BufferDescription<LocalHandle> buffer_desc = status.take(); if (buffer_desc.id() < 0) { ALOGE("DetachedBuffer::DetachedBuffer: Received an invalid id!"); return -EIO; } // Stash the buffer id to replace the value in id_. const int buffer_id = buffer_desc.id(); // Import the buffer. IonBuffer ion_buffer; ALOGD_IF(TRACE, "DetachedBuffer::DetachedBuffer: id=%d.", buffer_id); if (const int ret = buffer_desc.ImportBuffer(&ion_buffer)) { ALOGE("Failed to import GraphicBuffer, error=%d", ret); return ret; } // If all imports succeed, replace the previous buffer and id. id_ = buffer_id; buffer_ = std::move(ion_buffer); return 0; } std::unique_ptr<BufferProducer> DetachedBuffer::Promote() { ALOGE("DetachedBuffer::Promote: Not implemented."); return nullptr; } sp<GraphicBuffer> DetachedBuffer::TakeGraphicBuffer() { if (!client_.IsValid() || !buffer_.buffer()) { ALOGE("DetachedBuffer::TakeGraphicBuffer: Invalid buffer."); return nullptr; } // Technically this should never happen. LOG_FATAL_IF( buffer_.buffer()->isDetachedBuffer(), "DetachedBuffer::TakeGraphicBuffer: GraphicBuffer is already detached."); sp<GraphicBuffer> buffer = std::move(buffer_.buffer()); buffer->setDetachedBufferHandle( DetachedBufferHandle::Create(client_.TakeChannelHandle())); return buffer; } } // namespace dvr } // namespace android libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h +15 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,21 @@ namespace android { namespace dvr { class BufferHubClient : public pdx::Client { public: using LocalChannelHandle = pdx::LocalChannelHandle; BufferHubClient(); explicit BufferHubClient(LocalChannelHandle channel_handle); bool IsValid() const; LocalChannelHandle TakeChannelHandle(); using pdx::Client::Close; using pdx::Client::InvokeRemoteMethod; using pdx::Client::IsConnected; }; class BufferHubBuffer : public pdx::Client { public: using LocalHandle = pdx::LocalHandle; Loading Loading
libs/vr/libbufferhub/Android.bp +6 −0 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ sourceFiles = [ "buffer_hub_client.cpp", "buffer_hub_rpc.cpp", "detached_buffer.cpp", "ion_buffer.cpp", ] Loading Loading @@ -59,6 +60,11 @@ cc_library { vndk: { enabled: true, }, target: { vendor: { exclude_srcs: ["detached_buffer.cpp"], }, }, } cc_test { Loading
libs/vr/libbufferhub/buffer_hub-test.cpp +87 −2 Original line number Diff line number Diff line Loading @@ -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> Loading @@ -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; Loading Loading @@ -730,6 +738,7 @@ TEST_F(LibBufferHubTest, TestDetachBufferFromProducer) { DvrNativeBufferMetadata metadata; LocalHandle invalid_fence; int p_id = p->id(); // Detach in posted state should fail. EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence)); Loading @@ -753,8 +762,8 @@ TEST_F(LibBufferHubTest, TestDetachBufferFromProducer) { 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); Loading @@ -779,4 +788,80 @@ TEST_F(LibBufferHubTest, TestDetachBufferFromProducer) { // 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()); }
libs/vr/libbufferhub/buffer_hub_client.cpp +20 −0 Original line number Diff line number Diff line Loading @@ -15,10 +15,30 @@ using android::pdx::LocalChannelHandle; using android::pdx::LocalHandle; using android::pdx::Status; using android::pdx::default_transport::ClientChannel; using android::pdx::default_transport::ClientChannelFactory; namespace android { namespace dvr { BufferHubClient::BufferHubClient() : Client(ClientChannelFactory::Create(BufferHubRPC::kClientPath)) {} BufferHubClient::BufferHubClient(LocalChannelHandle channel_handle) : Client(ClientChannel::Create(std::move(channel_handle))) {} bool BufferHubClient::IsValid() const { return IsConnected() && GetChannelHandle().valid(); } LocalChannelHandle BufferHubClient::TakeChannelHandle() { if (IsConnected()) { return std::move(GetChannelHandle()); } else { return {}; } } BufferHubBuffer::BufferHubBuffer(LocalChannelHandle channel_handle) : Client{pdx::default_transport::ClientChannel::Create( std::move(channel_handle))}, Loading
libs/vr/libbufferhub/detached_buffer.cpp 0 → 100644 +104 −0 Original line number Diff line number Diff line #include <private/dvr/detached_buffer.h> #include <pdx/file_handle.h> #include <ui/DetachedBufferHandle.h> using android::pdx::LocalHandle; namespace android { namespace dvr { DetachedBuffer::DetachedBuffer(uint32_t width, uint32_t height, uint32_t layer_count, uint32_t format, uint64_t usage, size_t user_metadata_size) { ATRACE_NAME("DetachedBuffer::DetachedBuffer"); ALOGD_IF(TRACE, "DetachedBuffer::DetachedBuffer: width=%u height=%u layer_count=%u, " "format=%u usage=%" PRIx64 " user_metadata_size=%zu", width, height, layer_count, format, usage, user_metadata_size); auto status = client_.InvokeRemoteMethod<DetachedBufferRPC::Create>( width, height, layer_count, format, usage, user_metadata_size); if (!status) { ALOGE( "DetachedBuffer::DetachedBuffer: Failed to create detached buffer: %s", status.GetErrorMessage().c_str()); client_.Close(-status.error()); } const int ret = ImportGraphicBuffer(); if (ret < 0) { ALOGE("DetachedBuffer::DetachedBuffer: Failed to import buffer: %s", strerror(-ret)); client_.Close(ret); } } DetachedBuffer::DetachedBuffer(LocalChannelHandle channel_handle) : client_(std::move(channel_handle)) { const int ret = ImportGraphicBuffer(); if (ret < 0) { ALOGE("DetachedBuffer::DetachedBuffer: Failed to import buffer: %s", strerror(-ret)); client_.Close(ret); } } int DetachedBuffer::ImportGraphicBuffer() { ATRACE_NAME("DetachedBuffer::DetachedBuffer"); auto status = client_.InvokeRemoteMethod<DetachedBufferRPC::Import>(); if (!status) { ALOGE("DetachedBuffer::DetachedBuffer: Failed to import GraphicBuffer: %s", status.GetErrorMessage().c_str()); return -status.error(); } BufferDescription<LocalHandle> buffer_desc = status.take(); if (buffer_desc.id() < 0) { ALOGE("DetachedBuffer::DetachedBuffer: Received an invalid id!"); return -EIO; } // Stash the buffer id to replace the value in id_. const int buffer_id = buffer_desc.id(); // Import the buffer. IonBuffer ion_buffer; ALOGD_IF(TRACE, "DetachedBuffer::DetachedBuffer: id=%d.", buffer_id); if (const int ret = buffer_desc.ImportBuffer(&ion_buffer)) { ALOGE("Failed to import GraphicBuffer, error=%d", ret); return ret; } // If all imports succeed, replace the previous buffer and id. id_ = buffer_id; buffer_ = std::move(ion_buffer); return 0; } std::unique_ptr<BufferProducer> DetachedBuffer::Promote() { ALOGE("DetachedBuffer::Promote: Not implemented."); return nullptr; } sp<GraphicBuffer> DetachedBuffer::TakeGraphicBuffer() { if (!client_.IsValid() || !buffer_.buffer()) { ALOGE("DetachedBuffer::TakeGraphicBuffer: Invalid buffer."); return nullptr; } // Technically this should never happen. LOG_FATAL_IF( buffer_.buffer()->isDetachedBuffer(), "DetachedBuffer::TakeGraphicBuffer: GraphicBuffer is already detached."); sp<GraphicBuffer> buffer = std::move(buffer_.buffer()); buffer->setDetachedBufferHandle( DetachedBufferHandle::Create(client_.TakeChannelHandle())); return buffer; } } // namespace dvr } // namespace android
libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h +15 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,21 @@ namespace android { namespace dvr { class BufferHubClient : public pdx::Client { public: using LocalChannelHandle = pdx::LocalChannelHandle; BufferHubClient(); explicit BufferHubClient(LocalChannelHandle channel_handle); bool IsValid() const; LocalChannelHandle TakeChannelHandle(); using pdx::Client::Close; using pdx::Client::InvokeRemoteMethod; using pdx::Client::IsConnected; }; class BufferHubBuffer : public pdx::Client { public: using LocalHandle = pdx::LocalHandle; Loading