1 /*
2 * Copyright (C) 2024 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <string>
18 #include <vector>
19
20 #include <gtest/gtest.h>
21 #include <gui/BufferReleaseChannel.h>
22
23 using namespace std::string_literals;
24 using android::gui::BufferReleaseChannel;
25
26 namespace android {
27
28 namespace {
29
30 // Helper function to check if two file descriptors point to the same file.
is_same_file(int fd1,int fd2)31 bool is_same_file(int fd1, int fd2) {
32 struct stat stat1 {};
33 if (fstat(fd1, &stat1) != 0) {
34 return false;
35 }
36 struct stat stat2 {};
37 if (fstat(fd2, &stat2) != 0) {
38 return false;
39 }
40 return (stat1.st_dev == stat2.st_dev) && (stat1.st_ino == stat2.st_ino);
41 }
42
43 } // namespace
44
45 class BufferReleaseChannelTest : public testing::Test {
46 protected:
47 std::unique_ptr<BufferReleaseChannel::ConsumerEndpoint> mConsumer;
48 std::shared_ptr<BufferReleaseChannel::ProducerEndpoint> mProducer;
49
SetUp()50 void SetUp() override {
51 ASSERT_EQ(OK,
52 BufferReleaseChannel::open("BufferReleaseChannelTest"s, mConsumer, mProducer));
53 }
54 };
55
TEST_F(BufferReleaseChannelTest,MessageFlattenable)56 TEST_F(BufferReleaseChannelTest, MessageFlattenable) {
57 ReleaseCallbackId releaseCallbackId{1, 2};
58 sp<Fence> releaseFence = sp<Fence>::make(memfd_create("fake-fence-fd", 0));
59 uint32_t maxAcquiredBufferCount = 5;
60
61 std::vector<uint8_t> dataBuffer;
62 std::vector<int> fdBuffer;
63
64 // Verify that we can flatten a message
65 {
66 BufferReleaseChannel::Message message{releaseCallbackId, releaseFence,
67 maxAcquiredBufferCount};
68
69 dataBuffer.resize(message.getFlattenedSize());
70 void* dataPtr = dataBuffer.data();
71 size_t dataSize = dataBuffer.size();
72
73 fdBuffer.resize(message.getFdCount());
74 int* fdPtr = fdBuffer.data();
75 size_t fdSize = fdBuffer.size();
76
77 ASSERT_EQ(OK, message.flatten(dataPtr, dataSize, fdPtr, fdSize));
78
79 // Fence's unique_fd uses fdsan to check ownership of the file descriptor. Normally the file
80 // descriptor is passed through the Unix socket and duplicated (and sent to another process)
81 // so there's no problem with duplicate file descriptor ownership. For this unit test, we
82 // need to set up a duplicate file descriptor to avoid crashing due to duplicate ownership.
83 ASSERT_EQ(releaseFence->get(), fdBuffer[0]);
84 fdBuffer[0] = message.releaseFence->dup();
85 }
86
87 // Verify that we can unflatten a message
88 {
89 BufferReleaseChannel::Message message;
90
91 const void* dataPtr = dataBuffer.data();
92 size_t dataSize = dataBuffer.size();
93
94 const int* fdPtr = fdBuffer.data();
95 size_t fdSize = fdBuffer.size();
96
97 ASSERT_EQ(OK, message.unflatten(dataPtr, dataSize, fdPtr, fdSize));
98 ASSERT_EQ(releaseCallbackId, message.releaseCallbackId);
99 ASSERT_TRUE(is_same_file(releaseFence->get(), message.releaseFence->get()));
100 ASSERT_EQ(maxAcquiredBufferCount, message.maxAcquiredBufferCount);
101 }
102 }
103
104 // Verify that the BufferReleaseChannel consume returns WOULD_BLOCK when there's no message
105 // available.
TEST_F(BufferReleaseChannelTest,ConsumerEndpointIsNonBlocking)106 TEST_F(BufferReleaseChannelTest, ConsumerEndpointIsNonBlocking) {
107 ReleaseCallbackId releaseCallbackId;
108 sp<Fence> releaseFence;
109 uint32_t maxAcquiredBufferCount;
110 ASSERT_EQ(WOULD_BLOCK,
111 mConsumer->readReleaseFence(releaseCallbackId, releaseFence, maxAcquiredBufferCount));
112 }
113
114 // Verify that we can write a message to the BufferReleaseChannel producer and read that message
115 // using the BufferReleaseChannel consumer.
TEST_F(BufferReleaseChannelTest,ProduceAndConsume)116 TEST_F(BufferReleaseChannelTest, ProduceAndConsume) {
117 sp<Fence> fence = sp<Fence>::make(memfd_create("fake-fence-fd", 0));
118
119 for (uint64_t i = 0; i < 64; i++) {
120 ReleaseCallbackId producerId{i, i + 1};
121 uint32_t maxAcquiredBufferCount = i + 2;
122 ASSERT_EQ(OK, mProducer->writeReleaseFence(producerId, fence, maxAcquiredBufferCount));
123 }
124
125 for (uint64_t i = 0; i < 64; i++) {
126 ReleaseCallbackId expectedId{i, i + 1};
127 uint32_t expectedMaxAcquiredBufferCount = i + 2;
128
129 ReleaseCallbackId consumerId;
130 sp<Fence> consumerFence;
131 uint32_t maxAcquiredBufferCount;
132 ASSERT_EQ(OK,
133 mConsumer->readReleaseFence(consumerId, consumerFence, maxAcquiredBufferCount));
134
135 ASSERT_EQ(expectedId, consumerId);
136 ASSERT_TRUE(is_same_file(fence->get(), consumerFence->get()));
137 ASSERT_EQ(expectedMaxAcquiredBufferCount, maxAcquiredBufferCount);
138 }
139 }
140
141 // Verify that BufferReleaseChannel::ConsumerEndpoint's socket can't be written to.
TEST_F(BufferReleaseChannelTest,ConsumerSocketReadOnly)142 TEST_F(BufferReleaseChannelTest, ConsumerSocketReadOnly) {
143 uint64_t data = 0;
144 ASSERT_EQ(-1, write(mConsumer->getFd().get(), &data, sizeof(uint64_t)));
145 ASSERT_EQ(errno, EPIPE);
146 }
147
148 // Verify that BufferReleaseChannel::ProducerEndpoint's socket can't be read from.
TEST_F(BufferReleaseChannelTest,ProducerSocketWriteOnly)149 TEST_F(BufferReleaseChannelTest, ProducerSocketWriteOnly) {
150 ASSERT_EQ(0, read(mProducer->getFd().get(), nullptr, sizeof(uint64_t)));
151 }
152
153 } // namespace android