Loading services/surfaceflinger/SurfaceFlinger.cpp +172 −169 Original line number Diff line number Diff line Loading @@ -1914,19 +1914,17 @@ void SurfaceFlinger::onMessageInvalidate(int64_t vsyncId, nsecs_t expectedVSyncT bool SurfaceFlinger::handleMessageTransaction() { ATRACE_CALL(); uint32_t transactionFlags = peekTransactionFlags(); bool flushedATransaction = flushTransactionQueues(); if (getTransactionFlags(eTransactionFlushNeeded)) { flushPendingTransactionQueues(); flushTransactionQueue(); } uint32_t transactionFlags = peekTransactionFlags(); bool runHandleTransaction = (transactionFlags && (transactionFlags != eTransactionFlushNeeded)) || flushedATransaction || mForceTraversal; ((transactionFlags & (~eTransactionFlushNeeded)) != 0) || mForceTraversal; if (runHandleTransaction) { handleTransaction(eTransactionMask); } else { getTransactionFlags(eTransactionFlushNeeded); } if (transactionFlushNeeded()) { Loading Loading @@ -2828,7 +2826,6 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) { }); } commitInputWindowCommands(); commitTransaction(); } Loading Loading @@ -2869,11 +2866,6 @@ 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 @@ -3237,55 +3229,55 @@ void SurfaceFlinger::setTraversalNeeded() { mForceTraversal = true; } bool SurfaceFlinger::flushTransactionQueues() { void SurfaceFlinger::flushPendingTransactionQueues() { // 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(mStateLock); Mutex::Autolock _l(mQueueLock); auto it = mTransactionQueues.begin(); while (it != mTransactionQueues.end()) { auto it = mPendingTransactionQueues.begin(); while (it != mPendingTransactionQueues.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 = mTransactionQueues.erase(it); mTransactionCV.broadcast(); it = mPendingTransactionQueues.erase(it); mTransactionQueueCV.broadcast(); } else { it = std::next(it, 1); } } } return flushedATransaction; { 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); } } } bool SurfaceFlinger::transactionFlushNeeded() { return !mTransactionQueues.empty(); Mutex::Autolock _l(mQueueLock); return !mPendingTransactionQueues.empty(); } bool SurfaceFlinger::transactionIsReadyToBeApplied(int64_t desiredPresentTime, const Vector<ComposerState>& states, bool updateTransactionCounters) { Loading @@ -3307,6 +3299,8 @@ bool SurfaceFlinger::transactionIsReadyToBeApplied(int64_t desiredPresentTime, 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(); Loading @@ -3321,7 +3315,6 @@ bool SurfaceFlinger::transactionIsReadyToBeApplied(int64_t desiredPresentTime, if (updateTransactionCounters) { // See BufferStateLayer::mPendingBufferTransactions if (layer) layer->incrementPendingBufferCount(); } } return ready; Loading @@ -3338,27 +3331,28 @@ status_t SurfaceFlinger::setTransactionState( const int64_t postTime = systemTime(); bool privileged = callingThreadHasUnscopedSurfaceFlingerAccess(); Mutex::Autolock _l(mStateLock); { Mutex::Autolock _l(mQueueLock); // If its TransactionQueue already has a pending TransactionState or if it is pending auto itr = mTransactionQueues.find(applyToken); 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 != mTransactionQueues.end()) { status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5)); 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 = mTransactionQueues.find(applyToken); itr = mPendingTransactionQueues.find(applyToken); } } const bool pendingTransactions = itr != mTransactionQueues.end(); 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(); Loading @@ -3373,55 +3367,117 @@ status_t SurfaceFlinger::setTransactionState( } } // 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) || 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); mPendingTransactionQueues[applyToken].emplace(frameTimelineVsyncId, states, displays, flags, inputWindowCommands, desiredPresentTime, isAutoTimestamp, uncacheBuffer, postTime, privileged, hasListenerCallbacks, listenerCallbacks, originPid, originUid, transactionId); setTransactionFlags(eTransactionFlushNeeded); return NO_ERROR; } applyTransactionState(frameTimelineVsyncId, states, displays, flags, inputWindowCommands, desiredPresentTime, isAutoTimestamp, uncacheBuffer, postTime, privileged, hasListenerCallbacks, listenerCallbacks, originPid, originUid, transactionId, /*isMainThread*/ false); 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); // 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 NO_ERROR; } 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; // Handle synchronous cases. { Mutex::Autolock _l(mStateLock); if (synchronous) { mTransactionPending = true; } if (syncInput) { mPendingSyncInputWindows = true; } 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) { // 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) { 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 // caller after a few seconds. ALOGW_IF(err == TIMED_OUT, "setTransactionState timed out " "waiting for previous animation frame"); mAnimTransactionPending = false; // called after a few seconds. ALOGW_IF(err == TIMED_OUT, "setTransactionState timed out!"); mTransactionPending = false; mPendingSyncInputWindows = 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); Loading Loading @@ -3480,80 +3536,25 @@ void SurfaceFlinger::applyTransactionState( 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); } // TODO(b/159125966): Remove eEarlyWakeup completly as no client should use this flag if (flags & eEarlyWakeup) { ALOGW("eEarlyWakeup is deprecated. Use eExplicitEarlyWakeup[Start|End]"); // 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; } if (!privileged && (flags & (eExplicitEarlyWakeupStart | eExplicitEarlyWakeupEnd))) { ALOGE("Only WindowManager is allowed to use eExplicitEarlyWakeup[Start|End] flags"); flags &= ~(eExplicitEarlyWakeupStart | eExplicitEarlyWakeupEnd); if (transactionFlags) { setTransactionFlags(transactionFlags); } // 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); } } } Loading Loading @@ -3945,7 +3946,7 @@ uint32_t SurfaceFlinger::setClientStateLocked( } uint32_t SurfaceFlinger::addInputWindowCommands(const InputWindowCommands& inputWindowCommands) { bool hasChanges = mPendingInputWindowCommands.merge(inputWindowCommands); bool hasChanges = mInputWindowCommands.merge(inputWindowCommands); return hasChanges ? eTraversalNeeded : 0; } Loading Loading @@ -4210,9 +4211,11 @@ void SurfaceFlinger::onInitializeDisplays() { d.width = 0; d.height = 0; displays.add(d); setTransactionState(ISurfaceComposer::INVALID_VSYNC_ID, state, displays, 0, nullptr, mPendingInputWindowCommands, systemTime(), true, {}, false, {}, 0 /* Undefined transactionId */); // 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 */); setPowerModeInternal(display, hal::PowerMode::ON); const nsecs_t vsyncPeriod = mRefreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod(); Loading Loading @@ -5389,7 +5392,7 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r void SurfaceFlinger::repaintEverything() { mRepaintEverything = true; signalTransaction(); setTransactionFlags(eTransactionNeeded); } void SurfaceFlinger::repaintEverythingForHWC() { Loading services/surfaceflinger/SurfaceFlinger.h +16 −9 Original line number Diff line number Diff line Loading @@ -434,15 +434,16 @@ private: struct TransactionState { TransactionState(int64_t frameTimelineVsyncId, const Vector<ComposerState>& composerStates, const Vector<DisplayState>& displayStates, uint32_t transactionFlags, int64_t desiredPresentTime, bool isAutoTimestamp, const client_cache_t& uncacheBuffer, int64_t postTime, bool privileged, bool hasListenerCallbacks, const InputWindowCommands& inputWindowCommands, int64_t desiredPresentTime, bool isAutoTimestamp, const client_cache_t& uncacheBuffer, int64_t postTime, bool privileged, bool hasListenerCallbacks, std::vector<ListenerCallbacks> listenerCallbacks, int originPid, int originUid, uint64_t transactionId) : frameTimelineVsyncId(frameTimelineVsyncId), states(composerStates), displays(displayStates), flags(transactionFlags), inputWindowCommands(inputWindowCommands), desiredPresentTime(desiredPresentTime), isAutoTimestamp(isAutoTimestamp), buffer(uncacheBuffer), Loading @@ -458,6 +459,7 @@ private: Vector<ComposerState> states; Vector<DisplayState> displays; uint32_t flags; InputWindowCommands inputWindowCommands; const int64_t desiredPresentTime; const bool isAutoTimestamp; client_cache_t buffer; Loading Loading @@ -723,6 +725,7 @@ private: /* * Transactions */ void flushTransactionQueue(); void applyTransactionState(int64_t frameTimelineVsyncId, const Vector<ComposerState>& state, const Vector<DisplayState>& displays, uint32_t flags, const InputWindowCommands& inputWindowCommands, Loading @@ -730,10 +733,12 @@ private: 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 = false) REQUIRES(mStateLock); int originPid, int originUid, uint64_t transactionId) REQUIRES(mStateLock); // Returns true if at least one transaction was flushed bool flushTransactionQueues(); // flush pending transaction that was presented after desiredPresentTime. void flushPendingTransactionQueues(); // Returns true if there is at least one transaction that needs to be flushed bool transactionFlushNeeded(); uint32_t getTransactionFlags(uint32_t flags); Loading @@ -751,7 +756,7 @@ private: void commitOffscreenLayers(); bool transactionIsReadyToBeApplied(int64_t desiredPresentTime, const Vector<ComposerState>& states, bool updateTransactionCounters = false) REQUIRES(mStateLock); bool updateTransactionCounters = false); uint32_t setDisplayStateLocked(const DisplayState& s) REQUIRES(mStateLock); uint32_t addInputWindowCommands(const InputWindowCommands& inputWindowCommands) REQUIRES(mStateLock); Loading Loading @@ -1168,8 +1173,11 @@ private: uint32_t mTexturePoolSize = 0; std::vector<uint32_t> mTexturePool; std::unordered_map<sp<IBinder>, std::queue<TransactionState>, IListenerHash> mTransactionQueues; mutable Mutex mQueueLock; Condition mTransactionQueueCV; std::unordered_map<sp<IBinder>, std::queue<TransactionState>, IListenerHash> mPendingTransactionQueues GUARDED_BY(mQueueLock); std::vector<TransactionState> mTransactionQueue GUARDED_BY(mQueueLock); /* * Feature prototyping */ Loading Loading @@ -1246,7 +1254,6 @@ 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 +3 −0 Original line number Diff line number Diff line Loading @@ -68,6 +68,9 @@ 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 @@ -365,7 +365,7 @@ public: return mFlinger->SurfaceFlinger::getDisplayNativePrimaries(displayToken, primaries); } auto& getTransactionQueue() { return mFlinger->mTransactionQueues; } auto& getPendingTransactionQueue() { return mFlinger->mPendingTransactionQueues; } auto setTransactionState(int64_t frameTimelineVsyncId, const Vector<ComposerState>& states, const Vector<DisplayState>& displays, uint32_t flags, Loading @@ -381,7 +381,7 @@ public: listenerCallbacks, transactionId); } auto flushTransactionQueues() { return mFlinger->flushTransactionQueues(); }; auto flushPendingTransactionQueues() { return mFlinger->flushPendingTransactionQueues(); }; 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 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
services/surfaceflinger/SurfaceFlinger.cpp +172 −169 Original line number Diff line number Diff line Loading @@ -1914,19 +1914,17 @@ void SurfaceFlinger::onMessageInvalidate(int64_t vsyncId, nsecs_t expectedVSyncT bool SurfaceFlinger::handleMessageTransaction() { ATRACE_CALL(); uint32_t transactionFlags = peekTransactionFlags(); bool flushedATransaction = flushTransactionQueues(); if (getTransactionFlags(eTransactionFlushNeeded)) { flushPendingTransactionQueues(); flushTransactionQueue(); } uint32_t transactionFlags = peekTransactionFlags(); bool runHandleTransaction = (transactionFlags && (transactionFlags != eTransactionFlushNeeded)) || flushedATransaction || mForceTraversal; ((transactionFlags & (~eTransactionFlushNeeded)) != 0) || mForceTraversal; if (runHandleTransaction) { handleTransaction(eTransactionMask); } else { getTransactionFlags(eTransactionFlushNeeded); } if (transactionFlushNeeded()) { Loading Loading @@ -2828,7 +2826,6 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) { }); } commitInputWindowCommands(); commitTransaction(); } Loading Loading @@ -2869,11 +2866,6 @@ 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 @@ -3237,55 +3229,55 @@ void SurfaceFlinger::setTraversalNeeded() { mForceTraversal = true; } bool SurfaceFlinger::flushTransactionQueues() { void SurfaceFlinger::flushPendingTransactionQueues() { // 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(mStateLock); Mutex::Autolock _l(mQueueLock); auto it = mTransactionQueues.begin(); while (it != mTransactionQueues.end()) { auto it = mPendingTransactionQueues.begin(); while (it != mPendingTransactionQueues.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 = mTransactionQueues.erase(it); mTransactionCV.broadcast(); it = mPendingTransactionQueues.erase(it); mTransactionQueueCV.broadcast(); } else { it = std::next(it, 1); } } } return flushedATransaction; { 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); } } } bool SurfaceFlinger::transactionFlushNeeded() { return !mTransactionQueues.empty(); Mutex::Autolock _l(mQueueLock); return !mPendingTransactionQueues.empty(); } bool SurfaceFlinger::transactionIsReadyToBeApplied(int64_t desiredPresentTime, const Vector<ComposerState>& states, bool updateTransactionCounters) { Loading @@ -3307,6 +3299,8 @@ bool SurfaceFlinger::transactionIsReadyToBeApplied(int64_t desiredPresentTime, 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(); Loading @@ -3321,7 +3315,6 @@ bool SurfaceFlinger::transactionIsReadyToBeApplied(int64_t desiredPresentTime, if (updateTransactionCounters) { // See BufferStateLayer::mPendingBufferTransactions if (layer) layer->incrementPendingBufferCount(); } } return ready; Loading @@ -3338,27 +3331,28 @@ status_t SurfaceFlinger::setTransactionState( const int64_t postTime = systemTime(); bool privileged = callingThreadHasUnscopedSurfaceFlingerAccess(); Mutex::Autolock _l(mStateLock); { Mutex::Autolock _l(mQueueLock); // If its TransactionQueue already has a pending TransactionState or if it is pending auto itr = mTransactionQueues.find(applyToken); 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 != mTransactionQueues.end()) { status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5)); 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 = mTransactionQueues.find(applyToken); itr = mPendingTransactionQueues.find(applyToken); } } const bool pendingTransactions = itr != mTransactionQueues.end(); 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(); Loading @@ -3373,55 +3367,117 @@ status_t SurfaceFlinger::setTransactionState( } } // 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) || 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); mPendingTransactionQueues[applyToken].emplace(frameTimelineVsyncId, states, displays, flags, inputWindowCommands, desiredPresentTime, isAutoTimestamp, uncacheBuffer, postTime, privileged, hasListenerCallbacks, listenerCallbacks, originPid, originUid, transactionId); setTransactionFlags(eTransactionFlushNeeded); return NO_ERROR; } applyTransactionState(frameTimelineVsyncId, states, displays, flags, inputWindowCommands, desiredPresentTime, isAutoTimestamp, uncacheBuffer, postTime, privileged, hasListenerCallbacks, listenerCallbacks, originPid, originUid, transactionId, /*isMainThread*/ false); 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); // 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 NO_ERROR; } 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; // Handle synchronous cases. { Mutex::Autolock _l(mStateLock); if (synchronous) { mTransactionPending = true; } if (syncInput) { mPendingSyncInputWindows = true; } 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) { // 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) { 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 // caller after a few seconds. ALOGW_IF(err == TIMED_OUT, "setTransactionState timed out " "waiting for previous animation frame"); mAnimTransactionPending = false; // called after a few seconds. ALOGW_IF(err == TIMED_OUT, "setTransactionState timed out!"); mTransactionPending = false; mPendingSyncInputWindows = 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); Loading Loading @@ -3480,80 +3536,25 @@ void SurfaceFlinger::applyTransactionState( 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); } // TODO(b/159125966): Remove eEarlyWakeup completly as no client should use this flag if (flags & eEarlyWakeup) { ALOGW("eEarlyWakeup is deprecated. Use eExplicitEarlyWakeup[Start|End]"); // 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; } if (!privileged && (flags & (eExplicitEarlyWakeupStart | eExplicitEarlyWakeupEnd))) { ALOGE("Only WindowManager is allowed to use eExplicitEarlyWakeup[Start|End] flags"); flags &= ~(eExplicitEarlyWakeupStart | eExplicitEarlyWakeupEnd); if (transactionFlags) { setTransactionFlags(transactionFlags); } // 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); } } } Loading Loading @@ -3945,7 +3946,7 @@ uint32_t SurfaceFlinger::setClientStateLocked( } uint32_t SurfaceFlinger::addInputWindowCommands(const InputWindowCommands& inputWindowCommands) { bool hasChanges = mPendingInputWindowCommands.merge(inputWindowCommands); bool hasChanges = mInputWindowCommands.merge(inputWindowCommands); return hasChanges ? eTraversalNeeded : 0; } Loading Loading @@ -4210,9 +4211,11 @@ void SurfaceFlinger::onInitializeDisplays() { d.width = 0; d.height = 0; displays.add(d); setTransactionState(ISurfaceComposer::INVALID_VSYNC_ID, state, displays, 0, nullptr, mPendingInputWindowCommands, systemTime(), true, {}, false, {}, 0 /* Undefined transactionId */); // 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 */); setPowerModeInternal(display, hal::PowerMode::ON); const nsecs_t vsyncPeriod = mRefreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod(); Loading Loading @@ -5389,7 +5392,7 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r void SurfaceFlinger::repaintEverything() { mRepaintEverything = true; signalTransaction(); setTransactionFlags(eTransactionNeeded); } void SurfaceFlinger::repaintEverythingForHWC() { Loading
services/surfaceflinger/SurfaceFlinger.h +16 −9 Original line number Diff line number Diff line Loading @@ -434,15 +434,16 @@ private: struct TransactionState { TransactionState(int64_t frameTimelineVsyncId, const Vector<ComposerState>& composerStates, const Vector<DisplayState>& displayStates, uint32_t transactionFlags, int64_t desiredPresentTime, bool isAutoTimestamp, const client_cache_t& uncacheBuffer, int64_t postTime, bool privileged, bool hasListenerCallbacks, const InputWindowCommands& inputWindowCommands, int64_t desiredPresentTime, bool isAutoTimestamp, const client_cache_t& uncacheBuffer, int64_t postTime, bool privileged, bool hasListenerCallbacks, std::vector<ListenerCallbacks> listenerCallbacks, int originPid, int originUid, uint64_t transactionId) : frameTimelineVsyncId(frameTimelineVsyncId), states(composerStates), displays(displayStates), flags(transactionFlags), inputWindowCommands(inputWindowCommands), desiredPresentTime(desiredPresentTime), isAutoTimestamp(isAutoTimestamp), buffer(uncacheBuffer), Loading @@ -458,6 +459,7 @@ private: Vector<ComposerState> states; Vector<DisplayState> displays; uint32_t flags; InputWindowCommands inputWindowCommands; const int64_t desiredPresentTime; const bool isAutoTimestamp; client_cache_t buffer; Loading Loading @@ -723,6 +725,7 @@ private: /* * Transactions */ void flushTransactionQueue(); void applyTransactionState(int64_t frameTimelineVsyncId, const Vector<ComposerState>& state, const Vector<DisplayState>& displays, uint32_t flags, const InputWindowCommands& inputWindowCommands, Loading @@ -730,10 +733,12 @@ private: 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 = false) REQUIRES(mStateLock); int originPid, int originUid, uint64_t transactionId) REQUIRES(mStateLock); // Returns true if at least one transaction was flushed bool flushTransactionQueues(); // flush pending transaction that was presented after desiredPresentTime. void flushPendingTransactionQueues(); // Returns true if there is at least one transaction that needs to be flushed bool transactionFlushNeeded(); uint32_t getTransactionFlags(uint32_t flags); Loading @@ -751,7 +756,7 @@ private: void commitOffscreenLayers(); bool transactionIsReadyToBeApplied(int64_t desiredPresentTime, const Vector<ComposerState>& states, bool updateTransactionCounters = false) REQUIRES(mStateLock); bool updateTransactionCounters = false); uint32_t setDisplayStateLocked(const DisplayState& s) REQUIRES(mStateLock); uint32_t addInputWindowCommands(const InputWindowCommands& inputWindowCommands) REQUIRES(mStateLock); Loading Loading @@ -1168,8 +1173,11 @@ private: uint32_t mTexturePoolSize = 0; std::vector<uint32_t> mTexturePool; std::unordered_map<sp<IBinder>, std::queue<TransactionState>, IListenerHash> mTransactionQueues; mutable Mutex mQueueLock; Condition mTransactionQueueCV; std::unordered_map<sp<IBinder>, std::queue<TransactionState>, IListenerHash> mPendingTransactionQueues GUARDED_BY(mQueueLock); std::vector<TransactionState> mTransactionQueue GUARDED_BY(mQueueLock); /* * Feature prototyping */ Loading Loading @@ -1246,7 +1254,6 @@ 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 +3 −0 Original line number Diff line number Diff line Loading @@ -68,6 +68,9 @@ 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 @@ -365,7 +365,7 @@ public: return mFlinger->SurfaceFlinger::getDisplayNativePrimaries(displayToken, primaries); } auto& getTransactionQueue() { return mFlinger->mTransactionQueues; } auto& getPendingTransactionQueue() { return mFlinger->mPendingTransactionQueues; } auto setTransactionState(int64_t frameTimelineVsyncId, const Vector<ComposerState>& states, const Vector<DisplayState>& displays, uint32_t flags, Loading @@ -381,7 +381,7 @@ public: listenerCallbacks, transactionId); } auto flushTransactionQueues() { return mFlinger->flushTransactionQueues(); }; auto flushPendingTransactionQueues() { return mFlinger->flushPendingTransactionQueues(); }; 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 File changed.Preview size limit exceeded, changes collapsed. Show changes