xref: /aosp_15_r20/frameworks/native/libs/gui/tests/BufferReleaseChannel_test.cpp (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
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