Add BufferHubEventFd

The main use case of BufferHubEventFd is to signal buffer state change
cross multiple processes without explicit IPC.

Intended architecture: There will be one BufferHubEventFd per
BufferNode object and multiple clients of the same BufferNode should
share the same kernel object of the eventFd.

This CL focuses on proving eventfd and epollfd fit our needs. More
work is needed for BufferHubEventFd to make it binder-parcelable with
necessary constructors.

Bug: 68770788
Test: BufferHubBuffer_test
Change-Id: I7f7f5e5762fa81df61b649c306d209be2fd4236c
diff --git a/libs/ui/tests/BufferHubEventFd_test.cpp b/libs/ui/tests/BufferHubEventFd_test.cpp
new file mode 100644
index 0000000..8e61c68
--- /dev/null
+++ b/libs/ui/tests/BufferHubEventFd_test.cpp
@@ -0,0 +1,338 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "BufferHubEventFdTest"
+
+#include <sys/epoll.h>
+#include <sys/eventfd.h>
+
+#include <hidl/ServiceManagement.h>
+#include <hwbinder/IPCThreadState.h>
+#include <condition_variable>
+#include <mutex>
+#include <thread>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <ui/BufferHubEventFd.h>
+
+namespace android {
+
+namespace {
+
+const int kTimeout = 100;
+const std::chrono::milliseconds kTimeoutMs(kTimeout);
+
+using ::testing::Contains;
+using BufferHubEventFdTest = ::testing::Test;
+
+} // namespace
+
+TEST_F(BufferHubEventFdTest, EventFd_testSingleEpollFd) {
+    BufferHubEventFd eventFd;
+    ASSERT_TRUE(eventFd.isValid());
+
+    base::unique_fd epollFd(epoll_create(64));
+    epoll_event e = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 0}};
+
+    ASSERT_GE(epollFd.get(), 0);
+    ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd.get(), &e), 0);
+
+    std::array<epoll_event, 1> events;
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+
+    eventFd.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);
+}
+
+TEST_F(BufferHubEventFdTest, EventFd_testClear) {
+    BufferHubEventFd eventFd;
+    ASSERT_TRUE(eventFd.isValid());
+
+    base::unique_fd epollFd(epoll_create(64));
+    epoll_event e = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 0}};
+
+    ASSERT_GE(epollFd.get(), 0);
+    ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd.get(), &e), 0);
+
+    eventFd.signal();
+    eventFd.clear();
+
+    std::array<epoll_event, 1> events;
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+}
+
+TEST_F(BufferHubEventFdTest, EventFd_testDupEventFd) {
+    BufferHubEventFd eventFd;
+    ASSERT_TRUE(eventFd.isValid());
+
+    base::unique_fd epollFd(epoll_create(64));
+    epoll_event e = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 0}};
+
+    ASSERT_GE(epollFd.get(), 0);
+    ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd.get(), &e), 0);
+
+    // Technically, the dupliated eventFd and the original eventFd are pointing
+    // to the same kernel object. This test signals the duplicated eventFd but epolls the origianl
+    // eventFd.
+    base::unique_fd dupedEventFd(dup(eventFd.get()));
+    ASSERT_GE(dupedEventFd.get(), 0);
+
+    std::array<epoll_event, 1> events;
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+
+    eventfd_write(dupedEventFd.get(), 1);
+    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);
+
+    eventfd_write(dupedEventFd.get(), 1);
+
+    eventfd_t value;
+    eventfd_read(dupedEventFd.get(), &value);
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+}
+
+TEST_F(BufferHubEventFdTest, EventFd_testTwoEpollFds) {
+    BufferHubEventFd eventFd;
+    ASSERT_TRUE(eventFd.isValid());
+
+    base::unique_fd epollFd1(epoll_create(64));
+    base::unique_fd epollFd2(epoll_create(64));
+    epoll_event e = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 0}};
+
+    ASSERT_GE(epollFd1.get(), 0);
+    ASSERT_GE(epollFd2.get(), 0);
+
+    // Register the same eventFd to two EpollFds.
+    ASSERT_EQ(epoll_ctl(epollFd1.get(), EPOLL_CTL_ADD, eventFd.get(), &e), 0);
+    ASSERT_EQ(epoll_ctl(epollFd2.get(), EPOLL_CTL_ADD, eventFd.get(), &e), 0);
+
+    std::array<epoll_event, 1> events;
+    EXPECT_EQ(epoll_wait(epollFd1.get(), events.data(), events.size(), 0), 0);
+    EXPECT_EQ(epoll_wait(epollFd2.get(), events.data(), events.size(), 0), 0);
+
+    eventFd.signal();
+    EXPECT_EQ(epoll_wait(epollFd1.get(), events.data(), events.size(), 0), 1);
+    EXPECT_EQ(epoll_wait(epollFd2.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(epollFd1.get(), events.data(), events.size(), 0), 0);
+    EXPECT_EQ(epoll_wait(epollFd2.get(), events.data(), events.size(), 0), 0);
+
+    eventFd.signal();
+    EXPECT_EQ(epoll_wait(epollFd1.get(), events.data(), events.size(), 0), 1);
+
+    eventFd.clear();
+    EXPECT_EQ(epoll_wait(epollFd1.get(), events.data(), events.size(), 0), 0);
+    EXPECT_EQ(epoll_wait(epollFd2.get(), events.data(), events.size(), 0), 0);
+}
+
+TEST_F(BufferHubEventFdTest, EventFd_testTwoEventFds) {
+    BufferHubEventFd eventFd1;
+    BufferHubEventFd eventFd2;
+
+    ASSERT_TRUE(eventFd1.isValid());
+    ASSERT_TRUE(eventFd2.isValid());
+
+    base::unique_fd epollFd(epoll_create(64));
+    epoll_event e1 = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 1}};
+    epoll_event e2 = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 2}};
+
+    ASSERT_GE(epollFd.get(), 0);
+    ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd1.get(), &e1), 0);
+    ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd2.get(), &e2), 0);
+
+    std::array<epoll_event, 2> events;
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+
+    // Signal one by one.
+    eventFd1.signal();
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1);
+    EXPECT_EQ(events[0].data.u32, e1.data.u32);
+
+    eventFd2.signal();
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1);
+    EXPECT_EQ(events[0].data.u32, e2.data.u32);
+
+    // Signal both.
+    eventFd1.signal();
+    eventFd2.signal();
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 2);
+
+    uint32_t u32s[] = {events[0].data.u32, events[1].data.u32};
+    EXPECT_THAT(u32s, Contains(e1.data.u32));
+    EXPECT_THAT(u32s, Contains(e2.data.u32));
+
+    // 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);
+
+    eventFd1.signal();
+    eventFd2.signal();
+    eventFd2.clear();
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1);
+}
+
+TEST_F(BufferHubEventFdTest, EventFd_testPollingThreadWithTwoEventFds) {
+    BufferHubEventFd eventFd1;
+    BufferHubEventFd eventFd2;
+
+    ASSERT_TRUE(eventFd1.isValid());
+    ASSERT_TRUE(eventFd2.isValid());
+
+    base::unique_fd epollFd(epoll_create(64));
+    epoll_event e1 = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 1}};
+    epoll_event e2 = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 2}};
+
+    ASSERT_GE(epollFd.get(), 0);
+    ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd1.get(), &e1), 0);
+    ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd2.get(), &e2), 0);
+
+    int countEvent1 = 0;
+    int countEvent2 = 0;
+    std::atomic<bool> stop{false};
+    std::mutex mx;
+    std::condition_variable cv;
+
+    std::thread pollingThread([&] {
+        std::array<epoll_event, 2> events;
+        while (true) {
+            if (stop.load()) {
+                break;
+            }
+            int ret = epoll_wait(epollFd.get(), events.data(), events.size(), kTimeout);
+            ALOGE_IF(ret < 0 && errno != ETIMEDOUT, "Epoll failed.");
+
+            std::lock_guard<std::mutex> lock(mx);
+            for (int i = 0; i < ret; i++) {
+                if (events[i].data.u32 == e1.data.u32) {
+                    countEvent1++;
+                    cv.notify_one();
+                } else if (events[i].data.u32 == e2.data.u32) {
+                    countEvent2++;
+                    cv.notify_one();
+                }
+            }
+        }
+    });
+
+    {
+        std::unique_lock<std::mutex> lock(mx);
+
+        eventFd1.signal();
+        EXPECT_TRUE(cv.wait_for(lock, kTimeoutMs, [&] { return countEvent1 == 1; }));
+
+        eventFd1.signal();
+        EXPECT_TRUE(cv.wait_for(lock, kTimeoutMs, [&] { return countEvent1 == 2; }));
+
+        eventFd2.signal();
+        EXPECT_TRUE(cv.wait_for(lock, kTimeoutMs, [&] { return countEvent2 == 1; }));
+
+        eventFd1.clear();
+        eventFd2.clear();
+        EXPECT_EQ(countEvent1, 2);
+        EXPECT_EQ(countEvent2, 1);
+
+        eventFd1.signal();
+        EXPECT_TRUE(cv.wait_for(lock, kTimeoutMs, [&] { return countEvent1 == 3; }));
+
+        eventFd2.signal();
+        EXPECT_TRUE(cv.wait_for(lock, kTimeoutMs, [&] { return countEvent2 == 2; }));
+    }
+
+    stop.store(true);
+    pollingThread.join();
+}
+
+TEST_F(BufferHubEventFdTest, EventFd_testTwoPollingThreads) {
+    BufferHubEventFd eventFd;
+    ASSERT_TRUE(eventFd.isValid());
+
+    base::unique_fd epollFd1(epoll_create(64));
+    base::unique_fd epollFd2(epoll_create(64));
+    epoll_event e = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 0}};
+
+    ASSERT_GE(epollFd1.get(), 0);
+    ASSERT_GE(epollFd2.get(), 0);
+
+    // Register the same eventFd to two EpollFds.
+    ASSERT_EQ(epoll_ctl(epollFd1.get(), EPOLL_CTL_ADD, eventFd.get(), &e), 0);
+    ASSERT_EQ(epoll_ctl(epollFd2.get(), EPOLL_CTL_ADD, eventFd.get(), &e), 0);
+
+    int countEpoll1 = 0;
+    int countEpoll2 = 0;
+    std::atomic<bool> stop{false};
+    std::mutex mx;
+    std::condition_variable cv;
+
+    std::thread pollingThread1([&] {
+        std::array<epoll_event, 1> events;
+        while (!stop.load()) {
+            int ret = epoll_wait(epollFd1.get(), events.data(), events.size(), kTimeout);
+            ALOGE_IF(ret < 0 && errno != ETIMEDOUT, "Epoll failed.");
+
+            if (ret > 0) {
+                std::lock_guard<std::mutex> lock(mx);
+                countEpoll1++;
+                cv.notify_one();
+            }
+        }
+    });
+
+    std::thread pollingThread2([&] {
+        std::array<epoll_event, 1> events;
+        while (!stop.load()) {
+            int ret = epoll_wait(epollFd2.get(), events.data(), events.size(), kTimeout);
+            ALOGE_IF(ret < 0 && errno != ETIMEDOUT, "Epoll failed.");
+
+            if (ret > 0) {
+                std::lock_guard<std::mutex> lock(mx);
+                countEpoll2++;
+                cv.notify_one();
+            }
+        }
+    });
+
+    {
+        std::unique_lock<std::mutex> lock(mx);
+
+        eventFd.signal();
+        EXPECT_TRUE(cv.wait_for(lock, kTimeoutMs, [&] { return countEpoll1 == 1; }));
+        EXPECT_TRUE(cv.wait_for(lock, kTimeoutMs, [&] { return countEpoll2 == 1; }));
+
+        eventFd.signal();
+        EXPECT_TRUE(cv.wait_for(lock, kTimeoutMs, [&] { return countEpoll1 == 2; }));
+        EXPECT_TRUE(cv.wait_for(lock, kTimeoutMs, [&] { return countEpoll2 == 2; }));
+
+        eventFd.clear();
+        EXPECT_EQ(countEpoll1, 2);
+        EXPECT_EQ(countEpoll2, 2);
+
+        eventFd.signal();
+        EXPECT_TRUE(cv.wait_for(lock, kTimeoutMs, [&] { return countEpoll1 == 3; }));
+        EXPECT_TRUE(cv.wait_for(lock, kTimeoutMs, [&] { return countEpoll2 == 3; }));
+    }
+
+    stop.store(true);
+    pollingThread1.join();
+    pollingThread2.join();
+}
+
+} // namespace android