Add BufferHubEventFd to bufferhub system
Now BufferNode will create a new BufferHubEventFd instance during
allocation, BufferHubService will pass that fd to client side, and
BufferHubBuffer will now extract and import it.
User can now access the eventFd by a public function of BufferHubBuffer.
Update BufferHubBuffer_test to check if the two event fds are actually
linked to each other.
Test: VtsHalBufferHubV1_0TargetTest, BufferHubServer_test,
BufferHub_test
Fix: 68770788
Change-Id: I7f6e07d17615d2b45c0e7e086c481292c5798e97
diff --git a/libs/ui/BufferHubBuffer.cpp b/libs/ui/BufferHubBuffer.cpp
index 6310f29..9669135 100644
--- a/libs/ui/BufferHubBuffer.cpp
+++ b/libs/ui/BufferHubBuffer.cpp
@@ -167,19 +167,26 @@
return -EINVAL;
}
- int bufferId = bufferTraits.bufferInfo->data[1];
+ int bufferId = bufferTraits.bufferInfo->data[2];
if (bufferId < 0) {
ALOGE("%s: Received an invalid (negative) id!", __FUNCTION__);
return -EINVAL;
}
uint32_t clientBitMask;
- memcpy(&clientBitMask, &bufferTraits.bufferInfo->data[2], sizeof(clientBitMask));
+ memcpy(&clientBitMask, &bufferTraits.bufferInfo->data[3], sizeof(clientBitMask));
if (clientBitMask == 0U) {
ALOGE("%s: Received a invalid client state mask!", __FUNCTION__);
return -EINVAL;
}
+ const int eventFd = bufferTraits.bufferInfo->data[1];
+ if (eventFd < 0) {
+ ALOGE("%s: Received a invalid event fd!", __FUNCTION__);
+ return -EINVAL;
+ }
+ mEventFd = BufferHubEventFd(eventFd);
+
// Import the metadata. Dup since hidl_handle owns the fd
unique_fd ashmemFd(fcntl(bufferTraits.bufferInfo->data[0], F_DUPFD_CLOEXEC, 0));
mMetadata = BufferHubMetadata::Import(std::move(ashmemFd));
@@ -190,7 +197,7 @@
}
uint32_t userMetadataSize;
- memcpy(&userMetadataSize, &bufferTraits.bufferInfo->data[3], sizeof(userMetadataSize));
+ memcpy(&userMetadataSize, &bufferTraits.bufferInfo->data[4], sizeof(userMetadataSize));
if (mMetadata.user_metadata_size() != userMetadataSize) {
ALOGE("%s: user metadata size not match: expected %u, actual %zu.", __FUNCTION__,
userMetadataSize, mMetadata.user_metadata_size());
@@ -314,9 +321,8 @@
}
bool BufferHubBuffer::IsValid() const {
- // TODO(b/68770788): check eventFd once implemented
return mBufferHandle.getNativeHandle() != nullptr && mId >= 0 && mClientStateMask != 0U &&
- mMetadata.IsValid() && mBufferClient != nullptr;
+ mEventFd.get() >= 0 && mMetadata.IsValid() && mBufferClient != nullptr;
}
native_handle_t* BufferHubBuffer::Duplicate() {
diff --git a/libs/ui/include/ui/BufferHubBuffer.h b/libs/ui/include/ui/BufferHubBuffer.h
index c6a4a23..42d9320 100644
--- a/libs/ui/include/ui/BufferHubBuffer.h
+++ b/libs/ui/include/ui/BufferHubBuffer.h
@@ -21,6 +21,7 @@
#include <android/hardware_buffer.h>
#include <cutils/native_handle.h>
#include <ui/BufferHubDefs.h>
+#include <ui/BufferHubEventFd.h>
#include <ui/BufferHubMetadata.h>
namespace android {
@@ -55,6 +56,8 @@
return native_handle_clone(mBufferHandle.getNativeHandle());
}
+ const BufferHubEventFd& eventFd() const { return mEventFd; }
+
// Returns the current value of MetadataHeader::buffer_state.
uint32_t buffer_state() {
return mMetadata.metadata_header()->buffer_state.load(std::memory_order_acquire);
@@ -123,6 +126,9 @@
// Wraps the gralloc buffer handle of this buffer.
hardware::hidl_handle mBufferHandle;
+ // Event fd used for signalling buffer state changes. Shared by all clients of the same buffer.
+ BufferHubEventFd mEventFd;
+
// An ashmem-based metadata object. The same shared memory are mapped to the
// bufferhubd daemon and all buffer clients.
BufferHubMetadata mMetadata;
diff --git a/libs/ui/include/ui/BufferHubDefs.h b/libs/ui/include/ui/BufferHubDefs.h
index 069f0dc..43d900c 100644
--- a/libs/ui/include/ui/BufferHubDefs.h
+++ b/libs/ui/include/ui/BufferHubDefs.h
@@ -170,15 +170,16 @@
*
* It's definition should follow the following format:
* {
- * NumFds = 1,
+ * NumFds = 2,
* NumInts = 3,
* data[0] = Ashmem fd for BufferHubMetadata,
- * data[1] = buffer id,
- * data[2] = client state bit mask,
- * data[3] = user metadata size,
+ * data[1] = event fd,
+ * data[2] = buffer id,
+ * data[3] = client state bit mask,
+ * data[4] = user metadata size,
* }
*/
-static constexpr int kBufferInfoNumFds = 1;
+static constexpr int kBufferInfoNumFds = 2;
static constexpr int kBufferInfoNumInts = 3;
} // namespace BufferHubDefs
diff --git a/libs/ui/tests/BufferHubBuffer_test.cpp b/libs/ui/tests/BufferHubBuffer_test.cpp
index cd744cd..77ea19c 100644
--- a/libs/ui/tests/BufferHubBuffer_test.cpp
+++ b/libs/ui/tests/BufferHubBuffer_test.cpp
@@ -16,6 +16,8 @@
#define LOG_TAG "BufferHubBufferTest"
+#include <sys/epoll.h>
+
#include <android/hardware_buffer.h>
#include <cutils/native_handle.h>
#include <gmock/gmock.h>
@@ -23,6 +25,7 @@
#include <hidl/ServiceManagement.h>
#include <hwbinder/IPCThreadState.h>
#include <ui/BufferHubBuffer.h>
+#include <ui/BufferHubEventFd.h>
namespace android {
@@ -160,6 +163,30 @@
// Both buffer instances should be in released state currently.
EXPECT_TRUE(IsBufferReleased(b1->buffer_state()));
EXPECT_TRUE(IsBufferReleased(b2->buffer_state()));
+
+ // The event fd should behave like duped event fds.
+ const BufferHubEventFd& eventFd1 = b1->eventFd();
+ const BufferHubEventFd& eventFd2 = b2->eventFd();
+
+ base::unique_fd epollFd(epoll_create(64));
+ ASSERT_GE(epollFd.get(), 0);
+
+ // Add eventFd1 to epoll set, and signal eventFd2.
+ epoll_event e = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 0}};
+ ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd1.get(), &e), 0);
+
+ std::array<epoll_event, 1> events;
+ EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+
+ eventFd2.signal();
+ EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1);
+
+ // The epoll fd is edge triggered, so it only responds to the eventFd once.
+ EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+
+ eventFd2.signal();
+ eventFd2.clear();
+ EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
}
TEST_F(BufferHubBufferTest, ImportFreedBuffer) {