Revert "Introduce SurfaceFlinger Queued Transaction"
This reverts commit dca14285b538820ab5164014c2913b118ed0a8ff.
Reason for revert: b/177355824
Bug: 177355824
Change-Id: Idbca13d2040b0d8e96fb7747bf5534f8c3feb08e
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 59b3824..44c7f96 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1914,17 +1914,19 @@
bool SurfaceFlinger::handleMessageTransaction() {
ATRACE_CALL();
-
- if (getTransactionFlags(eTransactionFlushNeeded)) {
- flushPendingTransactionQueues();
- flushTransactionQueue();
- }
uint32_t transactionFlags = peekTransactionFlags();
+
+ bool flushedATransaction = flushTransactionQueues();
+
bool runHandleTransaction =
- ((transactionFlags & (~eTransactionFlushNeeded)) != 0) || mForceTraversal;
+ (transactionFlags && (transactionFlags != eTransactionFlushNeeded)) ||
+ flushedATransaction ||
+ mForceTraversal;
if (runHandleTransaction) {
handleTransaction(eTransactionMask);
+ } else {
+ getTransactionFlags(eTransactionFlushNeeded);
}
if (transactionFlushNeeded()) {
@@ -2826,6 +2828,7 @@
});
}
+ commitInputWindowCommands();
commitTransaction();
}
@@ -2866,6 +2869,11 @@
: nullptr);
}
+void SurfaceFlinger::commitInputWindowCommands() {
+ mInputWindowCommands.merge(mPendingInputWindowCommands);
+ mPendingInputWindowCommands.clear();
+}
+
void SurfaceFlinger::updateCursorAsync() {
compositionengine::CompositionRefreshArgs refreshArgs;
for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) {
@@ -3229,55 +3237,55 @@
mForceTraversal = true;
}
-void SurfaceFlinger::flushPendingTransactionQueues() {
+bool SurfaceFlinger::flushTransactionQueues() {
// to prevent onHandleDestroyed from being called while the lock is held,
// we must keep a copy of the transactions (specifically the composer
// states) around outside the scope of the lock
std::vector<const TransactionState> transactions;
+ bool flushedATransaction = false;
{
- Mutex::Autolock _l(mQueueLock);
+ Mutex::Autolock _l(mStateLock);
- auto it = mPendingTransactionQueues.begin();
- while (it != mPendingTransactionQueues.end()) {
+ auto it = mTransactionQueues.begin();
+ while (it != mTransactionQueues.end()) {
auto& [applyToken, transactionQueue] = *it;
while (!transactionQueue.empty()) {
const auto& transaction = transactionQueue.front();
if (!transactionIsReadyToBeApplied(transaction.desiredPresentTime,
transaction.states)) {
+ setTransactionFlags(eTransactionFlushNeeded);
break;
}
transactions.push_back(transaction);
+ applyTransactionState(transaction.frameTimelineVsyncId, transaction.states,
+ transaction.displays, transaction.flags,
+ mPendingInputWindowCommands, transaction.desiredPresentTime,
+ transaction.isAutoTimestamp, transaction.buffer,
+ transaction.postTime, transaction.privileged,
+ transaction.hasListenerCallbacks,
+ transaction.listenerCallbacks, transaction.originPid,
+ transaction.originUid, transaction.id, /*isMainThread*/ true);
transactionQueue.pop();
+ flushedATransaction = true;
}
if (transactionQueue.empty()) {
- it = mPendingTransactionQueues.erase(it);
- mTransactionQueueCV.broadcast();
+ it = mTransactionQueues.erase(it);
+ mTransactionCV.broadcast();
} else {
it = std::next(it, 1);
}
}
}
-
- {
- Mutex::Autolock _l(mStateLock);
- for (const auto& transaction : transactions) {
- applyTransactionState(transaction.frameTimelineVsyncId, transaction.states,
- transaction.displays, transaction.flags, mInputWindowCommands,
- transaction.desiredPresentTime, transaction.isAutoTimestamp,
- transaction.buffer, transaction.postTime, transaction.privileged,
- transaction.hasListenerCallbacks, transaction.listenerCallbacks,
- transaction.originPid, transaction.originUid, transaction.id);
- }
- }
+ return flushedATransaction;
}
bool SurfaceFlinger::transactionFlushNeeded() {
- Mutex::Autolock _l(mQueueLock);
- return !mPendingTransactionQueues.empty();
+ return !mTransactionQueues.empty();
}
+
bool SurfaceFlinger::transactionIsReadyToBeApplied(int64_t desiredPresentTime,
const Vector<ComposerState>& states,
bool updateTransactionCounters) {
@@ -3299,8 +3307,6 @@
if (s.acquireFence && s.acquireFence->getStatus() == Fence::Status::Unsignaled) {
ready = false;
}
-
- Mutex::Autolock _l(mStateLock);
sp<Layer> layer = nullptr;
if (s.surface) {
layer = fromHandleLocked(s.surface).promote();
@@ -3313,8 +3319,9 @@
ready = false;
}
if (updateTransactionCounters) {
- // See BufferStateLayer::mPendingBufferTransactions
- if (layer) layer->incrementPendingBufferCount();
+ // See BufferStateLayer::mPendingBufferTransactions
+ if (layer) layer->incrementPendingBufferCount();
+
}
}
return ready;
@@ -3331,153 +3338,90 @@
const int64_t postTime = systemTime();
bool privileged = callingThreadHasUnscopedSurfaceFlingerAccess();
- {
- Mutex::Autolock _l(mQueueLock);
- // If its TransactionQueue already has a pending TransactionState or if it is pending
- auto itr = mPendingTransactionQueues.find(applyToken);
- // if this is an animation frame, wait until prior animation frame has
- // been applied by SF
- if (flags & eAnimation) {
- while (itr != mPendingTransactionQueues.end() ||
- (!mTransactionQueue.empty() && mAnimTransactionPending)) {
- status_t err = mTransactionQueueCV.waitRelative(mQueueLock, s2ns(5));
- if (CC_UNLIKELY(err != NO_ERROR)) {
- ALOGW_IF(err == TIMED_OUT,
- "setTransactionState timed out "
- "waiting for animation frame to apply");
- break;
- }
- itr = mPendingTransactionQueues.find(applyToken);
+ Mutex::Autolock _l(mStateLock);
+
+ // If its TransactionQueue already has a pending TransactionState or if it is pending
+ auto itr = mTransactionQueues.find(applyToken);
+ // if this is an animation frame, wait until prior animation frame has
+ // been applied by SF
+ if (flags & eAnimation) {
+ while (itr != mTransactionQueues.end()) {
+ status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5));
+ if (CC_UNLIKELY(err != NO_ERROR)) {
+ ALOGW_IF(err == TIMED_OUT,
+ "setTransactionState timed out "
+ "waiting for animation frame to apply");
+ break;
}
+ itr = mTransactionQueues.find(applyToken);
}
-
- const bool pendingTransactions = itr != mPendingTransactionQueues.end();
- // Expected present time is computed and cached on invalidate, so it may be stale.
- if (!pendingTransactions) {
- const auto now = systemTime();
- const bool nextVsyncPending = now < mExpectedPresentTime.load();
- const DisplayStatInfo stats = mScheduler->getDisplayStatInfo(now);
- mExpectedPresentTime = calculateExpectedPresentTime(stats);
- // The transaction might arrive just before the next vsync but after
- // invalidate was called. In that case we need to get the next vsync
- // afterwards.
- if (nextVsyncPending) {
- mExpectedPresentTime += stats.vsyncPeriod;
- }
- }
-
- // TODO(b/159125966): Remove eEarlyWakeup completly as no client should use this flag
- if (flags & eEarlyWakeup) {
- ALOGW("eEarlyWakeup is deprecated. Use eExplicitEarlyWakeup[Start|End]");
- }
-
- if (!privileged && (flags & (eExplicitEarlyWakeupStart | eExplicitEarlyWakeupEnd))) {
- ALOGE("Only WindowManager is allowed to use eExplicitEarlyWakeup[Start|End] flags");
- flags &= ~(eExplicitEarlyWakeupStart | eExplicitEarlyWakeupEnd);
- }
-
- IPCThreadState* ipc = IPCThreadState::self();
- const int originPid = ipc->getCallingPid();
- const int originUid = ipc->getCallingUid();
-
- // Call transactionIsReadyToBeApplied first in case we need to incrementPendingBufferCount
- // if the transaction contains a buffer.
- if (!transactionIsReadyToBeApplied(isAutoTimestamp ? 0 : desiredPresentTime, states,
- true) ||
- pendingTransactions) {
- mPendingTransactionQueues[applyToken].emplace(frameTimelineVsyncId, states, displays,
- flags, inputWindowCommands,
- desiredPresentTime, isAutoTimestamp,
- uncacheBuffer, postTime, privileged,
- hasListenerCallbacks, listenerCallbacks,
- originPid, originUid, transactionId);
-
- setTransactionFlags(eTransactionFlushNeeded);
- return NO_ERROR;
- }
-
- mTransactionQueue.emplace_back(frameTimelineVsyncId, states, displays, flags,
- inputWindowCommands, desiredPresentTime, isAutoTimestamp,
- uncacheBuffer, postTime, privileged, hasListenerCallbacks,
- listenerCallbacks, originPid, originUid, transactionId);
}
- const auto schedule = [](uint32_t flags) {
- if (flags & eEarlyWakeup) return TransactionSchedule::Early;
- if (flags & eExplicitEarlyWakeupEnd) return TransactionSchedule::EarlyEnd;
- if (flags & eExplicitEarlyWakeupStart) return TransactionSchedule::EarlyStart;
- return TransactionSchedule::Late;
- }(flags);
- setTransactionFlags(eTransactionFlushNeeded, schedule);
+ const bool pendingTransactions = itr != mTransactionQueues.end();
+ // Expected present time is computed and cached on invalidate, so it may be stale.
+ if (!pendingTransactions) {
+ const auto now = systemTime();
+ const bool nextVsyncPending = now < mExpectedPresentTime.load();
+ const DisplayStatInfo stats = mScheduler->getDisplayStatInfo(now);
+ mExpectedPresentTime = calculateExpectedPresentTime(stats);
+ // The transaction might arrive just before the next vsync but after
+ // invalidate was called. In that case we need to get the next vsync
+ // afterwards.
+ if (nextVsyncPending) {
+ mExpectedPresentTime += stats.vsyncPeriod;
+ }
+ }
- // if this is a synchronous transaction, wait for it to take effect
- // before returning.
- const bool synchronous = flags & eSynchronous;
- const bool syncInput = inputWindowCommands.syncInputWindows;
- if (!synchronous && !syncInput) {
+ IPCThreadState* ipc = IPCThreadState::self();
+ const int originPid = ipc->getCallingPid();
+ const int originUid = ipc->getCallingUid();
+
+ // Call transactionIsReadyToBeApplied first in case we need to incrementPendingBufferCount
+ // if the transaction contains a buffer.
+ if (!transactionIsReadyToBeApplied(isAutoTimestamp ? 0 : desiredPresentTime, states, true) ||
+ pendingTransactions) {
+ mTransactionQueues[applyToken].emplace(frameTimelineVsyncId, states, displays, flags,
+ desiredPresentTime, isAutoTimestamp, uncacheBuffer,
+ postTime, privileged, hasListenerCallbacks,
+ listenerCallbacks, originPid, originUid,
+ transactionId);
+ setTransactionFlags(eTransactionFlushNeeded);
return NO_ERROR;
}
- // Handle synchronous cases.
- {
- Mutex::Autolock _l(mStateLock);
- if (synchronous) {
- mTransactionPending = true;
- }
- if (syncInput) {
- mPendingSyncInputWindows = true;
- }
+ applyTransactionState(frameTimelineVsyncId, states, displays, flags, inputWindowCommands,
+ desiredPresentTime, isAutoTimestamp, uncacheBuffer, postTime, privileged,
+ hasListenerCallbacks, listenerCallbacks, originPid, originUid,
+ transactionId, /*isMainThread*/ false);
+ return NO_ERROR;
+}
- // applyTransactionState can be called by either the main SF thread or by
- // another process through setTransactionState. While a given process may wish
- // to wait on synchronous transactions, the main SF thread should never
- // be blocked. Therefore, we only wait if isMainThread is false.
- while (mTransactionPending || mPendingSyncInputWindows) {
+void SurfaceFlinger::applyTransactionState(
+ int64_t frameTimelineVsyncId, const Vector<ComposerState>& states,
+ const Vector<DisplayState>& displays, uint32_t flags,
+ const InputWindowCommands& inputWindowCommands, const int64_t desiredPresentTime,
+ bool isAutoTimestamp, const client_cache_t& uncacheBuffer, const int64_t postTime,
+ bool privileged, bool hasListenerCallbacks,
+ const std::vector<ListenerCallbacks>& listenerCallbacks, int originPid, int originUid,
+ uint64_t transactionId, bool isMainThread) {
+ uint32_t transactionFlags = 0;
+
+ if (flags & eAnimation) {
+ // For window updates that are part of an animation we must wait for
+ // previous animation "frames" to be handled.
+ while (!isMainThread && mAnimTransactionPending) {
status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5));
if (CC_UNLIKELY(err != NO_ERROR)) {
// just in case something goes wrong in SF, return to the
- // called after a few seconds.
- ALOGW_IF(err == TIMED_OUT, "setTransactionState timed out!");
- mTransactionPending = false;
- mPendingSyncInputWindows = false;
+ // caller after a few seconds.
+ ALOGW_IF(err == TIMED_OUT, "setTransactionState timed out "
+ "waiting for previous animation frame");
+ mAnimTransactionPending = false;
break;
}
}
}
- return NO_ERROR;
-}
-
-void SurfaceFlinger::flushTransactionQueue() {
- std::vector<TransactionState> transactionQueue;
- {
- Mutex::Autolock _l(mQueueLock);
- if (!mTransactionQueue.empty()) {
- transactionQueue.swap(mTransactionQueue);
- }
- mTransactionQueueCV.broadcast();
- }
-
- Mutex::Autolock _l(mStateLock);
- for (const auto& t : transactionQueue) {
- applyTransactionState(t.frameTimelineVsyncId, t.states, t.displays, t.flags,
- t.inputWindowCommands, t.desiredPresentTime, t.isAutoTimestamp,
- t.buffer, t.postTime, t.privileged, t.hasListenerCallbacks,
- t.listenerCallbacks, t.originPid, t.originUid, t.id);
- }
-}
-
-void SurfaceFlinger::applyTransactionState(int64_t frameTimelineVsyncId,
- const Vector<ComposerState>& states,
- const Vector<DisplayState>& displays, uint32_t flags,
- const InputWindowCommands& inputWindowCommands,
- const int64_t desiredPresentTime, bool isAutoTimestamp,
- const client_cache_t& uncacheBuffer,
- const int64_t postTime, bool privileged,
- bool hasListenerCallbacks,
- const std::vector<ListenerCallbacks>& listenerCallbacks,
- int originPid, int originUid, uint64_t transactionId) {
- uint32_t transactionFlags = 0;
for (const DisplayState& display : displays) {
transactionFlags |= setDisplayStateLocked(display);
@@ -3536,25 +3480,80 @@
transactionFlags = eTransactionNeeded;
}
+ // If we are on the main thread, we are about to preform a traversal. Clear the traversal bit
+ // so we don't have to wake up again next frame to preform an uneeded traversal.
+ if (isMainThread && (transactionFlags & eTraversalNeeded)) {
+ transactionFlags = transactionFlags & (~eTraversalNeeded);
+ mForceTraversal = true;
+ }
+
+ const auto schedule = [](uint32_t flags) {
+ if (flags & eEarlyWakeup) return TransactionSchedule::Early;
+ if (flags & eExplicitEarlyWakeupEnd) return TransactionSchedule::EarlyEnd;
+ if (flags & eExplicitEarlyWakeupStart) return TransactionSchedule::EarlyStart;
+ return TransactionSchedule::Late;
+ }(flags);
+
if (transactionFlags) {
if (mInterceptor->isEnabled()) {
mInterceptor->saveTransaction(states, mCurrentState.displays, displays, flags,
originPid, originUid, transactionId);
}
- // We are on the main thread, we are about to preform a traversal. Clear the traversal bit
- // so we don't have to wake up again next frame to preform an unnecessary traversal.
- if (transactionFlags & eTraversalNeeded) {
- transactionFlags = transactionFlags & (~eTraversalNeeded);
- mForceTraversal = true;
+ // TODO(b/159125966): Remove eEarlyWakeup completly as no client should use this flag
+ if (flags & eEarlyWakeup) {
+ ALOGW("eEarlyWakeup is deprecated. Use eExplicitEarlyWakeup[Start|End]");
}
- if (transactionFlags) {
- setTransactionFlags(transactionFlags);
+
+ if (!privileged && (flags & (eExplicitEarlyWakeupStart | eExplicitEarlyWakeupEnd))) {
+ ALOGE("Only WindowManager is allowed to use eExplicitEarlyWakeup[Start|End] flags");
+ flags &= ~(eExplicitEarlyWakeupStart | eExplicitEarlyWakeupEnd);
}
+ // this triggers the transaction
+ setTransactionFlags(transactionFlags, schedule);
+
if (flags & eAnimation) {
mAnimTransactionPending = true;
}
+
+ // if this is a synchronous transaction, wait for it to take effect
+ // before returning.
+ const bool synchronous = flags & eSynchronous;
+ const bool syncInput = inputWindowCommands.syncInputWindows;
+ if (!synchronous && !syncInput) {
+ return;
+ }
+
+ if (synchronous) {
+ mTransactionPending = true;
+ }
+ if (syncInput) {
+ mPendingSyncInputWindows = true;
+ }
+
+
+ // applyTransactionState can be called by either the main SF thread or by
+ // another process through setTransactionState. While a given process may wish
+ // to wait on synchronous transactions, the main SF thread should never
+ // be blocked. Therefore, we only wait if isMainThread is false.
+ while (!isMainThread && (mTransactionPending || mPendingSyncInputWindows)) {
+ status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5));
+ if (CC_UNLIKELY(err != NO_ERROR)) {
+ // just in case something goes wrong in SF, return to the
+ // called after a few seconds.
+ ALOGW_IF(err == TIMED_OUT, "setTransactionState timed out!");
+ mTransactionPending = false;
+ mPendingSyncInputWindows = false;
+ break;
+ }
+ }
+ } else {
+ // Update VsyncModulator state machine even if transaction is not needed.
+ if (schedule == TransactionSchedule::EarlyStart ||
+ schedule == TransactionSchedule::EarlyEnd) {
+ modulateVsync(&VsyncModulator::setTransactionSchedule, schedule);
+ }
}
}
@@ -3946,7 +3945,7 @@
}
uint32_t SurfaceFlinger::addInputWindowCommands(const InputWindowCommands& inputWindowCommands) {
- bool hasChanges = mInputWindowCommands.merge(inputWindowCommands);
+ bool hasChanges = mPendingInputWindowCommands.merge(inputWindowCommands);
return hasChanges ? eTraversalNeeded : 0;
}
@@ -4211,11 +4210,9 @@
d.width = 0;
d.height = 0;
displays.add(d);
-
- // This called on the main thread, apply it directly.
- applyTransactionState(ISurfaceComposer::INVALID_VSYNC_ID, state, displays, 0,
- mInputWindowCommands, systemTime(), true, {}, systemTime(), true, false,
- {}, getpid(), getuid(), 0 /* Undefined transactionId */);
+ setTransactionState(ISurfaceComposer::INVALID_VSYNC_ID, state, displays, 0, nullptr,
+ mPendingInputWindowCommands, systemTime(), true, {}, false, {},
+ 0 /* Undefined transactionId */);
setPowerModeInternal(display, hal::PowerMode::ON);
const nsecs_t vsyncPeriod = mRefreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod();
@@ -5392,7 +5389,7 @@
void SurfaceFlinger::repaintEverything() {
mRepaintEverything = true;
- setTransactionFlags(eTransactionNeeded);
+ signalTransaction();
}
void SurfaceFlinger::repaintEverythingForHWC() {