blob: e9c6ef3512980e24f51d59996fa594df482e6703 [file] [log] [blame]
Patrick Williamsf693bcf2024-08-02 09:55:23 -05001/*
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#define LOG_TAG "BufferReleaseChannel"
18
19#include <fcntl.h>
20#include <sys/socket.h>
21#include <sys/uio.h>
22
23#include <android-base/result.h>
24#include <android/binder_status.h>
25#include <binder/Parcel.h>
26#include <utils/Flattenable.h>
27
28#include <gui/BufferReleaseChannel.h>
29#include <private/gui/ParcelUtils.h>
30
31using android::base::Result;
32
33namespace android::gui {
34
35namespace {
36
37template <typename T>
38static void readAligned(const void*& buffer, size_t& size, T& value) {
39 size -= FlattenableUtils::align<alignof(T)>(buffer);
40 FlattenableUtils::read(buffer, size, value);
41}
42
43template <typename T>
44static void writeAligned(void*& buffer, size_t& size, T value) {
45 size -= FlattenableUtils::align<alignof(T)>(buffer);
46 FlattenableUtils::write(buffer, size, value);
47}
48
49template <typename T>
50static void addAligned(size_t& size, T /* value */) {
51 size = FlattenableUtils::align<sizeof(T)>(size);
52 size += sizeof(T);
53}
54
55template <typename T>
56static inline constexpr uint32_t low32(const T n) {
57 return static_cast<uint32_t>(static_cast<uint64_t>(n));
58}
59
60template <typename T>
61static inline constexpr uint32_t high32(const T n) {
62 return static_cast<uint32_t>(static_cast<uint64_t>(n) >> 32);
63}
64
65template <typename T>
66static inline constexpr T to64(const uint32_t lo, const uint32_t hi) {
67 return static_cast<T>(static_cast<uint64_t>(hi) << 32 | lo);
68}
69
70} // namespace
71
72size_t BufferReleaseChannel::Message::getPodSize() const {
73 size_t size = 0;
74 addAligned(size, low32(releaseCallbackId.bufferId));
75 addAligned(size, high32(releaseCallbackId.bufferId));
76 addAligned(size, low32(releaseCallbackId.framenumber));
77 addAligned(size, high32(releaseCallbackId.framenumber));
78 addAligned(size, maxAcquiredBufferCount);
79 return size;
80}
81
82size_t BufferReleaseChannel::Message::getFlattenedSize() const {
83 size_t size = releaseFence->getFlattenedSize();
84 size = FlattenableUtils::align<4>(size);
85 size += getPodSize();
86 return size;
87}
88
89status_t BufferReleaseChannel::Message::flatten(void*& buffer, size_t& size, int*& fds,
90 size_t& count) const {
91 if (status_t err = releaseFence->flatten(buffer, size, fds, count); err != OK) {
92 return err;
93 }
94 size -= FlattenableUtils::align<4>(buffer);
95
96 // Check we still have enough space
97 if (size < getPodSize()) {
98 return NO_MEMORY;
99 }
100
101 writeAligned(buffer, size, low32(releaseCallbackId.bufferId));
102 writeAligned(buffer, size, high32(releaseCallbackId.bufferId));
103 writeAligned(buffer, size, low32(releaseCallbackId.framenumber));
104 writeAligned(buffer, size, high32(releaseCallbackId.framenumber));
105 writeAligned(buffer, size, maxAcquiredBufferCount);
106 return OK;
107}
108
109status_t BufferReleaseChannel::Message::unflatten(void const*& buffer, size_t& size,
110 int const*& fds, size_t& count) {
111 releaseFence = new Fence();
112 if (status_t err = releaseFence->unflatten(buffer, size, fds, count); err != OK) {
113 return err;
114 }
115 size -= FlattenableUtils::align<4>(buffer);
116
117 // Check we still have enough space
118 if (size < getPodSize()) {
119 return OK;
120 }
121
122 uint32_t bufferIdLo = 0, bufferIdHi = 0;
123 uint32_t frameNumberLo = 0, frameNumberHi = 0;
124
125 readAligned(buffer, size, bufferIdLo);
126 readAligned(buffer, size, bufferIdHi);
127 releaseCallbackId.bufferId = to64<int64_t>(bufferIdLo, bufferIdHi);
128 readAligned(buffer, size, frameNumberLo);
129 readAligned(buffer, size, frameNumberHi);
130 releaseCallbackId.framenumber = to64<uint64_t>(frameNumberLo, frameNumberHi);
131 readAligned(buffer, size, maxAcquiredBufferCount);
132
133 return OK;
134}
135
136status_t BufferReleaseChannel::ConsumerEndpoint::readReleaseFence(
137 ReleaseCallbackId& outReleaseCallbackId, sp<Fence>& outReleaseFence,
138 uint32_t& outMaxAcquiredBufferCount) {
Patrick Williams078d7362024-08-27 10:20:39 -0500139 std::lock_guard lock{mMutex};
Patrick Williamsf693bcf2024-08-02 09:55:23 -0500140 Message message;
141 mFlattenedBuffer.resize(message.getFlattenedSize());
142 std::array<uint8_t, CMSG_SPACE(sizeof(int))> controlMessageBuffer;
143
144 iovec iov{
145 .iov_base = mFlattenedBuffer.data(),
146 .iov_len = mFlattenedBuffer.size(),
147 };
148
149 msghdr msg{
150 .msg_iov = &iov,
151 .msg_iovlen = 1,
152 .msg_control = controlMessageBuffer.data(),
153 .msg_controllen = controlMessageBuffer.size(),
154 };
155
Patrick Williams078d7362024-08-27 10:20:39 -0500156 ssize_t result;
Patrick Williamsf693bcf2024-08-02 09:55:23 -0500157 do {
158 result = recvmsg(mFd, &msg, 0);
159 } while (result == -1 && errno == EINTR);
160 if (result == -1) {
161 if (errno == EWOULDBLOCK || errno == EAGAIN) {
162 return WOULD_BLOCK;
163 }
164 ALOGE("Error reading release fence from socket: error %#x (%s)", errno, strerror(errno));
165 return UNKNOWN_ERROR;
166 }
167
168 if (msg.msg_iovlen != 1) {
169 ALOGE("Error reading release fence from socket: bad data length");
170 return UNKNOWN_ERROR;
171 }
172
173 if (msg.msg_controllen % sizeof(int) != 0) {
174 ALOGE("Error reading release fence from socket: bad fd length");
175 return UNKNOWN_ERROR;
176 }
177
178 size_t dataLen = msg.msg_iov->iov_len;
179 const void* data = static_cast<const void*>(msg.msg_iov->iov_base);
180 if (!data) {
181 ALOGE("Error reading release fence from socket: no buffer data");
182 return UNKNOWN_ERROR;
183 }
184
185 size_t fdCount = 0;
186 const int* fdData = nullptr;
187 if (cmsghdr* cmsg = CMSG_FIRSTHDR(&msg)) {
188 fdData = reinterpret_cast<const int*>(CMSG_DATA(cmsg));
189 fdCount = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
190 }
191
192 if (status_t err = message.unflatten(data, dataLen, fdData, fdCount); err != OK) {
193 return err;
194 }
195
196 outReleaseCallbackId = message.releaseCallbackId;
197 outReleaseFence = std::move(message.releaseFence);
198 outMaxAcquiredBufferCount = message.maxAcquiredBufferCount;
199
200 return OK;
201}
202
203int BufferReleaseChannel::ProducerEndpoint::writeReleaseFence(const ReleaseCallbackId& callbackId,
204 const sp<Fence>& fence,
205 uint32_t maxAcquiredBufferCount) {
206 Message message{callbackId, fence ? fence : Fence::NO_FENCE, maxAcquiredBufferCount};
207 mFlattenedBuffer.resize(message.getFlattenedSize());
208 int flattenedFd;
209 {
210 // Make copies of needed items since flatten modifies them, and we don't
211 // want to send anything if there's an error during flatten.
212 void* flattenedBufferPtr = mFlattenedBuffer.data();
213 size_t flattenedBufferSize = mFlattenedBuffer.size();
214 int* flattenedFdPtr = &flattenedFd;
215 size_t flattenedFdCount = 1;
216 if (status_t err = message.flatten(flattenedBufferPtr, flattenedBufferSize, flattenedFdPtr,
217 flattenedFdCount);
218 err != OK) {
219 ALOGE("Failed to flatten BufferReleaseChannel message.");
220 return err;
221 }
222 }
223
224 iovec iov{
225 .iov_base = mFlattenedBuffer.data(),
226 .iov_len = mFlattenedBuffer.size(),
227 };
228
229 msghdr msg{
230 .msg_iov = &iov,
231 .msg_iovlen = 1,
232 };
233
234 std::array<uint8_t, CMSG_SPACE(sizeof(int))> controlMessageBuffer;
235 if (fence && fence->isValid()) {
236 msg.msg_control = controlMessageBuffer.data();
237 msg.msg_controllen = controlMessageBuffer.size();
238
239 cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
240 cmsg->cmsg_level = SOL_SOCKET;
241 cmsg->cmsg_type = SCM_RIGHTS;
242 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
243 memcpy(CMSG_DATA(cmsg), &flattenedFd, sizeof(int));
244 }
245
Patrick Williams078d7362024-08-27 10:20:39 -0500246 ssize_t result;
Patrick Williamsf693bcf2024-08-02 09:55:23 -0500247 do {
248 result = sendmsg(mFd, &msg, 0);
249 } while (result == -1 && errno == EINTR);
250 if (result == -1) {
251 ALOGD("Error writing release fence to socket: error %#x (%s)", errno, strerror(errno));
252 return -errno;
253 }
254
255 return OK;
256}
257
258status_t BufferReleaseChannel::ProducerEndpoint::readFromParcel(const android::Parcel* parcel) {
259 if (!parcel) return STATUS_BAD_VALUE;
260 SAFE_PARCEL(parcel->readUtf8FromUtf16, &mName);
261 SAFE_PARCEL(parcel->readUniqueFileDescriptor, &mFd);
262 return STATUS_OK;
263}
264
265status_t BufferReleaseChannel::ProducerEndpoint::writeToParcel(android::Parcel* parcel) const {
266 if (!parcel) return STATUS_BAD_VALUE;
267 SAFE_PARCEL(parcel->writeUtf8AsUtf16, mName);
268 SAFE_PARCEL(parcel->writeUniqueFileDescriptor, mFd);
269 return STATUS_OK;
270}
271
272status_t BufferReleaseChannel::open(std::string name,
273 std::unique_ptr<ConsumerEndpoint>& outConsumer,
274 std::shared_ptr<ProducerEndpoint>& outProducer) {
275 outConsumer.reset();
276 outProducer.reset();
277
278 int sockets[2];
279 if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {
280 ALOGE("[%s] Failed to create socket pair. errorno=%d message='%s'", name.c_str(), errno,
281 strerror(errno));
282 return -errno;
283 }
284
285 android::base::unique_fd consumerFd(sockets[0]);
286 android::base::unique_fd producerFd(sockets[1]);
287
288 // Socket buffer size. The default is typically about 128KB, which is much larger than
289 // we really need.
290 size_t bufferSize = 32 * 1024;
291 if (setsockopt(consumerFd.get(), SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize)) ==
292 -1) {
293 ALOGE("[%s] Failed to set consumer socket send buffer size. errno=%d message='%s'",
294 name.c_str(), errno, strerror(errno));
295 return -errno;
296 }
297 if (setsockopt(consumerFd.get(), SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize)) ==
298 -1) {
299 ALOGE("[%s] Failed to set consumer socket receive buffer size. errno=%d "
300 "message='%s'",
301 name.c_str(), errno, strerror(errno));
302 return -errno;
303 }
304 if (setsockopt(producerFd.get(), SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize)) ==
305 -1) {
306 ALOGE("[%s] Failed to set producer socket send buffer size. errno=%d message='%s'",
307 name.c_str(), errno, strerror(errno));
308 return -errno;
309 }
310 if (setsockopt(producerFd.get(), SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize)) ==
311 -1) {
312 ALOGE("[%s] Failed to set producer socket receive buffer size. errno=%d "
313 "message='%s'",
314 name.c_str(), errno, strerror(errno));
315 return -errno;
316 }
317
318 // Configure the consumer socket to be non-blocking.
319 int flags = fcntl(consumerFd.get(), F_GETFL, 0);
320 if (flags == -1) {
321 ALOGE("[%s] Failed to get consumer socket flags. errno=%d message='%s'", name.c_str(),
322 errno, strerror(errno));
323 return -errno;
324 }
325 if (fcntl(consumerFd.get(), F_SETFL, flags | O_NONBLOCK) == -1) {
326 ALOGE("[%s] Failed to set consumer socket to non-blocking mode. errno=%d "
327 "message='%s'",
328 name.c_str(), errno, strerror(errno));
329 return -errno;
330 }
331
332 // Configure a timeout for the producer socket.
333 const timeval timeout{.tv_sec = 1, .tv_usec = 0};
334 if (setsockopt(producerFd.get(), SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeval)) == -1) {
335 ALOGE("[%s] Failed to set producer socket timeout. errno=%d message='%s'", name.c_str(),
336 errno, strerror(errno));
337 return -errno;
338 }
339
340 // Make the consumer read-only
341 if (shutdown(consumerFd.get(), SHUT_WR) == -1) {
342 ALOGE("[%s] Failed to shutdown writing on consumer socket. errno=%d message='%s'",
343 name.c_str(), errno, strerror(errno));
344 return -errno;
345 }
346
347 // Make the producer write-only
348 if (shutdown(producerFd.get(), SHUT_RD) == -1) {
349 ALOGE("[%s] Failed to shutdown reading on producer socket. errno=%d message='%s'",
350 name.c_str(), errno, strerror(errno));
351 return -errno;
352 }
353
354 outConsumer = std::make_unique<ConsumerEndpoint>(name, std::move(consumerFd));
355 outProducer = std::make_shared<ProducerEndpoint>(std::move(name), std::move(producerFd));
356 return STATUS_OK;
357}
358
359} // namespace android::gui