summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/surfaceflinger/SurfaceFlinger.cpp341
-rw-r--r--services/surfaceflinger/SurfaceFlinger.h25
-rw-r--r--services/surfaceflinger/tests/TransactionTestHarnesses.h3
-rw-r--r--services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h4
-rw-r--r--services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp20
5 files changed, 203 insertions, 190 deletions
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 44c7f96ea6..59b3824fbb 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -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()) {
@@ -2828,7 +2826,6 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) {
});
}
- commitInputWindowCommands();
commitTransaction();
}
@@ -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)) {
@@ -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) {
@@ -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();
@@ -3319,9 +3313,8 @@ bool SurfaceFlinger::transactionIsReadyToBeApplied(int64_t desiredPresentTime,
ready = false;
}
if (updateTransactionCounters) {
- // See BufferStateLayer::mPendingBufferTransactions
- if (layer) layer->incrementPendingBufferCount();
-
+ // See BufferStateLayer::mPendingBufferTransactions
+ if (layer) layer->incrementPendingBufferCount();
}
}
return ready;
@@ -3338,90 +3331,153 @@ status_t SurfaceFlinger::setTransactionState(
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);
+ // 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);
+ }
+ }
- // 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;
+ 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;
}
- itr = mTransactionQueues.find(applyToken);
}
- }
- 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;
+ // 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);
}
- 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);
+ 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;
}
- applyTransactionState(frameTimelineVsyncId, states, displays, flags, inputWindowCommands,
- desiredPresentTime, isAutoTimestamp, uncacheBuffer, postTime, privileged,
- hasListenerCallbacks, listenerCallbacks, originPid, originUid,
- transactionId, /*isMainThread*/ false);
- 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);
@@ -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);
- }
}
}
@@ -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;
}
@@ -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();
@@ -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() {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 9f0f2eaf5d..8f38c5d7ae 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -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),
@@ -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;
@@ -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,
@@ -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);
@@ -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);
@@ -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
*/
@@ -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;
diff --git a/services/surfaceflinger/tests/TransactionTestHarnesses.h b/services/surfaceflinger/tests/TransactionTestHarnesses.h
index a361b1e956..3ef63d5626 100644
--- a/services/surfaceflinger/tests/TransactionTestHarnesses.h
+++ b/services/surfaceflinger/tests/TransactionTestHarnesses.h
@@ -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);
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index b57d4733d2..22bf2eae24 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -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,
@@ -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);
diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
index 06275c6b5b..a4a44085f3 100644
--- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
@@ -127,7 +127,7 @@ public:
}
void NotPlacedOnTransactionQueue(uint32_t flags, bool syncInputWindows) {
- ASSERT_EQ(0, mFlinger.getTransactionQueue().size());
+ ASSERT_EQ(0, mFlinger.getPendingTransactionQueue().size());
// called in SurfaceFlinger::signalTransaction
EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
EXPECT_CALL(*mVSyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillOnce(Return(systemTime()));
@@ -154,12 +154,12 @@ public:
} else {
EXPECT_LE(returnedTime, applicationTime + s2ns(5));
}
- auto transactionQueue = mFlinger.getTransactionQueue();
+ auto transactionQueue = mFlinger.getPendingTransactionQueue();
EXPECT_EQ(0, transactionQueue.size());
}
void PlaceOnTransactionQueue(uint32_t flags, bool syncInputWindows) {
- ASSERT_EQ(0, mFlinger.getTransactionQueue().size());
+ ASSERT_EQ(0, mFlinger.getPendingTransactionQueue().size());
// called in SurfaceFlinger::signalTransaction
EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
@@ -183,12 +183,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.getTransactionQueue();
+ auto transactionQueue = mFlinger.getPendingTransactionQueue();
EXPECT_EQ(1, transactionQueue.size());
}
void BlockedByPriorTransaction(uint32_t flags, bool syncInputWindows) {
- ASSERT_EQ(0, mFlinger.getTransactionQueue().size());
+ ASSERT_EQ(0, mFlinger.getPendingTransactionQueue().size());
// called in SurfaceFlinger::signalTransaction
nsecs_t time = systemTime();
EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
@@ -239,7 +239,7 @@ public:
}
// check that there is one binder on the pending queue.
- auto transactionQueue = mFlinger.getTransactionQueue();
+ auto transactionQueue = mFlinger.getPendingTransactionQueue();
EXPECT_EQ(1, transactionQueue.size());
auto& [applyToken, transactionStates] = *(transactionQueue.begin());
@@ -258,7 +258,7 @@ public:
};
TEST_F(TransactionApplicationTest, Flush_RemovesFromQueue) {
- ASSERT_EQ(0, mFlinger.getTransactionQueue().size());
+ ASSERT_EQ(0, mFlinger.getPendingTransactionQueue().size());
// called in SurfaceFlinger::signalTransaction
EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
@@ -275,7 +275,7 @@ TEST_F(TransactionApplicationTest, Flush_RemovesFromQueue) {
transactionA.isAutoTimestamp, transactionA.uncacheBuffer,
mHasListenerCallbacks, mCallbacks, transactionA.id);
- auto& transactionQueue = mFlinger.getTransactionQueue();
+ auto& transactionQueue = mFlinger.getPendingTransactionQueue();
ASSERT_EQ(1, transactionQueue.size());
auto& [applyToken, transactionStates] = *(transactionQueue.begin());
@@ -294,9 +294,9 @@ TEST_F(TransactionApplicationTest, Flush_RemovesFromQueue) {
empty.desiredPresentTime, empty.isAutoTimestamp,
empty.uncacheBuffer, mHasListenerCallbacks, mCallbacks, empty.id);
- // flush transaction queue should flush as desiredPresentTime has
+ // flush pending transaction queue should flush as desiredPresentTime has
// passed
- mFlinger.flushTransactionQueues();
+ mFlinger.flushPendingTransactionQueues();
EXPECT_EQ(0, transactionQueue.size());
}