Merge "Add flag for connected displays cursor" into main
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index 49f4cba..fdc39ed 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -52,19 +52,18 @@
namespace {
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
-// RAII wrapper to defer arbitrary work until the Deferred instance is deleted.
-template <class F>
-class Deferred {
+template <class Mutex>
+class UnlockGuard {
public:
- explicit Deferred(F f) : mF{std::move(f)} {}
+ explicit UnlockGuard(Mutex& lock) : mLock{lock} { mLock.unlock(); }
- ~Deferred() { mF(); }
+ ~UnlockGuard() { mLock.lock(); }
- Deferred(const Deferred&) = delete;
- Deferred& operator=(const Deferred&) = delete;
+ UnlockGuard(const UnlockGuard&) = delete;
+ UnlockGuard& operator=(const UnlockGuard&) = delete;
private:
- F mF;
+ Mutex& mLock;
};
#endif
@@ -271,9 +270,6 @@
void BLASTBufferQueue::onFirstRef() {
// safe default, most producers are expected to override this
mProducer->setMaxDequeuedBufferCount(2);
-#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
- mBufferReleaseThread.emplace(sp<BLASTBufferQueue>::fromExisting(this));
-#endif
}
void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, uint32_t width, uint32_t height,
@@ -297,11 +293,16 @@
mSurfaceControl = surface;
SurfaceComposerClient::Transaction t;
if (surfaceControlChanged) {
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
+ // SELinux policy may prevent this process from sending the BufferReleaseChannel's file
+ // descriptor to SurfaceFlinger, causing the entire transaction to be dropped. This
+ // transaction is applied separately to ensure we don't lose the other updates.
+ t.setApplyToken(mApplyToken)
+ .setBufferReleaseChannel(mSurfaceControl, mBufferReleaseProducer)
+ .apply(false /* synchronous */, true /* oneWay */);
+#endif
t.setFlags(mSurfaceControl, layer_state_t::eEnableBackpressure,
layer_state_t::eEnableBackpressure);
-#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
- t.setBufferReleaseChannel(mSurfaceControl, mBufferReleaseProducer);
-#endif
applyTransaction = true;
}
mTransformHint = mSurfaceControl->getTransformHint();
@@ -325,7 +326,7 @@
}
if (applyTransaction) {
// All transactions on our apply token are one-way. See comment on mAppliedLastTransaction
- t.setApplyToken(mApplyToken).apply(false, true);
+ t.setApplyToken(mApplyToken).apply(false /* synchronous */, true /* oneWay */);
}
}
@@ -419,7 +420,6 @@
stat.latchTime,
stat.frameEventStats.dequeueReadyTime);
}
-#if !COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
auto currFrameNumber = stat.frameEventStats.frameNumber;
std::vector<ReleaseCallbackId> staleReleases;
for (const auto& [key, value]: mSubmitted) {
@@ -435,7 +435,6 @@
stat.currentMaxAcquiredBufferCount,
true /* fakeRelease */);
}
-#endif
} else {
BQA_LOGE("Failed to find matching SurfaceControl in transactionCallback");
}
@@ -469,6 +468,9 @@
return;
}
bbq->releaseBufferCallback(id, releaseFence, currentMaxAcquiredBufferCount);
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
+ bbq->drainBufferReleaseConsumer();
+#endif
};
}
@@ -535,8 +537,6 @@
const sp<Fence>& releaseFence) {
auto it = mSubmitted.find(callbackId);
if (it == mSubmitted.end()) {
- BQA_LOGE("ERROR: releaseBufferCallback without corresponding submitted buffer %s",
- callbackId.to_string().c_str());
return;
}
mNumAcquired--;
@@ -646,12 +646,7 @@
bufferItem.mGraphicBuffer->getHeight(), bufferItem.mTransform,
bufferItem.mScalingMode, crop);
-#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
- ReleaseBufferCallback releaseBufferCallback =
- applyTransaction ? nullptr : makeReleaseBufferCallbackThunk();
-#else
auto releaseBufferCallback = makeReleaseBufferCallbackThunk();
-#endif
sp<Fence> fence = bufferItem.mFence ? new Fence(bufferItem.mFence->dup()) : Fence::NO_FENCE;
nsecs_t dequeueTime = -1;
@@ -1230,12 +1225,7 @@
// we want to ignore it. This must be done before unlocking the BufferQueue lock to ensure
// we don't miss an interrupt.
bbq->mBufferReleaseReader->clearInterrupts();
- bbq->mThreadsBlockingOnDequeue++;
- bufferQueueLock.unlock();
- Deferred cleanup{[&]() {
- bufferQueueLock.lock();
- bbq->mThreadsBlockingOnDequeue--;
- }};
+ UnlockGuard unlockGuard{bufferQueueLock};
ATRACE_FORMAT("waiting for free buffer");
ReleaseCallbackId id;
@@ -1345,6 +1335,21 @@
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
+void BLASTBufferQueue::drainBufferReleaseConsumer() {
+ ATRACE_CALL();
+ while (true) {
+ ReleaseCallbackId id;
+ sp<Fence> fence;
+ uint32_t maxAcquiredBufferCount;
+ status_t status =
+ mBufferReleaseConsumer->readReleaseFence(id, fence, maxAcquiredBufferCount);
+ if (status != OK) {
+ return;
+ }
+ releaseBufferCallback(id, fence, maxAcquiredBufferCount);
+ }
+}
+
BLASTBufferQueue::BufferReleaseReader::BufferReleaseReader(BLASTBufferQueue& bbq) : mBbq{bbq} {
mEpollFd = android::base::unique_fd{epoll_create1(EPOLL_CLOEXEC)};
LOG_ALWAYS_FATAL_IF(!mEpollFd.ok(),
@@ -1438,95 +1443,6 @@
}
}
-BLASTBufferQueue::BufferReleaseThread::BufferReleaseThread(const sp<BLASTBufferQueue>& bbq) {
- android::base::unique_fd epollFd{epoll_create1(EPOLL_CLOEXEC)};
- LOG_ALWAYS_FATAL_IF(!epollFd.ok(),
- "Failed to create buffer release background thread epoll file descriptor. "
- "errno=%d message='%s'",
- errno, strerror(errno));
-
- epoll_event registerEndpointFd{};
- registerEndpointFd.events = EPOLLIN;
- registerEndpointFd.data.fd = bbq->mBufferReleaseConsumer->getFd();
- status_t status = epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, bbq->mBufferReleaseConsumer->getFd(),
- ®isterEndpointFd);
- LOG_ALWAYS_FATAL_IF(status == -1,
- "Failed to register background thread buffer release consumer file "
- "descriptor with epoll. errno=%d message='%s'",
- errno, strerror(errno));
-
- // EventFd is used to break the background thread's loop.
- android::base::unique_fd eventFd{eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK)};
- LOG_ALWAYS_FATAL_IF(!eventFd.ok(),
- "Failed to create background thread buffer release event file descriptor. "
- "errno=%d message='%s'",
- errno, strerror(errno));
-
- epoll_event registerEventFd{};
- registerEventFd.events = EPOLLIN;
- registerEventFd.data.fd = eventFd.get();
- status = epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd.get(), ®isterEventFd);
- LOG_ALWAYS_FATAL_IF(status == -1,
- "Failed to register background thread event file descriptor with epoll. "
- "errno=%d message='%s'",
- errno, strerror(errno));
-
- mEventFd = eventFd.get();
-
- std::thread([epollFd = std::move(epollFd), eventFd = std::move(eventFd),
- weakBbq = wp<BLASTBufferQueue>(bbq)]() {
- pthread_setname_np(pthread_self(), "BufferReleaseThread");
- while (true) {
- epoll_event event{};
- int eventCount;
- do {
- eventCount = epoll_wait(epollFd.get(), &event, 1 /*maxevents*/, -1 /*timeout*/);
- } while (eventCount == -1 && errno != EINTR);
-
- if (eventCount == -1) {
- ALOGE("epoll_wait error while waiting for buffer release in background thread. "
- "errno=%d message='%s'",
- errno, strerror(errno));
- continue;
- }
-
- // EventFd is used to join this thread.
- if (event.data.fd == eventFd.get()) {
- return;
- }
-
- sp<BLASTBufferQueue> bbq = weakBbq.promote();
- if (!bbq) {
- return;
- }
-
- // If there are threads blocking on dequeue, give those threads priority for handling
- // the release.
- if (bbq->mThreadsBlockingOnDequeue > 0) {
- std::this_thread::sleep_for(0ms);
- continue;
- }
-
- ReleaseCallbackId id;
- sp<Fence> fence;
- uint32_t maxAcquiredBufferCount;
- status_t status = bbq->mBufferReleaseConsumer->readReleaseFence(id, fence,
- maxAcquiredBufferCount);
- if (status != OK) {
- ALOGE("failed to read from buffer release consumer in background thread. errno=%d "
- "message='%s'",
- errno, strerror(errno));
- continue;
- }
- bbq->releaseBufferCallback(id, fence, maxAcquiredBufferCount);
- }
- }).detach();
-}
-
-BLASTBufferQueue::BufferReleaseThread::~BufferReleaseThread() {
- eventfd_write(mEventFd, 1);
-}
-
#endif
} // namespace android
diff --git a/libs/gui/BufferReleaseChannel.cpp b/libs/gui/BufferReleaseChannel.cpp
index e9c6ef3..e9cb013 100644
--- a/libs/gui/BufferReleaseChannel.cpp
+++ b/libs/gui/BufferReleaseChannel.cpp
@@ -35,35 +35,35 @@
namespace {
template <typename T>
-static void readAligned(const void*& buffer, size_t& size, T& value) {
+void readAligned(const void*& buffer, size_t& size, T& value) {
size -= FlattenableUtils::align<alignof(T)>(buffer);
FlattenableUtils::read(buffer, size, value);
}
template <typename T>
-static void writeAligned(void*& buffer, size_t& size, T value) {
+void writeAligned(void*& buffer, size_t& size, T value) {
size -= FlattenableUtils::align<alignof(T)>(buffer);
FlattenableUtils::write(buffer, size, value);
}
template <typename T>
-static void addAligned(size_t& size, T /* value */) {
+void addAligned(size_t& size, T /* value */) {
size = FlattenableUtils::align<sizeof(T)>(size);
size += sizeof(T);
}
template <typename T>
-static inline constexpr uint32_t low32(const T n) {
+inline constexpr uint32_t low32(const T n) {
return static_cast<uint32_t>(static_cast<uint64_t>(n));
}
template <typename T>
-static inline constexpr uint32_t high32(const T n) {
+inline constexpr uint32_t high32(const T n) {
return static_cast<uint32_t>(static_cast<uint64_t>(n) >> 32);
}
template <typename T>
-static inline constexpr T to64(const uint32_t lo, const uint32_t hi) {
+inline constexpr T to64(const uint32_t lo, const uint32_t hi) {
return static_cast<T>(static_cast<uint64_t>(hi) << 32 | lo);
}
@@ -139,19 +139,18 @@
std::lock_guard lock{mMutex};
Message message;
mFlattenedBuffer.resize(message.getFlattenedSize());
- std::array<uint8_t, CMSG_SPACE(sizeof(int))> controlMessageBuffer;
+ std::array<uint8_t, CMSG_SPACE(sizeof(int))> controlMessageBuffer{};
iovec iov{
.iov_base = mFlattenedBuffer.data(),
.iov_len = mFlattenedBuffer.size(),
};
- msghdr msg{
- .msg_iov = &iov,
- .msg_iovlen = 1,
- .msg_control = controlMessageBuffer.data(),
- .msg_controllen = controlMessageBuffer.size(),
- };
+ msghdr msg{};
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = controlMessageBuffer.data();
+ msg.msg_controllen = controlMessageBuffer.size();
ssize_t result;
do {
@@ -161,7 +160,7 @@
if (errno == EWOULDBLOCK || errno == EAGAIN) {
return WOULD_BLOCK;
}
- ALOGE("Error reading release fence from socket: error %#x (%s)", errno, strerror(errno));
+ ALOGE("Error reading release fence from socket: error %d (%s)", errno, strerror(errno));
return UNKNOWN_ERROR;
}
@@ -200,9 +199,9 @@
return OK;
}
-int BufferReleaseChannel::ProducerEndpoint::writeReleaseFence(const ReleaseCallbackId& callbackId,
- const sp<Fence>& fence,
- uint32_t maxAcquiredBufferCount) {
+status_t BufferReleaseChannel::ProducerEndpoint::writeReleaseFence(
+ const ReleaseCallbackId& callbackId, const sp<Fence>& fence,
+ uint32_t maxAcquiredBufferCount) {
Message message{callbackId, fence ? fence : Fence::NO_FENCE, maxAcquiredBufferCount};
mFlattenedBuffer.resize(message.getFlattenedSize());
int flattenedFd;
@@ -213,25 +212,22 @@
size_t flattenedBufferSize = mFlattenedBuffer.size();
int* flattenedFdPtr = &flattenedFd;
size_t flattenedFdCount = 1;
- if (status_t err = message.flatten(flattenedBufferPtr, flattenedBufferSize, flattenedFdPtr,
- flattenedFdCount);
- err != OK) {
- ALOGE("Failed to flatten BufferReleaseChannel message.");
- return err;
+ if (status_t status = message.flatten(flattenedBufferPtr, flattenedBufferSize,
+ flattenedFdPtr, flattenedFdCount);
+ status != OK) {
+ return status;
}
}
- iovec iov{
- .iov_base = mFlattenedBuffer.data(),
- .iov_len = mFlattenedBuffer.size(),
- };
+ iovec iov{};
+ iov.iov_base = mFlattenedBuffer.data();
+ iov.iov_len = mFlattenedBuffer.size();
- msghdr msg{
- .msg_iov = &iov,
- .msg_iovlen = 1,
- };
+ msghdr msg{};
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
- std::array<uint8_t, CMSG_SPACE(sizeof(int))> controlMessageBuffer;
+ std::array<uint8_t, CMSG_SPACE(sizeof(int))> controlMessageBuffer{};
if (fence && fence->isValid()) {
msg.msg_control = controlMessageBuffer.data();
msg.msg_controllen = controlMessageBuffer.size();
@@ -248,7 +244,6 @@
result = sendmsg(mFd, &msg, 0);
} while (result == -1 && errno == EINTR);
if (result == -1) {
- ALOGD("Error writing release fence to socket: error %#x (%s)", errno, strerror(errno));
return -errno;
}
@@ -344,13 +339,6 @@
return -errno;
}
- // Make the producer write-only
- if (shutdown(producerFd.get(), SHUT_RD) == -1) {
- ALOGE("[%s] Failed to shutdown reading on producer socket. errno=%d message='%s'",
- name.c_str(), errno, strerror(errno));
- return -errno;
- }
-
outConsumer = std::make_unique<ConsumerEndpoint>(name, std::move(consumerFd));
outProducer = std::make_shared<ProducerEndpoint>(std::move(name), std::move(producerFd));
return STATUS_OK;
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index 99c64da..4fd44e5 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -325,6 +325,8 @@
std::unique_ptr<gui::BufferReleaseChannel::ConsumerEndpoint> mBufferReleaseConsumer;
std::shared_ptr<gui::BufferReleaseChannel::ProducerEndpoint> mBufferReleaseProducer;
+ void drainBufferReleaseConsumer();
+
class BufferReleaseReader {
public:
explicit BufferReleaseReader(BLASTBufferQueue&);
@@ -353,19 +355,6 @@
};
std::optional<BufferReleaseReader> mBufferReleaseReader;
-
- std::atomic<int> mThreadsBlockingOnDequeue = 0;
-
- class BufferReleaseThread {
- public:
- BufferReleaseThread(const sp<BLASTBufferQueue>&);
- ~BufferReleaseThread();
-
- private:
- int mEventFd;
- };
-
- std::optional<BufferReleaseThread> mBufferReleaseThread;
#endif
};
diff --git a/libs/gui/tests/BufferReleaseChannel_test.cpp b/libs/gui/tests/BufferReleaseChannel_test.cpp
index 11d122b..74f69e1 100644
--- a/libs/gui/tests/BufferReleaseChannel_test.cpp
+++ b/libs/gui/tests/BufferReleaseChannel_test.cpp
@@ -29,11 +29,11 @@
// Helper function to check if two file descriptors point to the same file.
bool is_same_file(int fd1, int fd2) {
- struct stat stat1;
+ struct stat stat1 {};
if (fstat(fd1, &stat1) != 0) {
return false;
}
- struct stat stat2;
+ struct stat stat2 {};
if (fstat(fd2, &stat2) != 0) {
return false;
}
@@ -42,7 +42,18 @@
} // namespace
-TEST(BufferReleaseChannelTest, MessageFlattenable) {
+class BufferReleaseChannelTest : public testing::Test {
+protected:
+ std::unique_ptr<BufferReleaseChannel::ConsumerEndpoint> mConsumer;
+ std::shared_ptr<BufferReleaseChannel::ProducerEndpoint> mProducer;
+
+ void SetUp() override {
+ ASSERT_EQ(OK,
+ BufferReleaseChannel::open("BufferReleaseChannelTest"s, mConsumer, mProducer));
+ }
+};
+
+TEST_F(BufferReleaseChannelTest, MessageFlattenable) {
ReleaseCallbackId releaseCallbackId{1, 2};
sp<Fence> releaseFence = sp<Fence>::make(memfd_create("fake-fence-fd", 0));
uint32_t maxAcquiredBufferCount = 5;
@@ -92,31 +103,23 @@
// Verify that the BufferReleaseChannel consume returns WOULD_BLOCK when there's no message
// available.
-TEST(BufferReleaseChannelTest, ConsumerEndpointIsNonBlocking) {
- std::unique_ptr<BufferReleaseChannel::ConsumerEndpoint> consumer;
- std::shared_ptr<BufferReleaseChannel::ProducerEndpoint> producer;
- ASSERT_EQ(OK, BufferReleaseChannel::open("test-channel"s, consumer, producer));
-
+TEST_F(BufferReleaseChannelTest, ConsumerEndpointIsNonBlocking) {
ReleaseCallbackId releaseCallbackId;
sp<Fence> releaseFence;
uint32_t maxAcquiredBufferCount;
ASSERT_EQ(WOULD_BLOCK,
- consumer->readReleaseFence(releaseCallbackId, releaseFence, maxAcquiredBufferCount));
+ mConsumer->readReleaseFence(releaseCallbackId, releaseFence, maxAcquiredBufferCount));
}
// Verify that we can write a message to the BufferReleaseChannel producer and read that message
// using the BufferReleaseChannel consumer.
-TEST(BufferReleaseChannelTest, ProduceAndConsume) {
- std::unique_ptr<BufferReleaseChannel::ConsumerEndpoint> consumer;
- std::shared_ptr<BufferReleaseChannel::ProducerEndpoint> producer;
- ASSERT_EQ(OK, BufferReleaseChannel::open("test-channel"s, consumer, producer));
-
+TEST_F(BufferReleaseChannelTest, ProduceAndConsume) {
sp<Fence> fence = sp<Fence>::make(memfd_create("fake-fence-fd", 0));
for (uint64_t i = 0; i < 64; i++) {
ReleaseCallbackId producerId{i, i + 1};
uint32_t maxAcquiredBufferCount = i + 2;
- ASSERT_EQ(OK, producer->writeReleaseFence(producerId, fence, maxAcquiredBufferCount));
+ ASSERT_EQ(OK, mProducer->writeReleaseFence(producerId, fence, maxAcquiredBufferCount));
}
for (uint64_t i = 0; i < 64; i++) {
@@ -127,7 +130,7 @@
sp<Fence> consumerFence;
uint32_t maxAcquiredBufferCount;
ASSERT_EQ(OK,
- consumer->readReleaseFence(consumerId, consumerFence, maxAcquiredBufferCount));
+ mConsumer->readReleaseFence(consumerId, consumerFence, maxAcquiredBufferCount));
ASSERT_EQ(expectedId, consumerId);
ASSERT_TRUE(is_same_file(fence->get(), consumerFence->get()));
@@ -135,4 +138,16 @@
}
}
+// Verify that BufferReleaseChannel::ConsumerEndpoint's socket can't be written to.
+TEST_F(BufferReleaseChannelTest, ConsumerSocketReadOnly) {
+ uint64_t data = 0;
+ ASSERT_EQ(-1, write(mConsumer->getFd().get(), &data, sizeof(uint64_t)));
+ ASSERT_EQ(errno, EPIPE);
+}
+
+// Verify that BufferReleaseChannel::ProducerEndpoint's socket can't be read from.
+TEST_F(BufferReleaseChannelTest, ProducerSocketWriteOnly) {
+ ASSERT_EQ(0, read(mProducer->getFd().get(), nullptr, sizeof(uint64_t)));
+}
+
} // namespace android
\ No newline at end of file
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index 7d0b512..a481d12 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -294,7 +294,7 @@
transactionBody) {
SurfaceComposerClient::Transaction t;
transactionBody(t, mSurfaceControl);
- t.apply(true);
+ t.apply(/*synchronously=*/true);
}
virtual void showAt(int x, int y, Rect crop = Rect(0, 0, 100, 100)) {
@@ -307,7 +307,7 @@
t.setAlpha(mSurfaceControl, 1);
auto reportedListener = sp<SynchronousWindowInfosReportedListener>::make();
t.addWindowInfosReportedListener(reportedListener);
- t.apply();
+ t.apply(/*synchronously=*/true);
reportedListener->wait();
}
@@ -319,7 +319,7 @@
request.timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
request.displayId = displayId.val();
t.setFocusedWindow(request);
- t.apply(true);
+ t.apply(/*synchronously=*/true);
}
public:
@@ -363,7 +363,7 @@
transactionBody) override {
SurfaceComposerClient::Transaction t;
transactionBody(t, mParentSurfaceControl);
- t.apply(true);
+ t.apply(/*synchronously=*/true);
}
void showAt(int x, int y, Rect crop = Rect(0, 0, 100, 100)) override {
@@ -377,7 +377,7 @@
t.setInputWindowInfo(mSurfaceControl, mInputInfo);
t.setCrop(mSurfaceControl, crop);
t.setAlpha(mSurfaceControl, 1);
- t.apply(true);
+ t.apply(/*synchronously=*/true);
}
private:
@@ -417,7 +417,7 @@
BufferUsage::COMPOSER_OVERLAY | BufferUsage::GPU_TEXTURE;
sp<GraphicBuffer> buffer =
new GraphicBuffer(w, h, PIXEL_FORMAT_RGBA_8888, 1, usageFlags, "test");
- Transaction().setBuffer(layer, buffer).apply(true);
+ Transaction().setBuffer(layer, buffer).apply(/*synchronously=*/true);
usleep(mBufferPostDelay);
}
@@ -1207,7 +1207,7 @@
t.setDisplayLayerStack(token, layerStack);
t.setDisplayProjection(token, ui::ROTATION_0, {0, 0, width, height},
{offsetX, offsetY, offsetX + width, offsetY + height});
- t.apply(true);
+ t.apply(/*synchronously=*/true);
mVirtualDisplays.push_back(token);
}
diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp
index f97eed5..ac3a832 100644
--- a/libs/nativewindow/ANativeWindow.cpp
+++ b/libs/nativewindow/ANativeWindow.cpp
@@ -263,6 +263,16 @@
return native_window_set_frame_rate(window, frameRate, compatibility, changeFrameRateStrategy);
}
+int32_t ANativeWindow_setFrameRateParams(
+ ANativeWindow* window, float desiredMinRate, float desiredMaxRate, float fixedSourceRate,
+ ANativeWindow_ChangeFrameRateStrategy changeFrameRateStrategy) {
+ if (!window || !query(window, NATIVE_WINDOW_IS_VALID)) {
+ return -EINVAL;
+ }
+ return native_window_set_frame_rate_params(window, desiredMinRate, desiredMaxRate,
+ fixedSourceRate, changeFrameRateStrategy);
+}
+
/**************************************************************************************************
* vndk-stable
**************************************************************************************************/
diff --git a/libs/nativewindow/include/android/native_window.h b/libs/nativewindow/include/android/native_window.h
index be6623e..bd8d67a 100644
--- a/libs/nativewindow/include/android/native_window.h
+++ b/libs/nativewindow/include/android/native_window.h
@@ -33,8 +33,8 @@
#ifndef ANDROID_NATIVE_WINDOW_H
#define ANDROID_NATIVE_WINDOW_H
-#include <stdint.h>
#include <stdbool.h>
+#include <stdint.h>
#include <sys/cdefs.h>
#include <android/data_space.h>
@@ -282,7 +282,7 @@
void ANativeWindow_tryAllocateBuffers(ANativeWindow* window) __INTRODUCED_IN(30);
/** Change frame rate strategy value for ANativeWindow_setFrameRate. */
-enum ANativeWindow_ChangeFrameRateStrategy {
+typedef enum ANativeWindow_ChangeFrameRateStrategy : int8_t {
/**
* Change the frame rate only if the transition is going to be seamless.
*/
@@ -292,7 +292,7 @@
* i.e. with visual interruptions for the user.
*/
ANATIVEWINDOW_CHANGE_FRAME_RATE_ALWAYS = 1
-} __INTRODUCED_IN(31);
+} ANativeWindow_ChangeFrameRateStrategy __INTRODUCED_IN(31);
/**
* Sets the intended frame rate for this window.
@@ -345,6 +345,76 @@
__INTRODUCED_IN(31);
/**
+ * Sets the intended frame rate for this window.
+ *
+ * On devices that are capable of running the display at different frame rates,
+ * the system may choose a display refresh rate to better match this surface's frame
+ * rate. Usage of this API won't introduce frame rate throttling, or affect other
+ * aspects of the application's frame production pipeline. However, because the system
+ * may change the display refresh rate, calls to this function may result in changes
+ * to Choreographer callback timings, and changes to the time interval at which the
+ * system releases buffers back to the application.
+ *
+ * Note that this only has an effect for surfaces presented on the display. If this
+ * surface is consumed by something other than the system compositor, e.g. a media
+ * codec, this call has no effect.
+ *
+ * You can register for changes in the refresh rate using
+ * \a AChoreographer_registerRefreshRateCallback.
+ *
+ * See ANativeWindow_clearFrameRate().
+ *
+ * Available since API level 36.
+ *
+ * \param window pointer to an ANativeWindow object.
+ *
+ * \param desiredMinRate The desired minimum frame rate (inclusive) for the window, specifying that
+ * the surface prefers the device render rate to be at least `desiredMinRate`.
+ *
+ * <p>Set `desiredMinRate` = `desiredMaxRate` to indicate the surface prefers an exact frame rate.
+ *
+ * <p>Set `desiredMinRate` = 0 to indicate the window has no preference
+ * and any frame rate is acceptable.
+ *
+ * <p>The value should be greater than or equal to 0.
+ *
+ * \param desiredMaxRate The desired maximum frame rate (inclusive) for the window, specifying that
+ * the surface prefers the device render rate to be at most `desiredMaxRate`.
+ *
+ * <p>Set `desiredMaxRate` = `desiredMinRate` to indicate the surface prefers an exact frame rate.
+ *
+ * <p>Set `desiredMaxRate` = positive infinity to indicate the window has no preference
+ * and any frame rate is acceptable.
+ *
+ * <p>The value should be greater than or equal to `desiredMinRate`.
+ *
+ * \param fixedSourceRate The "fixed source" frame rate of the window if the content has an
+ * inherently fixed frame rate, e.g. a video that has a specific frame rate.
+ *
+ * <p>When the frame rate chosen for the surface is the `fixedSourceRate` or a
+ * multiple, the surface can render without frame pulldown, for optimal smoothness. For
+ * example, a 30 fps video (`fixedSourceRate`=30) renders just as smoothly on 30 fps,
+ * 60 fps, 90 fps, 120 fps, and so on.
+ *
+ * <p>Setting the fixed source rate can also be used together with a desired
+ * frame rate min and max via setting `desiredMinRate` and `desiredMaxRate`. This still
+ * means the window's content has a fixed frame rate of `fixedSourceRate`, but additionally
+ * specifies the preference to be in the range [`desiredMinRate`, `desiredMaxRate`]. For example, an
+ * app might want to specify there is 30 fps video (`fixedSourceRate`=30) as well as a smooth
+ * animation on the same window which looks good when drawing within a frame rate range such as
+ * [`desiredMinRate`, `desiredMaxRate`] = [60,120].
+ *
+ * \param changeFrameRateStrategy Whether display refresh rate transitions caused by this surface
+ * should be seamless. A seamless transition is one that doesn't have any visual interruptions, such
+ * as a black screen for a second or two.
+ *
+ * \return 0 for success, -EINVAL if the arguments are invalid.
+ */
+int32_t ANativeWindow_setFrameRateParams(
+ ANativeWindow* window, float desiredMinRate, float desiredMaxRate, float fixedSourceRate,
+ ANativeWindow_ChangeFrameRateStrategy changeFrameRateStrategy) __INTRODUCED_IN(36);
+
+/**
* Clears the frame rate which is set for this window.
*
* This is equivalent to calling
@@ -366,14 +436,13 @@
*
* See ANativeWindow_setFrameRateWithChangeStrategy().
*
- * Available since API level 34.
+ * Available since API level 31.
*
* \param window pointer to an ANativeWindow object.
*
* \return 0 for success, -EINVAL if the window value is invalid.
*/
-inline int32_t ANativeWindow_clearFrameRate(ANativeWindow* window)
- __INTRODUCED_IN(__ANDROID_API_U__) {
+inline int32_t ANativeWindow_clearFrameRate(ANativeWindow* window) __INTRODUCED_IN(31) {
return ANativeWindow_setFrameRateWithChangeStrategy(window, 0,
ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT,
ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS);
diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h
index 33c303a..05f49ad 100644
--- a/libs/nativewindow/include/system/window.h
+++ b/libs/nativewindow/include/system/window.h
@@ -1156,6 +1156,23 @@
(int)compatibility, (int)changeFrameRateStrategy);
}
+static inline int native_window_set_frame_rate_params(struct ANativeWindow* window,
+ float desiredMinRate, float desiredMaxRate,
+ float fixedSourceRate,
+ int8_t changeFrameRateStrategy) {
+ // TODO(b/362798998): Fix plumbing to send whole params
+ int compatibility = fixedSourceRate == 0 ? ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT
+ : ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE;
+ double frameRate = compatibility == ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE
+ ? fixedSourceRate
+ : desiredMinRate;
+ if (desiredMaxRate < desiredMinRate) {
+ return -EINVAL;
+ }
+ return window->perform(window, NATIVE_WINDOW_SET_FRAME_RATE, frameRate, compatibility,
+ changeFrameRateStrategy);
+}
+
struct ANativeWindowFrameTimelineInfo {
// Frame Id received from ANativeWindow_getNextFrameId.
uint64_t frameNumber;
diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt
index e29d5a6..071e354 100644
--- a/libs/nativewindow/libnativewindow.map.txt
+++ b/libs/nativewindow/libnativewindow.map.txt
@@ -53,6 +53,7 @@
ANativeWindow_setBuffersTransform;
ANativeWindow_setDequeueTimeout; # systemapi introduced=30
ANativeWindow_setFrameRate; # introduced=30
+ ANativeWindow_setFrameRateParams; # introduced=36
ANativeWindow_setFrameRateWithChangeStrategy; # introduced=31
ANativeWindow_setSharedBufferMode; # llndk
ANativeWindow_setSwapInterval; # llndk
diff --git a/services/powermanager/tests/PowerHalWrapperAidlTest.cpp b/services/powermanager/tests/PowerHalWrapperAidlTest.cpp
index 1589c99..f5c4fc5 100644
--- a/services/powermanager/tests/PowerHalWrapperAidlTest.cpp
+++ b/services/powermanager/tests/PowerHalWrapperAidlTest.cpp
@@ -35,6 +35,7 @@
using aidl::android::hardware::power::Mode;
using aidl::android::hardware::power::SessionConfig;
using aidl::android::hardware::power::SessionTag;
+using aidl::android::hardware::power::SupportInfo;
using android::binder::Status;
using namespace android;
@@ -65,6 +66,7 @@
(int32_t tgid, int32_t uid, ChannelConfig* _aidl_return), (override));
MOCK_METHOD(ndk::ScopedAStatus, closeSessionChannel, (int32_t tgid, int32_t uid), (override));
MOCK_METHOD(ndk::ScopedAStatus, getHintSessionPreferredRate, (int64_t * rate), (override));
+ MOCK_METHOD(ndk::ScopedAStatus, getSupportInfo, (SupportInfo * _aidl_return), (override));
MOCK_METHOD(ndk::ScopedAStatus, getInterfaceVersion, (int32_t * version), (override));
MOCK_METHOD(ndk::ScopedAStatus, getInterfaceHash, (std::string * hash), (override));
MOCK_METHOD(ndk::SpAIBinder, asBinder, (), (override));
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index e176569..f1c79c1 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -284,7 +284,6 @@
],
static_libs: [
"android.frameworks.displayservice@1.0",
- "libc++fs",
"libdisplayservicehidl",
"libserviceutils",
],
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index c88092b..20ba45f 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -689,8 +689,20 @@
listener->onReleaseBuffer(callbackId, fence, currentMaxAcquiredBufferCount);
}
- if (mBufferReleaseChannel) {
- mBufferReleaseChannel->writeReleaseFence(callbackId, fence, currentMaxAcquiredBufferCount);
+ if (!mBufferReleaseChannel) {
+ return;
+ }
+
+ status_t status = mBufferReleaseChannel->writeReleaseFence(callbackId, fence,
+ currentMaxAcquiredBufferCount);
+ if (status != OK) {
+ int error = -status;
+ // callReleaseBufferCallback is called during Layer's destructor. In this case, it's
+ // expected to receive connection errors.
+ if (error != EPIPE && error != ECONNRESET) {
+ ALOGD("[%s] writeReleaseFence failed. error %d (%s)", getDebugName(), error,
+ strerror(error));
+ }
}
}
diff --git a/services/surfaceflinger/TransactionCallbackInvoker.cpp b/services/surfaceflinger/TransactionCallbackInvoker.cpp
index de4825b..b22ec66 100644
--- a/services/surfaceflinger/TransactionCallbackInvoker.cpp
+++ b/services/surfaceflinger/TransactionCallbackInvoker.cpp
@@ -144,7 +144,7 @@
eventStats, handle->previousReleaseCallbackId);
if (handle->bufferReleaseChannel &&
handle->previousReleaseCallbackId != ReleaseCallbackId::INVALID_ID) {
- mBufferReleases.emplace_back(handle->bufferReleaseChannel,
+ mBufferReleases.emplace_back(handle->name, handle->bufferReleaseChannel,
handle->previousReleaseCallbackId,
handle->previousReleaseFence,
handle->currentMaxAcquiredBufferCount);
@@ -159,8 +159,13 @@
void TransactionCallbackInvoker::sendCallbacks(bool onCommitOnly) {
for (const auto& bufferRelease : mBufferReleases) {
- bufferRelease.channel->writeReleaseFence(bufferRelease.callbackId, bufferRelease.fence,
- bufferRelease.currentMaxAcquiredBufferCount);
+ status_t status = bufferRelease.channel
+ ->writeReleaseFence(bufferRelease.callbackId, bufferRelease.fence,
+ bufferRelease.currentMaxAcquiredBufferCount);
+ if (status != OK) {
+ ALOGE("[%s] writeReleaseFence failed. error %d (%s)", bufferRelease.layerName.c_str(),
+ -status, strerror(-status));
+ }
}
mBufferReleases.clear();
diff --git a/services/surfaceflinger/TransactionCallbackInvoker.h b/services/surfaceflinger/TransactionCallbackInvoker.h
index d81d8d0..178ddbb 100644
--- a/services/surfaceflinger/TransactionCallbackInvoker.h
+++ b/services/surfaceflinger/TransactionCallbackInvoker.h
@@ -83,6 +83,7 @@
mCompletedTransactions;
struct BufferRelease {
+ std::string layerName;
std::shared_ptr<gui::BufferReleaseChannel::ProducerEndpoint> channel;
ReleaseCallbackId callbackId;
sp<Fence> fence;
diff --git a/services/surfaceflinger/fuzzer/Android.bp b/services/surfaceflinger/fuzzer/Android.bp
index 3582d38..1de6b4a 100644
--- a/services/surfaceflinger/fuzzer/Android.bp
+++ b/services/surfaceflinger/fuzzer/Android.bp
@@ -28,7 +28,6 @@
cc_defaults {
name: "surfaceflinger_fuzz_defaults",
static_libs: [
- "libc++fs",
"libsurfaceflinger_common",
],
srcs: [
diff --git a/services/surfaceflinger/tests/tracing/Android.bp b/services/surfaceflinger/tests/tracing/Android.bp
index bce1406..6eb7f4a 100644
--- a/services/surfaceflinger/tests/tracing/Android.bp
+++ b/services/surfaceflinger/tests/tracing/Android.bp
@@ -35,9 +35,6 @@
":libsurfaceflinger_mock_sources",
"TransactionTraceTestSuite.cpp",
],
- static_libs: [
- "libc++fs",
- ],
header_libs: [
"libsurfaceflinger_mocks_headers",
],
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 8269fcb..cb8820a 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -81,7 +81,6 @@
"surfaceflinger_defaults",
],
test_suites: ["device-tests"],
- static_libs: ["libc++fs"],
header_libs: ["surfaceflinger_tests_common_headers"],
srcs: [
":libsurfaceflinger_backend_mock_sources",
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPower.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPower.h
index ed1405b..4c034d7 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPower.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPower.h
@@ -32,6 +32,7 @@
using aidl::android::hardware::power::IPowerHintSession;
using aidl::android::hardware::power::SessionConfig;
using aidl::android::hardware::power::SessionTag;
+using aidl::android::hardware::power::SupportInfo;
using aidl::android::hardware::power::Mode;
using android::binder::Status;
@@ -59,6 +60,7 @@
MOCK_METHOD(ndk::ScopedAStatus, getSessionChannel,
(int32_t tgid, int32_t uid, ChannelConfig* _aidl_return), (override));
MOCK_METHOD(ndk::ScopedAStatus, closeSessionChannel, (int32_t tgid, int32_t uid), (override));
+ MOCK_METHOD(ndk::ScopedAStatus, getSupportInfo, (SupportInfo * _aidl_return), (override));
MOCK_METHOD(ndk::ScopedAStatus, getInterfaceVersion, (int32_t * version), (override));
MOCK_METHOD(ndk::ScopedAStatus, getInterfaceHash, (std::string * hash), (override));
MOCK_METHOD(ndk::SpAIBinder, asBinder, (), (override));