Skip to content

Commit 5b54bd3

Browse files
Treehugger RobotAndroid (Google) Code Review
authored andcommitted
Merge "Drain buffer release thread in binder callback" into main
2 parents ae65265 + c16a4a5 commit 5b54bd3

2 files changed

Lines changed: 37 additions & 132 deletions

File tree

libs/gui/BLASTBufferQueue.cpp

Lines changed: 35 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -52,19 +52,18 @@ using namespace std::chrono_literals;
5252
namespace {
5353

5454
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
55-
// RAII wrapper to defer arbitrary work until the Deferred instance is deleted.
56-
template <class F>
57-
class Deferred {
55+
template <class Mutex>
56+
class UnlockGuard {
5857
public:
59-
explicit Deferred(F f) : mF{std::move(f)} {}
58+
explicit UnlockGuard(Mutex& lock) : mLock{lock} { mLock.unlock(); }
6059

61-
~Deferred() { mF(); }
60+
~UnlockGuard() { mLock.lock(); }
6261

63-
Deferred(const Deferred&) = delete;
64-
Deferred& operator=(const Deferred&) = delete;
62+
UnlockGuard(const UnlockGuard&) = delete;
63+
UnlockGuard& operator=(const UnlockGuard&) = delete;
6564

6665
private:
67-
F mF;
66+
Mutex& mLock;
6867
};
6968
#endif
7069

@@ -271,9 +270,6 @@ BLASTBufferQueue::~BLASTBufferQueue() {
271270
void BLASTBufferQueue::onFirstRef() {
272271
// safe default, most producers are expected to override this
273272
mProducer->setMaxDequeuedBufferCount(2);
274-
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
275-
mBufferReleaseThread.emplace(sp<BLASTBufferQueue>::fromExisting(this));
276-
#endif
277273
}
278274

279275
void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, uint32_t width, uint32_t height,
@@ -297,11 +293,16 @@ void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, uint32_t width,
297293
mSurfaceControl = surface;
298294
SurfaceComposerClient::Transaction t;
299295
if (surfaceControlChanged) {
300-
t.setFlags(mSurfaceControl, layer_state_t::eEnableBackpressure,
301-
layer_state_t::eEnableBackpressure);
302296
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
303-
t.setBufferReleaseChannel(mSurfaceControl, mBufferReleaseProducer);
297+
// SELinux policy may prevent this process from sending the BufferReleaseChannel's file
298+
// descriptor to SurfaceFlinger, causing the entire transaction to be dropped. This
299+
// transaction is applied separately to ensure we don't lose the other updates.
300+
t.setApplyToken(mApplyToken)
301+
.setBufferReleaseChannel(mSurfaceControl, mBufferReleaseProducer)
302+
.apply(false /* synchronous */, true /* oneWay */);
304303
#endif
304+
t.setFlags(mSurfaceControl, layer_state_t::eEnableBackpressure,
305+
layer_state_t::eEnableBackpressure);
305306
applyTransaction = true;
306307
}
307308
mTransformHint = mSurfaceControl->getTransformHint();
@@ -325,7 +326,7 @@ void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, uint32_t width,
325326
}
326327
if (applyTransaction) {
327328
// All transactions on our apply token are one-way. See comment on mAppliedLastTransaction
328-
t.setApplyToken(mApplyToken).apply(false, true);
329+
t.setApplyToken(mApplyToken).apply(false /* synchronous */, true /* oneWay */);
329330
}
330331
}
331332

@@ -419,7 +420,6 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp<Fence
419420
stat.latchTime,
420421
stat.frameEventStats.dequeueReadyTime);
421422
}
422-
#if !COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
423423
auto currFrameNumber = stat.frameEventStats.frameNumber;
424424
std::vector<ReleaseCallbackId> staleReleases;
425425
for (const auto& [key, value]: mSubmitted) {
@@ -435,7 +435,6 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp<Fence
435435
stat.currentMaxAcquiredBufferCount,
436436
true /* fakeRelease */);
437437
}
438-
#endif
439438
} else {
440439
BQA_LOGE("Failed to find matching SurfaceControl in transactionCallback");
441440
}
@@ -469,6 +468,9 @@ ReleaseBufferCallback BLASTBufferQueue::makeReleaseBufferCallbackThunk() {
469468
return;
470469
}
471470
bbq->releaseBufferCallback(id, releaseFence, currentMaxAcquiredBufferCount);
471+
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
472+
bbq->drainBufferReleaseConsumer();
473+
#endif
472474
};
473475
}
474476

@@ -535,8 +537,6 @@ void BLASTBufferQueue::releaseBuffer(const ReleaseCallbackId& callbackId,
535537
const sp<Fence>& releaseFence) {
536538
auto it = mSubmitted.find(callbackId);
537539
if (it == mSubmitted.end()) {
538-
BQA_LOGE("ERROR: releaseBufferCallback without corresponding submitted buffer %s",
539-
callbackId.to_string().c_str());
540540
return;
541541
}
542542
mNumAcquired--;
@@ -646,12 +646,7 @@ status_t BLASTBufferQueue::acquireNextBufferLocked(
646646
bufferItem.mGraphicBuffer->getHeight(), bufferItem.mTransform,
647647
bufferItem.mScalingMode, crop);
648648

649-
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
650-
ReleaseBufferCallback releaseBufferCallback =
651-
applyTransaction ? nullptr : makeReleaseBufferCallbackThunk();
652-
#else
653649
auto releaseBufferCallback = makeReleaseBufferCallbackThunk();
654-
#endif
655650
sp<Fence> fence = bufferItem.mFence ? new Fence(bufferItem.mFence->dup()) : Fence::NO_FENCE;
656651

657652
nsecs_t dequeueTime = -1;
@@ -1230,12 +1225,7 @@ class BBQBufferQueueProducer : public BufferQueueProducer {
12301225
// we want to ignore it. This must be done before unlocking the BufferQueue lock to ensure
12311226
// we don't miss an interrupt.
12321227
bbq->mBufferReleaseReader->clearInterrupts();
1233-
bbq->mThreadsBlockingOnDequeue++;
1234-
bufferQueueLock.unlock();
1235-
Deferred cleanup{[&]() {
1236-
bufferQueueLock.lock();
1237-
bbq->mThreadsBlockingOnDequeue--;
1238-
}};
1228+
UnlockGuard unlockGuard{bufferQueueLock};
12391229

12401230
ATRACE_FORMAT("waiting for free buffer");
12411231
ReleaseCallbackId id;
@@ -1345,6 +1335,21 @@ void BLASTBufferQueue::setApplyToken(sp<IBinder> applyToken) {
13451335

13461336
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
13471337

1338+
void BLASTBufferQueue::drainBufferReleaseConsumer() {
1339+
ATRACE_CALL();
1340+
while (true) {
1341+
ReleaseCallbackId id;
1342+
sp<Fence> fence;
1343+
uint32_t maxAcquiredBufferCount;
1344+
status_t status =
1345+
mBufferReleaseConsumer->readReleaseFence(id, fence, maxAcquiredBufferCount);
1346+
if (status != OK) {
1347+
return;
1348+
}
1349+
releaseBufferCallback(id, fence, maxAcquiredBufferCount);
1350+
}
1351+
}
1352+
13481353
BLASTBufferQueue::BufferReleaseReader::BufferReleaseReader(BLASTBufferQueue& bbq) : mBbq{bbq} {
13491354
mEpollFd = android::base::unique_fd{epoll_create1(EPOLL_CLOEXEC)};
13501355
LOG_ALWAYS_FATAL_IF(!mEpollFd.ok(),
@@ -1438,95 +1443,6 @@ void BLASTBufferQueue::BufferReleaseReader::clearInterrupts() {
14381443
}
14391444
}
14401445

1441-
BLASTBufferQueue::BufferReleaseThread::BufferReleaseThread(const sp<BLASTBufferQueue>& bbq) {
1442-
android::base::unique_fd epollFd{epoll_create1(EPOLL_CLOEXEC)};
1443-
LOG_ALWAYS_FATAL_IF(!epollFd.ok(),
1444-
"Failed to create buffer release background thread epoll file descriptor. "
1445-
"errno=%d message='%s'",
1446-
errno, strerror(errno));
1447-
1448-
epoll_event registerEndpointFd{};
1449-
registerEndpointFd.events = EPOLLIN;
1450-
registerEndpointFd.data.fd = bbq->mBufferReleaseConsumer->getFd();
1451-
status_t status = epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, bbq->mBufferReleaseConsumer->getFd(),
1452-
&registerEndpointFd);
1453-
LOG_ALWAYS_FATAL_IF(status == -1,
1454-
"Failed to register background thread buffer release consumer file "
1455-
"descriptor with epoll. errno=%d message='%s'",
1456-
errno, strerror(errno));
1457-
1458-
// EventFd is used to break the background thread's loop.
1459-
android::base::unique_fd eventFd{eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK)};
1460-
LOG_ALWAYS_FATAL_IF(!eventFd.ok(),
1461-
"Failed to create background thread buffer release event file descriptor. "
1462-
"errno=%d message='%s'",
1463-
errno, strerror(errno));
1464-
1465-
epoll_event registerEventFd{};
1466-
registerEventFd.events = EPOLLIN;
1467-
registerEventFd.data.fd = eventFd.get();
1468-
status = epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd.get(), &registerEventFd);
1469-
LOG_ALWAYS_FATAL_IF(status == -1,
1470-
"Failed to register background thread event file descriptor with epoll. "
1471-
"errno=%d message='%s'",
1472-
errno, strerror(errno));
1473-
1474-
mEventFd = eventFd.get();
1475-
1476-
std::thread([epollFd = std::move(epollFd), eventFd = std::move(eventFd),
1477-
weakBbq = wp<BLASTBufferQueue>(bbq)]() {
1478-
pthread_setname_np(pthread_self(), "BufferReleaseThread");
1479-
while (true) {
1480-
epoll_event event{};
1481-
int eventCount;
1482-
do {
1483-
eventCount = epoll_wait(epollFd.get(), &event, 1 /*maxevents*/, -1 /*timeout*/);
1484-
} while (eventCount == -1 && errno != EINTR);
1485-
1486-
if (eventCount == -1) {
1487-
ALOGE("epoll_wait error while waiting for buffer release in background thread. "
1488-
"errno=%d message='%s'",
1489-
errno, strerror(errno));
1490-
continue;
1491-
}
1492-
1493-
// EventFd is used to join this thread.
1494-
if (event.data.fd == eventFd.get()) {
1495-
return;
1496-
}
1497-
1498-
sp<BLASTBufferQueue> bbq = weakBbq.promote();
1499-
if (!bbq) {
1500-
return;
1501-
}
1502-
1503-
// If there are threads blocking on dequeue, give those threads priority for handling
1504-
// the release.
1505-
if (bbq->mThreadsBlockingOnDequeue > 0) {
1506-
std::this_thread::sleep_for(0ms);
1507-
continue;
1508-
}
1509-
1510-
ReleaseCallbackId id;
1511-
sp<Fence> fence;
1512-
uint32_t maxAcquiredBufferCount;
1513-
status_t status = bbq->mBufferReleaseConsumer->readReleaseFence(id, fence,
1514-
maxAcquiredBufferCount);
1515-
if (status != OK) {
1516-
ALOGE("failed to read from buffer release consumer in background thread. errno=%d "
1517-
"message='%s'",
1518-
errno, strerror(errno));
1519-
continue;
1520-
}
1521-
bbq->releaseBufferCallback(id, fence, maxAcquiredBufferCount);
1522-
}
1523-
}).detach();
1524-
}
1525-
1526-
BLASTBufferQueue::BufferReleaseThread::~BufferReleaseThread() {
1527-
eventfd_write(mEventFd, 1);
1528-
}
1529-
15301446
#endif
15311447

15321448
} // namespace android

libs/gui/include/gui/BLASTBufferQueue.h

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,8 @@ class BLASTBufferQueue : public ConsumerBase::FrameAvailableListener {
325325
std::unique_ptr<gui::BufferReleaseChannel::ConsumerEndpoint> mBufferReleaseConsumer;
326326
std::shared_ptr<gui::BufferReleaseChannel::ProducerEndpoint> mBufferReleaseProducer;
327327

328+
void drainBufferReleaseConsumer();
329+
328330
class BufferReleaseReader {
329331
public:
330332
explicit BufferReleaseReader(BLASTBufferQueue&);
@@ -353,19 +355,6 @@ class BLASTBufferQueue : public ConsumerBase::FrameAvailableListener {
353355
};
354356

355357
std::optional<BufferReleaseReader> mBufferReleaseReader;
356-
357-
std::atomic<int> mThreadsBlockingOnDequeue = 0;
358-
359-
class BufferReleaseThread {
360-
public:
361-
BufferReleaseThread(const sp<BLASTBufferQueue>&);
362-
~BufferReleaseThread();
363-
364-
private:
365-
int mEventFd;
366-
};
367-
368-
std::optional<BufferReleaseThread> mBufferReleaseThread;
369358
#endif
370359
};
371360

0 commit comments

Comments
 (0)