bufferhubd: Add DetachedBufferChannel
1/ Introduces four new BufferHub RPC operations.
2/ Implements the ProducerBufferDetach with test case.
3/ Also fixes a bug that Hangup signal wasn't propogated to the client
when bufferhubd closes a producer channel.
Bug: 38137191
Bug: 70046255
Bug: 70912269
Test: buffer_hub-test
Change-Id: Ia2ba0e95abd3c1b960670c505c6fdb9c9de3a6dd
diff --git a/libs/vr/libbufferhub/buffer_hub-test.cpp b/libs/vr/libbufferhub/buffer_hub-test.cpp
index b7a6099..3ce5c9f 100644
--- a/libs/vr/libbufferhub/buffer_hub-test.cpp
+++ b/libs/vr/libbufferhub/buffer_hub-test.cpp
@@ -25,7 +25,9 @@
using android::dvr::BufferHubDefs::IsBufferAcquired;
using android::dvr::BufferHubDefs::IsBufferReleased;
using android::dvr::BufferProducer;
+using android::pdx::LocalChannelHandle;
using android::pdx::LocalHandle;
+using android::pdx::Status;
const int kWidth = 640;
const int kHeight = 480;
@@ -717,3 +719,59 @@
// Producer should be able to gain no matter what.
EXPECT_EQ(0, p->GainAsync(&meta, &fence));
}
+
+TEST_F(LibBufferHubTest, TestDetachBufferFromProducer) {
+ std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+ kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
+ std::unique_ptr<BufferConsumer> c =
+ BufferConsumer::Import(p->CreateConsumer());
+ ASSERT_TRUE(p.get() != nullptr);
+ ASSERT_TRUE(c.get() != nullptr);
+
+ DvrNativeBufferMetadata metadata;
+ LocalHandle invalid_fence;
+
+ // Detach in posted state should fail.
+ EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence));
+ EXPECT_GT(RETRY_EINTR(c->Poll(kPollTimeoutMs)), 0);
+ auto s1 = p->Detach();
+ EXPECT_FALSE(s1);
+
+ // Detach in acquired state should fail.
+ EXPECT_EQ(0, c->AcquireAsync(&metadata, &invalid_fence));
+ s1 = p->Detach();
+ EXPECT_FALSE(s1);
+
+ // Detach in released state should fail.
+ EXPECT_EQ(0, c->ReleaseAsync(&metadata, invalid_fence));
+ EXPECT_GT(RETRY_EINTR(p->Poll(kPollTimeoutMs)), 0);
+ s1 = p->Detach();
+ EXPECT_FALSE(s1);
+
+ // Detach in gained state should succeed.
+ EXPECT_EQ(0, p->GainAsync(&metadata, &invalid_fence));
+ s1 = p->Detach();
+ EXPECT_TRUE(s1);
+
+ LocalChannelHandle detached_buffer = s1.take();
+ EXPECT_TRUE(detached_buffer.valid());
+
+ // Both producer and consumer should have hangup.
+ EXPECT_GT(RETRY_EINTR(p->Poll(kPollTimeoutMs)), 0);
+ auto s2 = p->GetEventMask(POLLHUP);
+ EXPECT_TRUE(s2);
+ EXPECT_EQ(s2.get(), POLLHUP);
+
+ EXPECT_GT(RETRY_EINTR(c->Poll(kPollTimeoutMs)), 0);
+ s2 = p->GetEventMask(POLLHUP);
+ EXPECT_TRUE(s2);
+ EXPECT_EQ(s2.get(), POLLHUP);
+
+ auto s3 = p->CreateConsumer();
+ EXPECT_FALSE(s3);
+ EXPECT_EQ(s3.error(), EOPNOTSUPP);
+
+ s3 = c->CreateConsumer();
+ EXPECT_FALSE(s3);
+ EXPECT_EQ(s3.error(), EOPNOTSUPP);
+}
diff --git a/libs/vr/libbufferhub/buffer_hub_client.cpp b/libs/vr/libbufferhub/buffer_hub_client.cpp
index 6db09a9..13971eb 100644
--- a/libs/vr/libbufferhub/buffer_hub_client.cpp
+++ b/libs/vr/libbufferhub/buffer_hub_client.cpp
@@ -608,5 +608,23 @@
: LocalChannelHandle{nullptr, -status.error()});
}
+Status<LocalChannelHandle> BufferProducer::Detach() {
+ uint64_t buffer_state = buffer_state_->load();
+ if (!BufferHubDefs::IsBufferGained(buffer_state)) {
+ // Can only detach a BufferProducer when it's in gained state.
+ ALOGW("BufferProducer::Detach: The buffer (id=%d, state=0x%" PRIx64
+ ") is not in gained state.",
+ id(), buffer_state);
+ return {};
+ }
+
+ Status<LocalChannelHandle> status =
+ InvokeRemoteMethod<BufferHubRPC::ProducerBufferDetach>();
+ ALOGE_IF(!status,
+ "BufferProducer::Detach: Failed to detach buffer (id=%d): %s.", id(),
+ status.GetErrorMessage().c_str());
+ return status;
+}
+
} // namespace dvr
} // namespace android
diff --git a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h
index c791250..32448a1 100644
--- a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h
+++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h
@@ -217,6 +217,14 @@
// succeeded, or a negative errno code if local error check fails.
int GainAsync(DvrNativeBufferMetadata* out_meta, LocalHandle* out_fence);
+ // Detaches a ProducerBuffer from an existing producer/consumer set. Can only
+ // be called when a producer buffer has exclusive access to the buffer (i.e.
+ // in the gain'ed state). On the successful return of the IPC call, a new
+ // LocalChannelHandle representing a detached buffer will be returned and all
+ // existing producer and consumer channels will be closed. Further IPCs
+ // towards those channels will return error.
+ Status<LocalChannelHandle> Detach();
+
private:
friend BASE;
diff --git a/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h b/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
index c70fffc..fabefd5 100644
--- a/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
+++ b/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
@@ -373,6 +373,10 @@
kOpConsumerAcquire,
kOpConsumerRelease,
kOpConsumerSetIgnore,
+ kOpProducerBufferDetach,
+ kOpConsumerBufferDetach,
+ kOpCreateDetachedBuffer,
+ kOpDetachedBufferPromote,
kOpCreateProducerQueue,
kOpCreateConsumerQueue,
kOpGetQueueInfo,
@@ -400,6 +404,28 @@
PDX_REMOTE_METHOD(ConsumerRelease, kOpConsumerRelease,
void(LocalFence release_fence));
PDX_REMOTE_METHOD(ConsumerSetIgnore, kOpConsumerSetIgnore, void(bool ignore));
+ PDX_REMOTE_METHOD(ProducerBufferDetach, kOpProducerBufferDetach,
+ LocalChannelHandle(Void));
+
+ // Detaches a ConsumerBuffer from an existing producer/consumer set. Can only
+ // be called when the consumer is the only consumer and it has exclusive
+ // access to the buffer (i.e. in the acquired'ed state). On the successful
+ // return of the IPC call, a new DetachedBufferChannel handle will be returned
+ // and all existing producer and consumer channels will be closed. Further
+ // IPCs towards those channels will return error.
+ PDX_REMOTE_METHOD(ConsumerBufferDetach, kOpConsumerBufferDetach,
+ LocalChannelHandle(Void));
+
+ // Creates a standalone DetachedBuffer not associated with any
+ // producer/consumer set.
+ PDX_REMOTE_METHOD(CreateDetachedBuffer, kOpCreateDetachedBuffer,
+ LocalChannelHandle(Void));
+
+ // Promotes a DetachedBuffer to become a ProducerBuffer. Once promoted the
+ // DetachedBuffer channel will be closed automatically on successful IPC
+ // return. Further IPCs towards this channel will return error.
+ PDX_REMOTE_METHOD(DetachedBufferPromote, kOpDetachedBufferPromote,
+ LocalChannelHandle(Void));
// Buffer Queue Methods.
PDX_REMOTE_METHOD(CreateProducerQueue, kOpCreateProducerQueue,