Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5cf47bcf authored by Fan Xu's avatar Fan Xu
Browse files

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
parent d5855a65
Loading
Loading
Loading
Loading
+11 −5
Original line number Diff line number Diff line
@@ -167,19 +167,26 @@ int BufferHubBuffer::initWithBufferTraits(const BufferTraits& bufferTraits) {
        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 @@ int BufferHubBuffer::initWithBufferTraits(const BufferTraits& bufferTraits) {
    }

    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 @@ int BufferHubBuffer::Release() {
}

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() {
+6 −0
Original line number Diff line number Diff line
@@ -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 @@ public:
        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 @@ private:
    // 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;
+6 −5
Original line number Diff line number Diff line
@@ -170,15 +170,16 @@ static constexpr size_t kMetadataHeaderSize = sizeof(MetadataHeader);
 *
 * 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
+27 −0
Original line number Diff line number Diff line
@@ -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 @@ TEST_F(BufferHubBufferTest, DuplicateAndImportBuffer) {
    // 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) {
+10 −8
Original line number Diff line number Diff line
@@ -65,9 +65,9 @@ Return<void> BufferHubService::allocateBuffer(const HardwareBufferDescription& d
    std::lock_guard<std::mutex> lock(mClientSetMutex);
    mClientSet.emplace(client);

    hidl_handle bufferInfo =
            buildBufferInfo(node->id(), node->AddNewActiveClientsBitToMask(),
                            node->user_metadata_size(), node->metadata().ashmem_fd());
    hidl_handle bufferInfo = buildBufferInfo(node->id(), node->AddNewActiveClientsBitToMask(),
                                             node->user_metadata_size(), node->eventFd().get(),
                                             node->metadata().ashmem_fd());
    BufferTraits bufferTraits = {/*bufferDesc=*/description,
                                 /*bufferHandle=*/hidl_handle(node->buffer_handle()),
                                 /*bufferInfo=*/bufferInfo};
@@ -156,7 +156,7 @@ Return<void> BufferHubService::importBuffer(const hidl_handle& tokenHandle,

    hidl_handle bufferInfo =
            buildBufferInfo(node->id(), clientStateMask, node->user_metadata_size(),
                            node->metadata().ashmem_fd());
                            node->eventFd().get(), node->metadata().ashmem_fd());
    BufferTraits bufferTraits = {/*bufferDesc=*/bufferDesc,
                                 /*bufferHandle=*/hidl_handle(node->buffer_handle()),
                                 /*bufferInfo=*/bufferInfo};
@@ -345,16 +345,18 @@ void BufferHubService::onClientClosed(const BufferClient* client) {
// Implementation of this function should be consistent with the definition of bufferInfo handle in
// ui/BufferHubDefs.h.
hidl_handle BufferHubService::buildBufferInfo(int bufferId, uint32_t clientBitMask,
                                              uint32_t userMetadataSize, const int metadataFd) {
                                              uint32_t userMetadataSize, const int eventFd,
                                              const int metadataFd) {
    native_handle_t* infoHandle = native_handle_create(BufferHubDefs::kBufferInfoNumFds,
                                                       BufferHubDefs::kBufferInfoNumInts);

    infoHandle->data[0] = dup(metadataFd);
    infoHandle->data[1] = bufferId;
    infoHandle->data[1] = dup(eventFd);
    infoHandle->data[2] = bufferId;
    // Use memcpy to convert to int without missing digit.
    // TOOD(b/121345852): use bit_cast to unpack bufferInfo when C++20 becomes available.
    memcpy(&infoHandle->data[2], &clientBitMask, sizeof(clientBitMask));
    memcpy(&infoHandle->data[3], &userMetadataSize, sizeof(userMetadataSize));
    memcpy(&infoHandle->data[3], &clientBitMask, sizeof(clientBitMask));
    memcpy(&infoHandle->data[4], &userMetadataSize, sizeof(userMetadataSize));

    hidl_handle bufferInfo;
    bufferInfo.setTo(infoHandle, /*shouldOwn=*/true);
Loading