Loading services/surfaceflinger/SurfaceFlinger.cpp +146 −145 Original line number Diff line number Diff line Loading @@ -1896,18 +1896,19 @@ void SurfaceFlinger::onMessageInvalidate(int64_t vsyncId, nsecs_t expectedVSyncT bool SurfaceFlinger::handleMessageTransaction() { ATRACE_CALL(); uint32_t transactionFlags = peekTransactionFlags(); if (getTransactionFlags(eTransactionFlushNeeded)) { flushPendingTransactionQueues(); flushTransactionQueue(); } bool flushedATransaction = flushTransactionQueues(); uint32_t transactionFlags = peekTransactionFlags(); bool runHandleTransaction = (transactionFlags && (transactionFlags != eTransactionFlushNeeded)) || mForceTraversal; (transactionFlags && (transactionFlags != eTransactionFlushNeeded)) || flushedATransaction || mForceTraversal; if (runHandleTransaction) { handleTransaction(eTransactionMask); } else { getTransactionFlags(eTransactionFlushNeeded); } if (transactionFlushNeeded()) { Loading Loading @@ -2776,6 +2777,7 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) }); } commitInputWindowCommands(); commitTransaction(); } Loading Loading @@ -2816,6 +2818,11 @@ void SurfaceFlinger::updateInputWindowInfo() { : nullptr); } void SurfaceFlinger::commitInputWindowCommands() { mInputWindowCommands.merge(mPendingInputWindowCommands); mPendingInputWindowCommands.clear(); } void SurfaceFlinger::updateCursorAsync() { compositionengine::CompositionRefreshArgs refreshArgs; for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) { Loading Loading @@ -3168,52 +3175,50 @@ void SurfaceFlinger::setTraversalNeeded() { 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.states, transaction.displays, transaction.flags, mPendingInputWindowCommands, transaction.desiredPresentTime, transaction.buffer, transaction.postTime, transaction.privileged, transaction.hasListenerCallbacks, transaction.listenerCallbacks, transaction.originPID, transaction.originUID, /*isMainThread*/ true); transactionQueue.pop(); flushedATransaction = true; } if (transactionQueue.empty()) { it = mPendingTransactionQueues.erase(it); it = mTransactionQueues.erase(it); mTransactionCV.broadcast(); } else { it = std::next(it, 1); } } } { Mutex::Autolock _l(mStateLock); for (const auto& transaction : transactions) { applyTransactionState(transaction.states, transaction.displays, transaction.flags, mInputWindowCommands, transaction.desiredPresentTime, transaction.buffer, transaction.postTime, transaction.privileged, transaction.hasListenerCallbacks, transaction.listenerCallbacks, transaction.originPID, transaction.originUID); } } return flushedATransaction; } bool SurfaceFlinger::transactionFlushNeeded() { Mutex::Autolock _l(mQueueLock); return !mPendingTransactionQueues.empty(); return !mTransactionQueues.empty(); } Loading Loading @@ -3248,16 +3253,17 @@ status_t SurfaceFlinger::setTransactionState( ATRACE_CALL(); const int64_t postTime = systemTime(); bool privileged = callingThreadHasUnscopedSurfaceFlingerAccess(); { Mutex::Autolock _l(mQueueLock); Mutex::Autolock _l(mStateLock); // If its TransactionQueue already has a pending TransactionState or if it is pending auto itr = mPendingTransactionQueues.find(applyToken); 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 != mPendingTransactionQueues.end()) { while (itr != mTransactionQueues.end()) { status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5)); if (CC_UNLIKELY(err != NO_ERROR)) { ALOGW_IF(err == TIMED_OUT, Loading @@ -3265,21 +3271,11 @@ status_t SurfaceFlinger::setTransactionState( "waiting for animation frame to apply"); break; } itr = mPendingTransactionQueues.find(applyToken); itr = mTransactionQueues.find(applyToken); } } // 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); } const bool pendingTransactions = itr != mPendingTransactionQueues.end(); const bool pendingTransactions = itr != mTransactionQueues.end(); // Expected present time is computed and cached on invalidate, so it may be stale. if (!pendingTransactions) { mExpectedPresentTime = calculateExpectedPresentTime(systemTime()); Loading @@ -3290,92 +3286,43 @@ status_t SurfaceFlinger::setTransactionState( const int originUID = ipc->getCallingUid(); if (pendingTransactions || !transactionIsReadyToBeApplied(desiredPresentTime, states)) { mPendingTransactionQueues[applyToken].emplace(states, displays, flags, inputWindowCommands, desiredPresentTime, mTransactionQueues[applyToken].emplace(states, displays, flags, desiredPresentTime, uncacheBuffer, postTime, privileged, hasListenerCallbacks, listenerCallbacks, originPID, originUID); setTransactionFlags(eTransactionFlushNeeded); return NO_ERROR; } mTransactionQueue.emplace_back(states, displays, flags, inputWindowCommands, desiredPresentTime, uncacheBuffer, postTime, privileged, hasListenerCallbacks, listenerCallbacks, originPID, originUID); setTransactionFlags(eTransactionFlushNeeded); return NO_ERROR; } { Mutex::Autolock _l(mStateLock); 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 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) { setTransactionFlags(eTransactionFlushNeeded, schedule); applyTransactionState(states, displays, flags, inputWindowCommands, desiredPresentTime, uncacheBuffer, postTime, privileged, hasListenerCallbacks, listenerCallbacks, originPID, originUID, /*isMainThread*/ false); return NO_ERROR; } if (synchronous) { mTransactionPending = true; } if (syncInput) { mPendingSyncInputWindows = true; } setTransactionFlags(eTransactionFlushNeeded, schedule); void SurfaceFlinger::applyTransactionState( const Vector<ComposerState>& states, const Vector<DisplayState>& displays, uint32_t flags, const InputWindowCommands& inputWindowCommands, const int64_t desiredPresentTime, const client_cache_t& uncacheBuffer, const int64_t postTime, bool privileged, bool hasListenerCallbacks, const std::vector<ListenerCallbacks>& listenerCallbacks, int originPID, int originUID, bool isMainThread) { uint32_t transactionFlags = 0; // 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) { 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); } } Mutex::Autolock _l(mStateLock); for (const auto& t : transactionQueue) { applyTransactionState(t.states, t.displays, t.flags, t.inputWindowCommands, t.desiredPresentTime, t.buffer, t.postTime, t.privileged, t.hasListenerCallbacks, t.listenerCallbacks, t.originPID, t.originUID); } } void SurfaceFlinger::applyTransactionState( const Vector<ComposerState>& states, const Vector<DisplayState>& displays, uint32_t flags, const InputWindowCommands& inputWindowCommands, const int64_t desiredPresentTime, const client_cache_t& uncacheBuffer, const int64_t postTime, bool privileged, bool hasListenerCallbacks, const std::vector<ListenerCallbacks>& listenerCallbacks, int32_t originPID, int32_t originUID) { uint32_t transactionFlags = 0; for (const DisplayState& display : displays) { transactionFlags |= setDisplayStateLocked(display); Loading Loading @@ -3432,25 +3379,80 @@ void SurfaceFlinger::applyTransactionState( transactionFlags = eTransactionNeeded; } if (transactionFlags && mInterceptor->isEnabled()) { mInterceptor->saveTransaction(states, mCurrentState.displays, displays, flags, originPID, originUID); } // 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) { // 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); } // 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); } // this triggers the transaction setTransactionFlags(transactionFlags); 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); } } } Loading Loading @@ -3829,7 +3831,7 @@ uint32_t SurfaceFlinger::setClientStateLocked( } uint32_t SurfaceFlinger::addInputWindowCommands(const InputWindowCommands& inputWindowCommands) { bool hasChanges = mInputWindowCommands.merge(inputWindowCommands); bool hasChanges = mPendingInputWindowCommands.merge(inputWindowCommands); return hasChanges ? eTraversalNeeded : 0; } Loading Loading @@ -4086,9 +4088,8 @@ void SurfaceFlinger::onInitializeDisplays() { d.width = 0; d.height = 0; displays.add(d); // This called on the main thread, apply it directly. applyTransactionState(state, displays, 0, mInputWindowCommands, -1, {}, systemTime(), true, false, {}, getpid(), getuid()); setTransactionState(state, displays, 0, nullptr, mPendingInputWindowCommands, -1, {}, false, {}); setPowerModeInternal(display, hal::PowerMode::ON); const nsecs_t vsyncPeriod = mRefreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod(); Loading Loading @@ -5253,7 +5254,7 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r void SurfaceFlinger::repaintEverything() { mRepaintEverything = true; setTransactionFlags(eTransactionNeeded); signalTransaction(); } void SurfaceFlinger::repaintEverythingForHWC() { Loading services/surfaceflinger/SurfaceFlinger.h +9 −13 Original line number Diff line number Diff line Loading @@ -433,15 +433,13 @@ private: struct TransactionState { TransactionState(const Vector<ComposerState>& composerStates, const Vector<DisplayState>& displayStates, uint32_t transactionFlags, const InputWindowCommands& inputWindowCommands, int64_t desiredPresentTime, const client_cache_t& uncacheBuffer, int64_t postTime, bool privileged, bool hasListenerCallbacks, int64_t desiredPresentTime, const client_cache_t& uncacheBuffer, int64_t postTime, bool privileged, bool hasListenerCallbacks, std::vector<ListenerCallbacks> listenerCallbacks, int originPID, int originUID) : states(composerStates), displays(displayStates), flags(transactionFlags), inputWindowCommands(inputWindowCommands), desiredPresentTime(desiredPresentTime), buffer(uncacheBuffer), postTime(postTime), Loading @@ -454,7 +452,6 @@ private: Vector<ComposerState> states; Vector<DisplayState> displays; uint32_t flags; InputWindowCommands inputWindowCommands; const int64_t desiredPresentTime; client_cache_t buffer; const int64_t postTime; Loading Loading @@ -710,7 +707,6 @@ private: /* * Transactions */ void flushTransactionQueue(); void applyTransactionState(const Vector<ComposerState>& state, const Vector<DisplayState>& displays, uint32_t flags, const InputWindowCommands& inputWindowCommands, Loading @@ -718,9 +714,10 @@ private: const client_cache_t& uncacheBuffer, const int64_t postTime, bool privileged, bool hasListenerCallbacks, const std::vector<ListenerCallbacks>& listenerCallbacks, int32_t originPID, int32_t originUID) REQUIRES(mStateLock); // flush pending transaction that was presented after desiredPresentTime. void flushPendingTransactionQueues(); int originPID, int originUID, bool isMainThread = false) REQUIRES(mStateLock); // Returns true if at least one transaction was flushed bool flushTransactionQueues(); // Returns true if there is at least one transaction that needs to be flushed bool transactionFlushNeeded(); uint32_t getTransactionFlags(uint32_t flags); Loading Loading @@ -1164,10 +1161,8 @@ private: uint32_t mTexturePoolSize = 0; std::vector<uint32_t> mTexturePool; mutable Mutex mQueueLock; std::unordered_map<sp<IBinder>, std::queue<TransactionState>, IListenerHash> mPendingTransactionQueues GUARDED_BY(mQueueLock); std::vector<TransactionState> mTransactionQueue GUARDED_BY(mQueueLock); std::unordered_map<sp<IBinder>, std::queue<TransactionState>, IListenerHash> mTransactionQueues; /* * Feature prototyping */ Loading Loading @@ -1244,6 +1239,7 @@ private: const float mEmulatedDisplayDensity; sp<os::IInputFlinger> mInputFlinger; InputWindowCommands mPendingInputWindowCommands GUARDED_BY(mStateLock); // Should only be accessed by the main thread. InputWindowCommands mInputWindowCommands; Loading services/surfaceflinger/tests/TransactionTestHarnesses.h +0 −3 Original line number Diff line number Diff line Loading @@ -68,9 +68,6 @@ public: Rect(displayState.layerStackSpaceRect), Rect(resolution)); t.apply(); SurfaceComposerClient::Transaction().apply(true); // wait for 3 vsyncs to ensure the buffer is latched. usleep(static_cast<int32_t>(1e6 / displayConfig.refreshRate) * 3); BufferItem item; itemConsumer->acquireBuffer(&item, 0, true); auto sc = std::make_unique<ScreenCapture>(item.mGraphicBuffer); Loading services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +2 −2 Original line number Diff line number Diff line Loading @@ -346,7 +346,7 @@ public: return mFlinger->SurfaceFlinger::getDisplayNativePrimaries(displayToken, primaries); } auto& getPendingTransactionQueue() { return mFlinger->mPendingTransactionQueues; } auto& getTransactionQueue() { return mFlinger->mTransactionQueues; } auto setTransactionState(const Vector<ComposerState>& states, const Vector<DisplayState>& displays, uint32_t flags, Loading @@ -360,7 +360,7 @@ public: hasListenerCallbacks, listenerCallbacks); } auto flushPendingTransactionQueues() { return mFlinger->flushPendingTransactionQueues(); }; auto flushTransactionQueues() { return mFlinger->flushTransactionQueues(); }; auto onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { return mFlinger->onTransact(code, data, reply, flags); Loading services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp +10 −10 Original line number Diff line number Diff line Loading @@ -122,7 +122,7 @@ public: } void NotPlacedOnTransactionQueue(uint32_t flags, bool syncInputWindows) { ASSERT_EQ(0, mFlinger.getPendingTransactionQueue().size()); ASSERT_EQ(0, mFlinger.getTransactionQueue().size()); // called in SurfaceFlinger::signalTransaction EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); EXPECT_CALL(*mVSyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillOnce(Return(systemTime())); Loading @@ -146,12 +146,12 @@ public: } else { EXPECT_LE(returnedTime, applicationTime + s2ns(5)); } auto transactionQueue = mFlinger.getPendingTransactionQueue(); auto transactionQueue = mFlinger.getTransactionQueue(); EXPECT_EQ(0, transactionQueue.size()); } void PlaceOnTransactionQueue(uint32_t flags, bool syncInputWindows) { ASSERT_EQ(0, mFlinger.getPendingTransactionQueue().size()); ASSERT_EQ(0, mFlinger.getTransactionQueue().size()); // called in SurfaceFlinger::signalTransaction EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); Loading @@ -172,12 +172,12 @@ public: nsecs_t returnedTime = systemTime(); EXPECT_LE(returnedTime, applicationSentTime + s2ns(5)); // This transaction should have been placed on the transaction queue auto transactionQueue = mFlinger.getPendingTransactionQueue(); auto transactionQueue = mFlinger.getTransactionQueue(); EXPECT_EQ(1, transactionQueue.size()); } void BlockedByPriorTransaction(uint32_t flags, bool syncInputWindows) { ASSERT_EQ(0, mFlinger.getPendingTransactionQueue().size()); ASSERT_EQ(0, mFlinger.getTransactionQueue().size()); // called in SurfaceFlinger::signalTransaction nsecs_t time = systemTime(); EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); Loading Loading @@ -222,7 +222,7 @@ public: } // check that there is one binder on the pending queue. auto transactionQueue = mFlinger.getPendingTransactionQueue(); auto transactionQueue = mFlinger.getTransactionQueue(); EXPECT_EQ(1, transactionQueue.size()); auto& [applyToken, transactionStates] = *(transactionQueue.begin()); Loading @@ -241,7 +241,7 @@ public: }; TEST_F(TransactionApplicationTest, Flush_RemovesFromQueue) { ASSERT_EQ(0, mFlinger.getPendingTransactionQueue().size()); ASSERT_EQ(0, mFlinger.getTransactionQueue().size()); // called in SurfaceFlinger::signalTransaction EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); Loading @@ -257,7 +257,7 @@ TEST_F(TransactionApplicationTest, Flush_RemovesFromQueue) { transactionA.desiredPresentTime, transactionA.uncacheBuffer, mHasListenerCallbacks, mCallbacks); auto& transactionQueue = mFlinger.getPendingTransactionQueue(); auto& transactionQueue = mFlinger.getTransactionQueue(); ASSERT_EQ(1, transactionQueue.size()); auto& [applyToken, transactionStates] = *(transactionQueue.begin()); Loading @@ -275,9 +275,9 @@ TEST_F(TransactionApplicationTest, Flush_RemovesFromQueue) { empty.inputWindowCommands, empty.desiredPresentTime, empty.uncacheBuffer, mHasListenerCallbacks, mCallbacks); // flush pending transaction queue should flush as desiredPresentTime has // flush transaction queue should flush as desiredPresentTime has // passed mFlinger.flushPendingTransactionQueues(); mFlinger.flushTransactionQueues(); EXPECT_EQ(0, transactionQueue.size()); } Loading Loading
services/surfaceflinger/SurfaceFlinger.cpp +146 −145 Original line number Diff line number Diff line Loading @@ -1896,18 +1896,19 @@ void SurfaceFlinger::onMessageInvalidate(int64_t vsyncId, nsecs_t expectedVSyncT bool SurfaceFlinger::handleMessageTransaction() { ATRACE_CALL(); uint32_t transactionFlags = peekTransactionFlags(); if (getTransactionFlags(eTransactionFlushNeeded)) { flushPendingTransactionQueues(); flushTransactionQueue(); } bool flushedATransaction = flushTransactionQueues(); uint32_t transactionFlags = peekTransactionFlags(); bool runHandleTransaction = (transactionFlags && (transactionFlags != eTransactionFlushNeeded)) || mForceTraversal; (transactionFlags && (transactionFlags != eTransactionFlushNeeded)) || flushedATransaction || mForceTraversal; if (runHandleTransaction) { handleTransaction(eTransactionMask); } else { getTransactionFlags(eTransactionFlushNeeded); } if (transactionFlushNeeded()) { Loading Loading @@ -2776,6 +2777,7 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) }); } commitInputWindowCommands(); commitTransaction(); } Loading Loading @@ -2816,6 +2818,11 @@ void SurfaceFlinger::updateInputWindowInfo() { : nullptr); } void SurfaceFlinger::commitInputWindowCommands() { mInputWindowCommands.merge(mPendingInputWindowCommands); mPendingInputWindowCommands.clear(); } void SurfaceFlinger::updateCursorAsync() { compositionengine::CompositionRefreshArgs refreshArgs; for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) { Loading Loading @@ -3168,52 +3175,50 @@ void SurfaceFlinger::setTraversalNeeded() { 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.states, transaction.displays, transaction.flags, mPendingInputWindowCommands, transaction.desiredPresentTime, transaction.buffer, transaction.postTime, transaction.privileged, transaction.hasListenerCallbacks, transaction.listenerCallbacks, transaction.originPID, transaction.originUID, /*isMainThread*/ true); transactionQueue.pop(); flushedATransaction = true; } if (transactionQueue.empty()) { it = mPendingTransactionQueues.erase(it); it = mTransactionQueues.erase(it); mTransactionCV.broadcast(); } else { it = std::next(it, 1); } } } { Mutex::Autolock _l(mStateLock); for (const auto& transaction : transactions) { applyTransactionState(transaction.states, transaction.displays, transaction.flags, mInputWindowCommands, transaction.desiredPresentTime, transaction.buffer, transaction.postTime, transaction.privileged, transaction.hasListenerCallbacks, transaction.listenerCallbacks, transaction.originPID, transaction.originUID); } } return flushedATransaction; } bool SurfaceFlinger::transactionFlushNeeded() { Mutex::Autolock _l(mQueueLock); return !mPendingTransactionQueues.empty(); return !mTransactionQueues.empty(); } Loading Loading @@ -3248,16 +3253,17 @@ status_t SurfaceFlinger::setTransactionState( ATRACE_CALL(); const int64_t postTime = systemTime(); bool privileged = callingThreadHasUnscopedSurfaceFlingerAccess(); { Mutex::Autolock _l(mQueueLock); Mutex::Autolock _l(mStateLock); // If its TransactionQueue already has a pending TransactionState or if it is pending auto itr = mPendingTransactionQueues.find(applyToken); 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 != mPendingTransactionQueues.end()) { while (itr != mTransactionQueues.end()) { status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5)); if (CC_UNLIKELY(err != NO_ERROR)) { ALOGW_IF(err == TIMED_OUT, Loading @@ -3265,21 +3271,11 @@ status_t SurfaceFlinger::setTransactionState( "waiting for animation frame to apply"); break; } itr = mPendingTransactionQueues.find(applyToken); itr = mTransactionQueues.find(applyToken); } } // 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); } const bool pendingTransactions = itr != mPendingTransactionQueues.end(); const bool pendingTransactions = itr != mTransactionQueues.end(); // Expected present time is computed and cached on invalidate, so it may be stale. if (!pendingTransactions) { mExpectedPresentTime = calculateExpectedPresentTime(systemTime()); Loading @@ -3290,92 +3286,43 @@ status_t SurfaceFlinger::setTransactionState( const int originUID = ipc->getCallingUid(); if (pendingTransactions || !transactionIsReadyToBeApplied(desiredPresentTime, states)) { mPendingTransactionQueues[applyToken].emplace(states, displays, flags, inputWindowCommands, desiredPresentTime, mTransactionQueues[applyToken].emplace(states, displays, flags, desiredPresentTime, uncacheBuffer, postTime, privileged, hasListenerCallbacks, listenerCallbacks, originPID, originUID); setTransactionFlags(eTransactionFlushNeeded); return NO_ERROR; } mTransactionQueue.emplace_back(states, displays, flags, inputWindowCommands, desiredPresentTime, uncacheBuffer, postTime, privileged, hasListenerCallbacks, listenerCallbacks, originPID, originUID); setTransactionFlags(eTransactionFlushNeeded); return NO_ERROR; } { Mutex::Autolock _l(mStateLock); 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 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) { setTransactionFlags(eTransactionFlushNeeded, schedule); applyTransactionState(states, displays, flags, inputWindowCommands, desiredPresentTime, uncacheBuffer, postTime, privileged, hasListenerCallbacks, listenerCallbacks, originPID, originUID, /*isMainThread*/ false); return NO_ERROR; } if (synchronous) { mTransactionPending = true; } if (syncInput) { mPendingSyncInputWindows = true; } setTransactionFlags(eTransactionFlushNeeded, schedule); void SurfaceFlinger::applyTransactionState( const Vector<ComposerState>& states, const Vector<DisplayState>& displays, uint32_t flags, const InputWindowCommands& inputWindowCommands, const int64_t desiredPresentTime, const client_cache_t& uncacheBuffer, const int64_t postTime, bool privileged, bool hasListenerCallbacks, const std::vector<ListenerCallbacks>& listenerCallbacks, int originPID, int originUID, bool isMainThread) { uint32_t transactionFlags = 0; // 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) { 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); } } Mutex::Autolock _l(mStateLock); for (const auto& t : transactionQueue) { applyTransactionState(t.states, t.displays, t.flags, t.inputWindowCommands, t.desiredPresentTime, t.buffer, t.postTime, t.privileged, t.hasListenerCallbacks, t.listenerCallbacks, t.originPID, t.originUID); } } void SurfaceFlinger::applyTransactionState( const Vector<ComposerState>& states, const Vector<DisplayState>& displays, uint32_t flags, const InputWindowCommands& inputWindowCommands, const int64_t desiredPresentTime, const client_cache_t& uncacheBuffer, const int64_t postTime, bool privileged, bool hasListenerCallbacks, const std::vector<ListenerCallbacks>& listenerCallbacks, int32_t originPID, int32_t originUID) { uint32_t transactionFlags = 0; for (const DisplayState& display : displays) { transactionFlags |= setDisplayStateLocked(display); Loading Loading @@ -3432,25 +3379,80 @@ void SurfaceFlinger::applyTransactionState( transactionFlags = eTransactionNeeded; } if (transactionFlags && mInterceptor->isEnabled()) { mInterceptor->saveTransaction(states, mCurrentState.displays, displays, flags, originPID, originUID); } // 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) { // 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); } // 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); } // this triggers the transaction setTransactionFlags(transactionFlags); 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); } } } Loading Loading @@ -3829,7 +3831,7 @@ uint32_t SurfaceFlinger::setClientStateLocked( } uint32_t SurfaceFlinger::addInputWindowCommands(const InputWindowCommands& inputWindowCommands) { bool hasChanges = mInputWindowCommands.merge(inputWindowCommands); bool hasChanges = mPendingInputWindowCommands.merge(inputWindowCommands); return hasChanges ? eTraversalNeeded : 0; } Loading Loading @@ -4086,9 +4088,8 @@ void SurfaceFlinger::onInitializeDisplays() { d.width = 0; d.height = 0; displays.add(d); // This called on the main thread, apply it directly. applyTransactionState(state, displays, 0, mInputWindowCommands, -1, {}, systemTime(), true, false, {}, getpid(), getuid()); setTransactionState(state, displays, 0, nullptr, mPendingInputWindowCommands, -1, {}, false, {}); setPowerModeInternal(display, hal::PowerMode::ON); const nsecs_t vsyncPeriod = mRefreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod(); Loading Loading @@ -5253,7 +5254,7 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r void SurfaceFlinger::repaintEverything() { mRepaintEverything = true; setTransactionFlags(eTransactionNeeded); signalTransaction(); } void SurfaceFlinger::repaintEverythingForHWC() { Loading
services/surfaceflinger/SurfaceFlinger.h +9 −13 Original line number Diff line number Diff line Loading @@ -433,15 +433,13 @@ private: struct TransactionState { TransactionState(const Vector<ComposerState>& composerStates, const Vector<DisplayState>& displayStates, uint32_t transactionFlags, const InputWindowCommands& inputWindowCommands, int64_t desiredPresentTime, const client_cache_t& uncacheBuffer, int64_t postTime, bool privileged, bool hasListenerCallbacks, int64_t desiredPresentTime, const client_cache_t& uncacheBuffer, int64_t postTime, bool privileged, bool hasListenerCallbacks, std::vector<ListenerCallbacks> listenerCallbacks, int originPID, int originUID) : states(composerStates), displays(displayStates), flags(transactionFlags), inputWindowCommands(inputWindowCommands), desiredPresentTime(desiredPresentTime), buffer(uncacheBuffer), postTime(postTime), Loading @@ -454,7 +452,6 @@ private: Vector<ComposerState> states; Vector<DisplayState> displays; uint32_t flags; InputWindowCommands inputWindowCommands; const int64_t desiredPresentTime; client_cache_t buffer; const int64_t postTime; Loading Loading @@ -710,7 +707,6 @@ private: /* * Transactions */ void flushTransactionQueue(); void applyTransactionState(const Vector<ComposerState>& state, const Vector<DisplayState>& displays, uint32_t flags, const InputWindowCommands& inputWindowCommands, Loading @@ -718,9 +714,10 @@ private: const client_cache_t& uncacheBuffer, const int64_t postTime, bool privileged, bool hasListenerCallbacks, const std::vector<ListenerCallbacks>& listenerCallbacks, int32_t originPID, int32_t originUID) REQUIRES(mStateLock); // flush pending transaction that was presented after desiredPresentTime. void flushPendingTransactionQueues(); int originPID, int originUID, bool isMainThread = false) REQUIRES(mStateLock); // Returns true if at least one transaction was flushed bool flushTransactionQueues(); // Returns true if there is at least one transaction that needs to be flushed bool transactionFlushNeeded(); uint32_t getTransactionFlags(uint32_t flags); Loading Loading @@ -1164,10 +1161,8 @@ private: uint32_t mTexturePoolSize = 0; std::vector<uint32_t> mTexturePool; mutable Mutex mQueueLock; std::unordered_map<sp<IBinder>, std::queue<TransactionState>, IListenerHash> mPendingTransactionQueues GUARDED_BY(mQueueLock); std::vector<TransactionState> mTransactionQueue GUARDED_BY(mQueueLock); std::unordered_map<sp<IBinder>, std::queue<TransactionState>, IListenerHash> mTransactionQueues; /* * Feature prototyping */ Loading Loading @@ -1244,6 +1239,7 @@ private: const float mEmulatedDisplayDensity; sp<os::IInputFlinger> mInputFlinger; InputWindowCommands mPendingInputWindowCommands GUARDED_BY(mStateLock); // Should only be accessed by the main thread. InputWindowCommands mInputWindowCommands; Loading
services/surfaceflinger/tests/TransactionTestHarnesses.h +0 −3 Original line number Diff line number Diff line Loading @@ -68,9 +68,6 @@ public: Rect(displayState.layerStackSpaceRect), Rect(resolution)); t.apply(); SurfaceComposerClient::Transaction().apply(true); // wait for 3 vsyncs to ensure the buffer is latched. usleep(static_cast<int32_t>(1e6 / displayConfig.refreshRate) * 3); BufferItem item; itemConsumer->acquireBuffer(&item, 0, true); auto sc = std::make_unique<ScreenCapture>(item.mGraphicBuffer); Loading
services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +2 −2 Original line number Diff line number Diff line Loading @@ -346,7 +346,7 @@ public: return mFlinger->SurfaceFlinger::getDisplayNativePrimaries(displayToken, primaries); } auto& getPendingTransactionQueue() { return mFlinger->mPendingTransactionQueues; } auto& getTransactionQueue() { return mFlinger->mTransactionQueues; } auto setTransactionState(const Vector<ComposerState>& states, const Vector<DisplayState>& displays, uint32_t flags, Loading @@ -360,7 +360,7 @@ public: hasListenerCallbacks, listenerCallbacks); } auto flushPendingTransactionQueues() { return mFlinger->flushPendingTransactionQueues(); }; auto flushTransactionQueues() { return mFlinger->flushTransactionQueues(); }; auto onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { return mFlinger->onTransact(code, data, reply, flags); Loading
services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp +10 −10 Original line number Diff line number Diff line Loading @@ -122,7 +122,7 @@ public: } void NotPlacedOnTransactionQueue(uint32_t flags, bool syncInputWindows) { ASSERT_EQ(0, mFlinger.getPendingTransactionQueue().size()); ASSERT_EQ(0, mFlinger.getTransactionQueue().size()); // called in SurfaceFlinger::signalTransaction EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); EXPECT_CALL(*mVSyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillOnce(Return(systemTime())); Loading @@ -146,12 +146,12 @@ public: } else { EXPECT_LE(returnedTime, applicationTime + s2ns(5)); } auto transactionQueue = mFlinger.getPendingTransactionQueue(); auto transactionQueue = mFlinger.getTransactionQueue(); EXPECT_EQ(0, transactionQueue.size()); } void PlaceOnTransactionQueue(uint32_t flags, bool syncInputWindows) { ASSERT_EQ(0, mFlinger.getPendingTransactionQueue().size()); ASSERT_EQ(0, mFlinger.getTransactionQueue().size()); // called in SurfaceFlinger::signalTransaction EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); Loading @@ -172,12 +172,12 @@ public: nsecs_t returnedTime = systemTime(); EXPECT_LE(returnedTime, applicationSentTime + s2ns(5)); // This transaction should have been placed on the transaction queue auto transactionQueue = mFlinger.getPendingTransactionQueue(); auto transactionQueue = mFlinger.getTransactionQueue(); EXPECT_EQ(1, transactionQueue.size()); } void BlockedByPriorTransaction(uint32_t flags, bool syncInputWindows) { ASSERT_EQ(0, mFlinger.getPendingTransactionQueue().size()); ASSERT_EQ(0, mFlinger.getTransactionQueue().size()); // called in SurfaceFlinger::signalTransaction nsecs_t time = systemTime(); EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); Loading Loading @@ -222,7 +222,7 @@ public: } // check that there is one binder on the pending queue. auto transactionQueue = mFlinger.getPendingTransactionQueue(); auto transactionQueue = mFlinger.getTransactionQueue(); EXPECT_EQ(1, transactionQueue.size()); auto& [applyToken, transactionStates] = *(transactionQueue.begin()); Loading @@ -241,7 +241,7 @@ public: }; TEST_F(TransactionApplicationTest, Flush_RemovesFromQueue) { ASSERT_EQ(0, mFlinger.getPendingTransactionQueue().size()); ASSERT_EQ(0, mFlinger.getTransactionQueue().size()); // called in SurfaceFlinger::signalTransaction EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); Loading @@ -257,7 +257,7 @@ TEST_F(TransactionApplicationTest, Flush_RemovesFromQueue) { transactionA.desiredPresentTime, transactionA.uncacheBuffer, mHasListenerCallbacks, mCallbacks); auto& transactionQueue = mFlinger.getPendingTransactionQueue(); auto& transactionQueue = mFlinger.getTransactionQueue(); ASSERT_EQ(1, transactionQueue.size()); auto& [applyToken, transactionStates] = *(transactionQueue.begin()); Loading @@ -275,9 +275,9 @@ TEST_F(TransactionApplicationTest, Flush_RemovesFromQueue) { empty.inputWindowCommands, empty.desiredPresentTime, empty.uncacheBuffer, mHasListenerCallbacks, mCallbacks); // flush pending transaction queue should flush as desiredPresentTime has // flush transaction queue should flush as desiredPresentTime has // passed mFlinger.flushPendingTransactionQueues(); mFlinger.flushTransactionQueues(); EXPECT_EQ(0, transactionQueue.size()); } Loading