diff options
author | 2023-04-18 08:30:00 +0000 | |
---|---|---|
committer | 2023-05-11 14:43:24 +0000 | |
commit | 23780be14df464f815d3fab7466d216cfbb2eae3 (patch) | |
tree | 5478755eeb74e02a2c42dc080abd3a569d452ec4 | |
parent | 50fe0d960d1df5d6d99e6808d0cb941f2bc7f772 (diff) |
Track transaction merges through transaction trace
Bug: 233371599
Bug: 278663063
Test: dump a transaction trace and ensure transactions have the list of merged transaction ids in the proto
Change-Id: I3edf8f1443a2573ef2086f221ceeef57172ecdbe
-rw-r--r-- | libs/gui/ISurfaceComposer.cpp | 29 | ||||
-rw-r--r-- | libs/gui/SurfaceComposerClient.cpp | 41 | ||||
-rw-r--r-- | libs/gui/include/gui/ISurfaceComposer.h | 2 | ||||
-rw-r--r-- | libs/gui/include/gui/SurfaceComposerClient.h | 7 | ||||
-rw-r--r-- | libs/gui/tests/Surface_test.cpp | 18 | ||||
-rw-r--r-- | services/surfaceflinger/SurfaceFlinger.cpp | 6 | ||||
-rw-r--r-- | services/surfaceflinger/SurfaceFlinger.h | 16 | ||||
-rw-r--r-- | services/surfaceflinger/Tracing/TransactionProtoParser.cpp | 7 | ||||
-rw-r--r-- | services/surfaceflinger/TransactionState.h | 7 | ||||
-rw-r--r-- | services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp | 5 | ||||
-rw-r--r-- | services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h | 19 | ||||
-rw-r--r-- | services/surfaceflinger/layerproto/transactions.proto | 1 | ||||
-rw-r--r-- | services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h | 19 | ||||
-rw-r--r-- | services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp | 154 | ||||
-rw-r--r-- | services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp | 11 |
15 files changed, 274 insertions, 68 deletions
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index d72f65eb7a..b526a6c92c 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -59,15 +59,13 @@ public: virtual ~BpSurfaceComposer(); - status_t setTransactionState(const FrameTimelineInfo& frameTimelineInfo, - Vector<ComposerState>& state, const Vector<DisplayState>& displays, - uint32_t flags, const sp<IBinder>& applyToken, - InputWindowCommands commands, int64_t desiredPresentTime, - bool isAutoTimestamp, - const std::vector<client_cache_t>& uncacheBuffers, - bool hasListenerCallbacks, - const std::vector<ListenerCallbacks>& listenerCallbacks, - uint64_t transactionId) override { + status_t setTransactionState( + const FrameTimelineInfo& frameTimelineInfo, Vector<ComposerState>& state, + const Vector<DisplayState>& displays, uint32_t flags, const sp<IBinder>& applyToken, + InputWindowCommands commands, int64_t desiredPresentTime, bool isAutoTimestamp, + const std::vector<client_cache_t>& uncacheBuffers, bool hasListenerCallbacks, + const std::vector<ListenerCallbacks>& listenerCallbacks, uint64_t transactionId, + const std::vector<uint64_t>& mergedTransactionIds) override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); @@ -103,6 +101,11 @@ public: SAFE_PARCEL(data.writeUint64, transactionId); + SAFE_PARCEL(data.writeUint32, static_cast<uint32_t>(mergedTransactionIds.size())); + for (auto mergedTransactionId : mergedTransactionIds) { + SAFE_PARCEL(data.writeUint64, mergedTransactionId); + } + if (flags & ISurfaceComposer::eOneWay) { return remote()->transact(BnSurfaceComposer::SET_TRANSACTION_STATE, data, &reply, IBinder::FLAG_ONEWAY); @@ -187,10 +190,16 @@ status_t BnSurfaceComposer::onTransact( uint64_t transactionId = -1; SAFE_PARCEL(data.readUint64, &transactionId); + SAFE_PARCEL_READ_SIZE(data.readUint32, &count, data.dataSize()); + std::vector<uint64_t> mergedTransactions(count); + for (size_t i = 0; i < count; i++) { + SAFE_PARCEL(data.readUint64, &mergedTransactions[i]); + } + return setTransactionState(frameTimelineInfo, state, displays, stateFlags, applyToken, std::move(inputWindowCommands), desiredPresentTime, isAutoTimestamp, uncacheBuffers, hasListenerCallbacks, - listenerCallbacks, transactionId); + listenerCallbacks, transactionId, mergedTransactions); } default: { return BBinder::onTransact(code, data, reply, flags); diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 1b13ec1c06..08a1a058e1 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -827,6 +827,15 @@ status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel SAFE_PARCEL(parcel->readUint64, &uncacheBuffers[i].id); } + count = static_cast<size_t>(parcel->readUint32()); + if (count > parcel->dataSize()) { + return BAD_VALUE; + } + std::vector<uint64_t> mergedTransactionIds(count); + for (size_t i = 0; i < count; i++) { + SAFE_PARCEL(parcel->readUint64, &mergedTransactionIds[i]); + } + // Parsing was successful. Update the object. mId = transactionId; mTransactionNestCount = transactionNestCount; @@ -842,6 +851,7 @@ status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel mInputWindowCommands = inputWindowCommands; mApplyToken = applyToken; mUncacheBuffers = std::move(uncacheBuffers); + mMergedTransactionIds = std::move(mergedTransactionIds); return NO_ERROR; } @@ -900,6 +910,11 @@ status_t SurfaceComposerClient::Transaction::writeToParcel(Parcel* parcel) const SAFE_PARCEL(parcel->writeUint64, uncacheBuffer.id); } + SAFE_PARCEL(parcel->writeUint32, static_cast<uint32_t>(mMergedTransactionIds.size())); + for (auto mergedTransactionId : mMergedTransactionIds) { + SAFE_PARCEL(parcel->writeUint64, mergedTransactionId); + } + return NO_ERROR; } @@ -924,6 +939,22 @@ void SurfaceComposerClient::Transaction::releaseBufferIfOverwriting(const layer_ } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Transaction&& other) { + while (mMergedTransactionIds.size() + other.mMergedTransactionIds.size() > + MAX_MERGE_HISTORY_LENGTH - 1 && + mMergedTransactionIds.size() > 0) { + mMergedTransactionIds.pop_back(); + } + if (other.mMergedTransactionIds.size() == MAX_MERGE_HISTORY_LENGTH) { + mMergedTransactionIds.insert(mMergedTransactionIds.begin(), + other.mMergedTransactionIds.begin(), + other.mMergedTransactionIds.end() - 1); + } else if (other.mMergedTransactionIds.size() > 0u) { + mMergedTransactionIds.insert(mMergedTransactionIds.begin(), + other.mMergedTransactionIds.begin(), + other.mMergedTransactionIds.end()); + } + mMergedTransactionIds.insert(mMergedTransactionIds.begin(), other.mId); + for (auto const& [handle, composerState] : other.mComposerStates) { if (mComposerStates.count(handle) == 0) { mComposerStates[handle] = composerState; @@ -998,12 +1029,17 @@ void SurfaceComposerClient::Transaction::clear() { mIsAutoTimestamp = true; clearFrameTimelineInfo(mFrameTimelineInfo); mApplyToken = nullptr; + mMergedTransactionIds.clear(); } uint64_t SurfaceComposerClient::Transaction::getId() { return mId; } +std::vector<uint64_t> SurfaceComposerClient::Transaction::getMergedTransactionIds() { + return mMergedTransactionIds; +} + void SurfaceComposerClient::doUncacheBufferTransaction(uint64_t cacheId) { sp<ISurfaceComposer> sf(ComposerService::getComposerService()); @@ -1014,7 +1050,7 @@ void SurfaceComposerClient::doUncacheBufferTransaction(uint64_t cacheId) { status_t status = sf->setTransactionState(FrameTimelineInfo{}, composerStates, {}, ISurfaceComposer::eOneWay, Transaction::getDefaultApplyToken(), {}, systemTime(), - true, {uncacheBuffer}, false, {}, generateId()); + true, {uncacheBuffer}, false, {}, generateId(), {}); if (status != NO_ERROR) { ALOGE_AND_TRACE("SurfaceComposerClient::doUncacheBufferTransaction - %s", strerror(-status)); @@ -1189,7 +1225,8 @@ status_t SurfaceComposerClient::Transaction::apply(bool synchronous, bool oneWay sp<ISurfaceComposer> sf(ComposerService::getComposerService()); sf->setTransactionState(mFrameTimelineInfo, composerStates, displayStates, flags, applyToken, mInputWindowCommands, mDesiredPresentTime, mIsAutoTimestamp, - mUncacheBuffers, hasListenerCallbacks, listenerCallbacks, mId); + mUncacheBuffers, hasListenerCallbacks, listenerCallbacks, mId, + mMergedTransactionIds); mId = generateId(); // Clear the current states and flags diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index bd21851c14..7c150d53d9 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -116,7 +116,7 @@ public: InputWindowCommands inputWindowCommands, int64_t desiredPresentTime, bool isAutoTimestamp, const std::vector<client_cache_t>& uncacheBuffer, bool hasListenerCallbacks, const std::vector<ListenerCallbacks>& listenerCallbacks, - uint64_t transactionId) = 0; + uint64_t transactionId, const std::vector<uint64_t>& mergedTransactionIds) = 0; }; // ---------------------------------------------------------------------------- diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 8d2cdaf5b8..fb57f63dad 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -419,6 +419,11 @@ public: mListenerCallbacks; std::vector<client_cache_t> mUncacheBuffers; + // We keep track of the last MAX_MERGE_HISTORY_LENGTH merged transaction ids. + // Ordered most recently merged to least recently merged. + static const size_t MAX_MERGE_HISTORY_LENGTH = 10u; + std::vector<uint64_t> mMergedTransactionIds; + uint64_t mId; uint32_t mTransactionNestCount = 0; @@ -482,6 +487,8 @@ public: // The id is updated every time the transaction is applied. uint64_t getId(); + std::vector<uint64_t> getMergedTransactionIds(); + status_t apply(bool synchronous = false, bool oneWay = false); // Merge another transaction in to this one, clearing other // as if it had been applied. diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 5bc6904563..096a43cd95 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -695,16 +695,14 @@ public: mSupportsPresent = supportsPresent; } - status_t setTransactionState(const FrameTimelineInfo& /*frameTimelineInfo*/, - Vector<ComposerState>& /*state*/, - const Vector<DisplayState>& /*displays*/, uint32_t /*flags*/, - const sp<IBinder>& /*applyToken*/, - InputWindowCommands /*inputWindowCommands*/, - int64_t /*desiredPresentTime*/, bool /*isAutoTimestamp*/, - const std::vector<client_cache_t>& /*cachedBuffer*/, - bool /*hasListenerCallbacks*/, - const std::vector<ListenerCallbacks>& /*listenerCallbacks*/, - uint64_t /*transactionId*/) override { + status_t setTransactionState( + const FrameTimelineInfo& /*frameTimelineInfo*/, Vector<ComposerState>& /*state*/, + const Vector<DisplayState>& /*displays*/, uint32_t /*flags*/, + const sp<IBinder>& /*applyToken*/, InputWindowCommands /*inputWindowCommands*/, + int64_t /*desiredPresentTime*/, bool /*isAutoTimestamp*/, + const std::vector<client_cache_t>& /*cachedBuffer*/, bool /*hasListenerCallbacks*/, + const std::vector<ListenerCallbacks>& /*listenerCallbacks*/, uint64_t /*transactionId*/, + const std::vector<uint64_t>& /*mergedTransactionIds*/) override { return NO_ERROR; } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index dfe8c72bca..b87b36f7db 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -4474,7 +4474,8 @@ status_t SurfaceFlinger::setTransactionState( const Vector<DisplayState>& displays, uint32_t flags, const sp<IBinder>& applyToken, InputWindowCommands inputWindowCommands, int64_t desiredPresentTime, bool isAutoTimestamp, const std::vector<client_cache_t>& uncacheBuffers, bool hasListenerCallbacks, - const std::vector<ListenerCallbacks>& listenerCallbacks, uint64_t transactionId) { + const std::vector<ListenerCallbacks>& listenerCallbacks, uint64_t transactionId, + const std::vector<uint64_t>& mergedTransactionIds) { ATRACE_CALL(); IPCThreadState* ipc = IPCThreadState::self(); @@ -4563,7 +4564,8 @@ status_t SurfaceFlinger::setTransactionState( listenerCallbacks, originPid, originUid, - transactionId}; + transactionId, + mergedTransactionIds}; if (mTransactionTracing) { mTransactionTracing->addQueuedTransaction(state); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index d92ec7a3b6..45a82ed23e 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -508,15 +508,13 @@ private: } sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId displayId) const; - status_t setTransactionState(const FrameTimelineInfo& frameTimelineInfo, - Vector<ComposerState>& state, const Vector<DisplayState>& displays, - uint32_t flags, const sp<IBinder>& applyToken, - InputWindowCommands inputWindowCommands, - int64_t desiredPresentTime, bool isAutoTimestamp, - const std::vector<client_cache_t>& uncacheBuffers, - bool hasListenerCallbacks, - const std::vector<ListenerCallbacks>& listenerCallbacks, - uint64_t transactionId) override; + status_t setTransactionState( + const FrameTimelineInfo& frameTimelineInfo, Vector<ComposerState>& state, + const Vector<DisplayState>& displays, uint32_t flags, const sp<IBinder>& applyToken, + InputWindowCommands inputWindowCommands, int64_t desiredPresentTime, + bool isAutoTimestamp, const std::vector<client_cache_t>& uncacheBuffers, + bool hasListenerCallbacks, const std::vector<ListenerCallbacks>& listenerCallbacks, + uint64_t transactionId, const std::vector<uint64_t>& mergedTransactionIds) override; void bootFinished(); virtual status_t getSupportedFrameTimestamps(std::vector<FrameEvent>* outSupported) const; sp<IDisplayEventConnection> createDisplayEventConnection( diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp index 57d927b6bb..06941809ba 100644 --- a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp +++ b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp @@ -69,6 +69,13 @@ proto::TransactionState TransactionProtoParser::toProto(const TransactionState& for (auto& displayState : t.displays) { proto.mutable_display_changes()->Add(std::move(toProto(displayState))); } + + proto.mutable_merged_transaction_ids()->Reserve( + static_cast<int32_t>(t.mergedTransactionIds.size())); + for (auto& mergedTransactionId : t.mergedTransactionIds) { + proto.mutable_merged_transaction_ids()->Add(mergedTransactionId); + } + return proto; } diff --git a/services/surfaceflinger/TransactionState.h b/services/surfaceflinger/TransactionState.h index 62a7dfd0f1..7132a59016 100644 --- a/services/surfaceflinger/TransactionState.h +++ b/services/surfaceflinger/TransactionState.h @@ -56,7 +56,8 @@ struct TransactionState { int64_t desiredPresentTime, bool isAutoTimestamp, std::vector<uint64_t> uncacheBufferIds, int64_t postTime, bool hasListenerCallbacks, std::vector<ListenerCallbacks> listenerCallbacks, - int originPid, int originUid, uint64_t transactionId) + int originPid, int originUid, uint64_t transactionId, + std::vector<uint64_t> mergedTransactionIds) : frameTimelineInfo(frameTimelineInfo), states(std::move(composerStates)), displays(displayStates), @@ -71,7 +72,8 @@ struct TransactionState { listenerCallbacks(listenerCallbacks), originPid(originPid), originUid(originUid), - id(transactionId) {} + id(transactionId), + mergedTransactionIds(std::move(mergedTransactionIds)) {} // Invokes `void(const layer_state_t&)` visitor for matching layers. template <typename Visitor> @@ -131,6 +133,7 @@ struct TransactionState { int originUid; uint64_t id; bool sentFenceTimeoutWarning = false; + std::vector<uint64_t> mergedTransactionIds; }; } // namespace android diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp index ce4d18fbe1..80943b5b63 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp +++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp @@ -185,11 +185,12 @@ void SurfaceFlingerFuzzer::setTransactionState() { bool hasListenerCallbacks = mFdp.ConsumeBool(); std::vector<ListenerCallbacks> listenerCallbacks{}; uint64_t transactionId = mFdp.ConsumeIntegral<uint64_t>(); + std::vector<uint64_t> mergedTransactionIds{}; mTestableFlinger.setTransactionState(FrameTimelineInfo{}, states, displays, flags, applyToken, InputWindowCommands{}, desiredPresentTime, isAutoTimestamp, - {}, hasListenerCallbacks, listenerCallbacks, - transactionId); + {}, hasListenerCallbacks, listenerCallbacks, transactionId, + mergedTransactionIds); } void SurfaceFlingerFuzzer::setDisplayStateLocked() { diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h index 4d13aca5bb..da5ec480cc 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h +++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h @@ -737,19 +737,18 @@ public: return mFlinger->mTransactionHandler.mPendingTransactionQueues; } - auto setTransactionState(const FrameTimelineInfo& frameTimelineInfo, - Vector<ComposerState>& states, const Vector<DisplayState>& displays, - uint32_t flags, const sp<IBinder>& applyToken, - const InputWindowCommands& inputWindowCommands, - int64_t desiredPresentTime, bool isAutoTimestamp, - const std::vector<client_cache_t>& uncacheBuffers, - bool hasListenerCallbacks, - std::vector<ListenerCallbacks>& listenerCallbacks, - uint64_t transactionId) { + auto setTransactionState( + const FrameTimelineInfo& frameTimelineInfo, Vector<ComposerState>& states, + const Vector<DisplayState>& displays, uint32_t flags, const sp<IBinder>& applyToken, + const InputWindowCommands& inputWindowCommands, int64_t desiredPresentTime, + bool isAutoTimestamp, const std::vector<client_cache_t>& uncacheBuffers, + bool hasListenerCallbacks, std::vector<ListenerCallbacks>& listenerCallbacks, + uint64_t transactionId, const std::vector<uint64_t>& mergedTransactionIds) { return mFlinger->setTransactionState(frameTimelineInfo, states, displays, flags, applyToken, inputWindowCommands, desiredPresentTime, isAutoTimestamp, uncacheBuffers, hasListenerCallbacks, - listenerCallbacks, transactionId); + listenerCallbacks, transactionId, + mergedTransactionIds); } auto flushTransactionQueues() { diff --git a/services/surfaceflinger/layerproto/transactions.proto b/services/surfaceflinger/layerproto/transactions.proto index 2c4eb101e6..b0cee9b398 100644 --- a/services/surfaceflinger/layerproto/transactions.proto +++ b/services/surfaceflinger/layerproto/transactions.proto @@ -100,6 +100,7 @@ message TransactionState { uint64 transaction_id = 6; repeated LayerState layer_changes = 7; repeated DisplayState display_changes = 8; + repeated uint64 merged_transaction_ids = 9; } // Keep insync with layer_state_t diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index a189c002c9..856606488b 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -466,19 +466,18 @@ public: return mFlinger->mTransactionHandler.mPendingTransactionCount.load(); } - auto setTransactionState(const FrameTimelineInfo& frameTimelineInfo, - Vector<ComposerState>& states, const Vector<DisplayState>& displays, - uint32_t flags, const sp<IBinder>& applyToken, - const InputWindowCommands& inputWindowCommands, - int64_t desiredPresentTime, bool isAutoTimestamp, - const std::vector<client_cache_t>& uncacheBuffers, - bool hasListenerCallbacks, - std::vector<ListenerCallbacks>& listenerCallbacks, - uint64_t transactionId) { + auto setTransactionState( + const FrameTimelineInfo& frameTimelineInfo, Vector<ComposerState>& states, + const Vector<DisplayState>& displays, uint32_t flags, const sp<IBinder>& applyToken, + const InputWindowCommands& inputWindowCommands, int64_t desiredPresentTime, + bool isAutoTimestamp, const std::vector<client_cache_t>& uncacheBuffers, + bool hasListenerCallbacks, std::vector<ListenerCallbacks>& listenerCallbacks, + uint64_t transactionId, const std::vector<uint64_t>& mergedTransactionIds) { return mFlinger->setTransactionState(frameTimelineInfo, states, displays, flags, applyToken, inputWindowCommands, desiredPresentTime, isAutoTimestamp, uncacheBuffers, hasListenerCallbacks, - listenerCallbacks, transactionId); + listenerCallbacks, transactionId, + mergedTransactionIds); } auto setTransactionStateInternal(TransactionState& transaction) { diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp index 6a641b3926..afb8efbfff 100644 --- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp @@ -73,6 +73,7 @@ public: FrameTimelineInfo frameTimelineInfo; std::vector<client_cache_t> uncacheBuffers; uint64_t id = static_cast<uint64_t>(-1); + std::vector<uint64_t> mergedTransactionIds; static_assert(0xffffffffffffffff == static_cast<uint64_t>(-1)); }; @@ -108,7 +109,7 @@ public: transaction.applyToken, transaction.inputWindowCommands, transaction.desiredPresentTime, transaction.isAutoTimestamp, transaction.uncacheBuffers, mHasListenerCallbacks, mCallbacks, - transaction.id); + transaction.id, transaction.mergedTransactionIds); // If transaction is synchronous, SF applyTransactionState should time out (5s) wating for // SF to commit the transaction. If this is animation, it should not time out waiting. @@ -135,7 +136,7 @@ public: transaction.applyToken, transaction.inputWindowCommands, transaction.desiredPresentTime, transaction.isAutoTimestamp, transaction.uncacheBuffers, mHasListenerCallbacks, mCallbacks, - transaction.id); + transaction.id, transaction.mergedTransactionIds); nsecs_t returnedTime = systemTime(); EXPECT_LE(returnedTime, applicationSentTime + TRANSACTION_TIMEOUT); @@ -166,7 +167,7 @@ public: transactionA.applyToken, transactionA.inputWindowCommands, transactionA.desiredPresentTime, transactionA.isAutoTimestamp, transactionA.uncacheBuffers, mHasListenerCallbacks, mCallbacks, - transactionA.id); + transactionA.id, transactionA.mergedTransactionIds); // This thread should not have been blocked by the above transaction // (5s is the timeout period that applyTransactionState waits for SF to @@ -181,7 +182,7 @@ public: transactionB.applyToken, transactionB.inputWindowCommands, transactionB.desiredPresentTime, transactionB.isAutoTimestamp, transactionB.uncacheBuffers, mHasListenerCallbacks, mCallbacks, - transactionB.id); + transactionB.id, transactionB.mergedTransactionIds); // this thread should have been blocked by the above transaction // if this is an animation, this thread should be blocked for 5s @@ -218,7 +219,8 @@ TEST_F(TransactionApplicationTest, AddToPendingQueue) { transactionA.displays, transactionA.flags, transactionA.applyToken, transactionA.inputWindowCommands, transactionA.desiredPresentTime, transactionA.isAutoTimestamp, transactionA.uncacheBuffers, - mHasListenerCallbacks, mCallbacks, transactionA.id); + mHasListenerCallbacks, mCallbacks, transactionA.id, + transactionA.mergedTransactionIds); auto& transactionQueue = mFlinger.getTransactionQueue(); ASSERT_FALSE(transactionQueue.isEmpty()); @@ -238,7 +240,8 @@ TEST_F(TransactionApplicationTest, Flush_RemovesFromQueue) { transactionA.displays, transactionA.flags, transactionA.applyToken, transactionA.inputWindowCommands, transactionA.desiredPresentTime, transactionA.isAutoTimestamp, transactionA.uncacheBuffers, - mHasListenerCallbacks, mCallbacks, transactionA.id); + mHasListenerCallbacks, mCallbacks, transactionA.id, + transactionA.mergedTransactionIds); auto& transactionQueue = mFlinger.getTransactionQueue(); ASSERT_FALSE(transactionQueue.isEmpty()); @@ -251,7 +254,8 @@ TEST_F(TransactionApplicationTest, Flush_RemovesFromQueue) { mFlinger.setTransactionState(empty.frameTimelineInfo, empty.states, empty.displays, empty.flags, empty.applyToken, empty.inputWindowCommands, empty.desiredPresentTime, empty.isAutoTimestamp, - empty.uncacheBuffers, mHasListenerCallbacks, mCallbacks, empty.id); + empty.uncacheBuffers, mHasListenerCallbacks, mCallbacks, empty.id, + empty.mergedTransactionIds); // flush transaction queue should flush as desiredPresentTime has // passed @@ -388,7 +392,8 @@ public: transaction.desiredPresentTime, transaction.isAutoTimestamp, {}, systemTime(), mHasListenerCallbacks, mCallbacks, getpid(), - static_cast<int>(getuid()), transaction.id); + static_cast<int>(getuid()), transaction.id, + transaction.mergedTransactionIds); mFlinger.setTransactionStateInternal(transactionState); } mFlinger.flushTransactionQueues(); @@ -1083,4 +1088,137 @@ TEST(TransactionHandlerTest, QueueTransaction) { EXPECT_EQ(transactionsReadyToBeApplied.front().id, 42u); } +TEST(TransactionHandlerTest, TransactionsKeepTrackOfDirectMerges) { + SurfaceComposerClient::Transaction transaction1, transaction2, transaction3, transaction4; + + uint64_t transaction2Id = transaction2.getId(); + uint64_t transaction3Id = transaction3.getId(); + EXPECT_NE(transaction2Id, transaction3Id); + + transaction1.merge(std::move(transaction2)); + transaction1.merge(std::move(transaction3)); + + EXPECT_EQ(transaction1.getMergedTransactionIds().size(), 2u); + EXPECT_EQ(transaction1.getMergedTransactionIds()[0], transaction3Id); + EXPECT_EQ(transaction1.getMergedTransactionIds()[1], transaction2Id); +} + +TEST(TransactionHandlerTest, TransactionsKeepTrackOfIndirectMerges) { + SurfaceComposerClient::Transaction transaction1, transaction2, transaction3, transaction4; + + uint64_t transaction2Id = transaction2.getId(); + uint64_t transaction3Id = transaction3.getId(); + uint64_t transaction4Id = transaction4.getId(); + EXPECT_NE(transaction2Id, transaction3Id); + EXPECT_NE(transaction2Id, transaction4Id); + EXPECT_NE(transaction3Id, transaction4Id); + + transaction4.merge(std::move(transaction2)); + transaction4.merge(std::move(transaction3)); + + EXPECT_EQ(transaction4.getMergedTransactionIds().size(), 2u); + EXPECT_EQ(transaction4.getMergedTransactionIds()[0], transaction3Id); + EXPECT_EQ(transaction4.getMergedTransactionIds()[1], transaction2Id); + + transaction1.merge(std::move(transaction4)); + + EXPECT_EQ(transaction1.getMergedTransactionIds().size(), 3u); + EXPECT_EQ(transaction1.getMergedTransactionIds()[0], transaction4Id); + EXPECT_EQ(transaction1.getMergedTransactionIds()[1], transaction3Id); + EXPECT_EQ(transaction1.getMergedTransactionIds()[2], transaction2Id); +} + +TEST(TransactionHandlerTest, TransactionMergesAreCleared) { + SurfaceComposerClient::Transaction transaction1, transaction2, transaction3; + + transaction1.merge(std::move(transaction2)); + transaction1.merge(std::move(transaction3)); + + EXPECT_EQ(transaction1.getMergedTransactionIds().size(), 2u); + + transaction1.clear(); + + EXPECT_EQ(transaction1.getMergedTransactionIds().empty(), true); +} + +TEST(TransactionHandlerTest, TransactionMergesAreCapped) { + SurfaceComposerClient::Transaction transaction; + std::vector<uint64_t> mergedTransactionIds; + + for (uint i = 0; i < 20u; i++) { + SurfaceComposerClient::Transaction transactionToMerge; + mergedTransactionIds.push_back(transactionToMerge.getId()); + transaction.merge(std::move(transactionToMerge)); + } + + // Keeps latest 10 merges in order of merge recency + EXPECT_EQ(transaction.getMergedTransactionIds().size(), 10u); + for (uint i = 0; i < 10u; i++) { + EXPECT_EQ(transaction.getMergedTransactionIds()[i], + mergedTransactionIds[mergedTransactionIds.size() - 1 - i]); + } +} + +TEST(TransactionHandlerTest, KeepsMergesFromMoreRecentMerge) { + SurfaceComposerClient::Transaction transaction1, transaction2, transaction3; + std::vector<uint64_t> mergedTransactionIds1, mergedTransactionIds2, mergedTransactionIds3; + uint64_t transaction2Id = transaction2.getId(); + uint64_t transaction3Id = transaction3.getId(); + + for (uint i = 0; i < 20u; i++) { + SurfaceComposerClient::Transaction transactionToMerge; + mergedTransactionIds1.push_back(transactionToMerge.getId()); + transaction1.merge(std::move(transactionToMerge)); + } + + for (uint i = 0; i < 5u; i++) { + SurfaceComposerClient::Transaction transactionToMerge; + mergedTransactionIds2.push_back(transactionToMerge.getId()); + transaction2.merge(std::move(transactionToMerge)); + } + + transaction1.merge(std::move(transaction2)); + EXPECT_EQ(transaction1.getMergedTransactionIds().size(), 10u); + EXPECT_EQ(transaction1.getMergedTransactionIds()[0], transaction2Id); + for (uint i = 0; i < 5u; i++) { + EXPECT_EQ(transaction1.getMergedTransactionIds()[i + 1u], + mergedTransactionIds2[mergedTransactionIds2.size() - 1 - i]); + } + for (uint i = 0; i < 4u; i++) { + EXPECT_EQ(transaction1.getMergedTransactionIds()[i + 6u], + mergedTransactionIds1[mergedTransactionIds1.size() - 1 - i]); + } + + for (uint i = 0; i < 20u; i++) { + SurfaceComposerClient::Transaction transactionToMerge; + mergedTransactionIds3.push_back(transactionToMerge.getId()); + transaction3.merge(std::move(transactionToMerge)); + } + + transaction1.merge(std::move(transaction3)); + EXPECT_EQ(transaction1.getMergedTransactionIds().size(), 10u); + EXPECT_EQ(transaction1.getMergedTransactionIds()[0], transaction3Id); + for (uint i = 0; i < 9u; i++) { + EXPECT_EQ(transaction1.getMergedTransactionIds()[i + 1], + mergedTransactionIds3[mergedTransactionIds3.size() - 1 - i]); + } +} + +TEST(TransactionHandlerTest, CanAddTransactionWithFullMergedIds) { + SurfaceComposerClient::Transaction transaction1, transaction2; + for (uint i = 0; i < 20u; i++) { + SurfaceComposerClient::Transaction transactionToMerge; + transaction1.merge(std::move(transactionToMerge)); + } + + EXPECT_EQ(transaction1.getMergedTransactionIds().size(), 10u); + + auto transaction1Id = transaction1.getId(); + transaction2.merge(std::move(transaction1)); + EXPECT_EQ(transaction2.getMergedTransactionIds().size(), 10u); + auto mergedTransactionIds = transaction2.getMergedTransactionIds(); + EXPECT_TRUE(std::count(mergedTransactionIds.begin(), mergedTransactionIds.end(), + transaction1Id) > 0); +} + } // namespace android diff --git a/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp b/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp index 82aac7e4bf..92411a7ba9 100644 --- a/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp @@ -67,8 +67,14 @@ protected: ASSERT_EQ(actualProto.transactions().size(), static_cast<int32_t>(expectedTransactions.size())); for (uint32_t i = 0; i < expectedTransactions.size(); i++) { - EXPECT_EQ(actualProto.transactions(static_cast<int32_t>(i)).pid(), - expectedTransactions[i].originPid); + const auto expectedTransaction = expectedTransactions[i]; + const auto protoTransaction = actualProto.transactions(static_cast<int32_t>(i)); + EXPECT_EQ(protoTransaction.transaction_id(), expectedTransaction.id); + EXPECT_EQ(protoTransaction.pid(), expectedTransaction.originPid); + for (uint32_t i = 0; i < expectedTransaction.mergedTransactionIds.size(); i++) { + EXPECT_EQ(protoTransaction.merged_transaction_ids(static_cast<int32_t>(i)), + expectedTransaction.mergedTransactionIds[i]); + } } } @@ -92,6 +98,7 @@ TEST_F(TransactionTracingTest, addTransactions) { TransactionState transaction; transaction.id = i; transaction.originPid = static_cast<int32_t>(i); + transaction.mergedTransactionIds = std::vector<uint64_t>{i + 100, i + 102}; transactions.emplace_back(transaction); mTracing.addQueuedTransaction(transaction); } |