From 9febda8e05bbd924d14682454fdc7a846c38f954 Mon Sep 17 00:00:00 2001 From: Adithya Srinivasan Date: Mon, 19 Oct 2020 10:49:41 -0700 Subject: Plumb owner pid into Layer For shared timeline visualization, the pid of the process owning the layer is needed to show the information in the respective process tracks. This change stores the newly added METADATA_OWNER_PID information sent as a part of the Layer creation args Bug: 170911969 Test: pid section of `adb shell dumpsys SurfaceFlinger --frametimeline -` Change-Id: Ib1cd9b6239501b0b92283dca19d7de3916fff604 --- libs/gui/LayerMetadata.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'libs/gui/LayerMetadata.cpp') diff --git a/libs/gui/LayerMetadata.cpp b/libs/gui/LayerMetadata.cpp index b3eb9940b2..30c9b373ef 100644 --- a/libs/gui/LayerMetadata.cpp +++ b/libs/gui/LayerMetadata.cpp @@ -122,6 +122,8 @@ std::string LayerMetadata::itemToString(uint32_t key, const char* separator) con return StringPrintf("windowType%s%d", separator, getInt32(key, 0)); case view::LayerMetadataKey::METADATA_TASK_ID: return StringPrintf("taskId%s%d", separator, getInt32(key, 0)); + case view::LayerMetadataKey::METADATA_OWNER_PID: + return StringPrintf("ownerPID%s%d", separator, getInt32(key, 0)); default: return StringPrintf("%d%s%dbytes", key, separator, static_cast(mMap.at(key).size())); -- cgit v1.2.3-59-g8ed1b From adf632ba3a3298b4e66edfc468cf3888d5f2eac4 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Thu, 7 Jan 2021 14:05:08 -0800 Subject: BlastBufferQueue: Pass client dequeue times to SurfaceFlinger SF keeps track of client dequeue, queue, acquire etc. timestamps to construct frame rendering timelines for developers. With BBQ, SF no longer has access to this data, so pass the dequeue time along with the buffers. Ideally this data should flow to the perfetto trace directly from the client but this is a temp solution while some perf issues with client logging is sorted out. Bug: 176931912 Test: manual tests Change-Id: Ic88170c1fb20850662cb99325ac42b7232a02817 --- aidl/gui/android/view/LayerMetadataKey.aidl | 1 + libs/gui/BLASTBufferQueue.cpp | 20 ++++++++++++++++++++ libs/gui/LayerMetadata.cpp | 12 ++++++++++++ libs/gui/include/gui/BLASTBufferQueue.h | 12 +++++++++++- libs/gui/include/gui/LayerMetadata.h | 3 +++ services/surfaceflinger/BufferStateLayer.cpp | 3 ++- services/surfaceflinger/BufferStateLayer.h | 3 ++- services/surfaceflinger/Layer.h | 2 +- services/surfaceflinger/RefreshRateOverlay.cpp | 6 ++++-- services/surfaceflinger/SurfaceFlinger.cpp | 4 +++- 10 files changed, 59 insertions(+), 7 deletions(-) (limited to 'libs/gui/LayerMetadata.cpp') diff --git a/aidl/gui/android/view/LayerMetadataKey.aidl b/aidl/gui/android/view/LayerMetadataKey.aidl index 491c629278..a1d8ce5962 100644 --- a/aidl/gui/android/view/LayerMetadataKey.aidl +++ b/aidl/gui/android/view/LayerMetadataKey.aidl @@ -25,4 +25,5 @@ enum LayerMetadataKey { METADATA_MOUSE_CURSOR = 4, METADATA_ACCESSIBILITY_ID = 5, METADATA_OWNER_PID = 6, + METADATA_DEQUEUE_TIME = 7, } diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index eaa47f9680..f4b5a26033 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -354,6 +354,16 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { t->setAutoRefresh(mSurfaceControl, bufferItem.mAutoRefresh); mAutoRefresh = bufferItem.mAutoRefresh; } + { + std::unique_lock _lock{mTimestampMutex}; + auto dequeueTime = mDequeueTimestamps.find(buffer->getId()); + if (dequeueTime != mDequeueTimestamps.end()) { + Parcel p; + p.writeInt64(dequeueTime->second); + t->setMetadata(mSurfaceControl, METADATA_DEQUEUE_TIME, p); + mDequeueTimestamps.erase(dequeueTime); + } + } auto mergeTransaction = [&t, currentFrameNumber = bufferItem.mFrameNumber]( @@ -412,6 +422,16 @@ void BLASTBufferQueue::onFrameReplaced(const BufferItem& item) { // Do nothing since we are not storing unacquired buffer items locally. } +void BLASTBufferQueue::onFrameDequeued(const uint64_t bufferId) { + std::unique_lock _lock{mTimestampMutex}; + mDequeueTimestamps[bufferId] = systemTime(); +}; + +void BLASTBufferQueue::onFrameCancelled(const uint64_t bufferId) { + std::unique_lock _lock{mTimestampMutex}; + mDequeueTimestamps.erase(bufferId); +}; + void BLASTBufferQueue::setNextTransaction(SurfaceComposerClient::Transaction* t) { std::lock_guard _lock{mMutex}; mNextTransaction = t; diff --git a/libs/gui/LayerMetadata.cpp b/libs/gui/LayerMetadata.cpp index 30c9b373ef..634d8b7df0 100644 --- a/libs/gui/LayerMetadata.cpp +++ b/libs/gui/LayerMetadata.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include "android/view/LayerMetadataKey.h" @@ -113,6 +114,15 @@ void LayerMetadata::setInt32(uint32_t key, int32_t value) { memcpy(data.data(), p.data(), p.dataSize()); } +std::optional LayerMetadata::getInt64(uint32_t key) const { + if (!has(key)) return std::nullopt; + const std::vector& data = mMap.at(key); + if (data.size() < sizeof(int64_t)) return std::nullopt; + Parcel p; + p.setData(data.data(), data.size()); + return p.readInt64(); +} + std::string LayerMetadata::itemToString(uint32_t key, const char* separator) const { if (!has(key)) return std::string(); switch (static_cast(key)) { @@ -124,6 +134,8 @@ std::string LayerMetadata::itemToString(uint32_t key, const char* separator) con return StringPrintf("taskId%s%d", separator, getInt32(key, 0)); case view::LayerMetadataKey::METADATA_OWNER_PID: return StringPrintf("ownerPID%s%d", separator, getInt32(key, 0)); + case view::LayerMetadataKey::METADATA_DEQUEUE_TIME: + return StringPrintf("dequeueTime%s%" PRId64, separator, *getInt64(key)); default: return StringPrintf("%d%s%dbytes", key, separator, static_cast(mMap.at(key).size())); diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index 1198135b0c..0fbcbdc50f 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -78,6 +78,8 @@ public: void onBufferFreed(const wp&/* graphicBuffer*/) override { /* TODO */ } void onFrameReplaced(const BufferItem& item) override; void onFrameAvailable(const BufferItem& item) override; + void onFrameDequeued(const uint64_t) override; + void onFrameCancelled(const uint64_t) override; void transactionCallback(nsecs_t latchTime, const sp& presentFence, const std::vector& stats); @@ -168,7 +170,15 @@ private: // Queues up transactions using this token in SurfaceFlinger. This prevents queued up // transactions from other parts of the client from blocking this transaction. - const sp mApplyToken = new BBinder(); + const sp mApplyToken GUARDED_BY(mMutex) = new BBinder(); + + // Guards access to mDequeueTimestamps since we cannot hold to mMutex in onFrameDequeued or + // we will deadlock. + std::mutex mTimestampMutex; + // Tracks buffer dequeue times by the client. This info is sent to SurfaceFlinger which uses + // it for debugging purposes. + std::unordered_map mDequeueTimestamps + GUARDED_BY(mTimestampMutex); }; } // namespace android diff --git a/libs/gui/include/gui/LayerMetadata.h b/libs/gui/include/gui/LayerMetadata.h index ac48aefae6..41982c28a2 100644 --- a/libs/gui/include/gui/LayerMetadata.h +++ b/libs/gui/include/gui/LayerMetadata.h @@ -29,6 +29,7 @@ enum { METADATA_MOUSE_CURSOR = 4, METADATA_ACCESSIBILITY_ID = 5, METADATA_OWNER_PID = 6, + METADATA_DEQUEUE_TIME = 7 }; struct LayerMetadata : public Parcelable { @@ -51,6 +52,8 @@ struct LayerMetadata : public Parcelable { bool has(uint32_t key) const; int32_t getInt32(uint32_t key, int32_t fallback) const; void setInt32(uint32_t key, int32_t value); + std::optional getInt64(uint32_t key) const; + void setInt64(uint32_t key, int64_t value); std::string itemToString(uint32_t key, const char* separator) const; }; diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index bca1c69c0f..a431028bde 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -343,7 +343,8 @@ bool BufferStateLayer::addFrameEvent(const sp& acquireFence, nsecs_t post bool BufferStateLayer::setBuffer(const sp& buffer, const sp& acquireFence, nsecs_t postTime, nsecs_t desiredPresentTime, bool isAutoTimestamp, - const client_cache_t& clientCacheId, uint64_t frameNumber) { + const client_cache_t& clientCacheId, uint64_t frameNumber, + std::optional /* dequeueTime */) { ATRACE_CALL(); if (mCurrentState.buffer) { diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h index 6414e6be60..1098606cbb 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -71,7 +71,8 @@ public: bool setFrame(const Rect& frame) override; bool setBuffer(const sp& buffer, const sp& acquireFence, nsecs_t postTime, nsecs_t desiredPresentTime, bool isAutoTimestamp, - const client_cache_t& clientCacheId, uint64_t frameNumber) override; + const client_cache_t& clientCacheId, uint64_t frameNumber, + std::optional dequeueTime) override; bool setAcquireFence(const sp& fence) override; bool setDataspace(ui::Dataspace dataspace) override; bool setHdrMetadata(const HdrMetadata& hdrMetadata) override; diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index d6023b66ac..f78b5f31e9 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -446,7 +446,7 @@ public: virtual bool setBuffer(const sp& /*buffer*/, const sp& /*acquireFence*/, nsecs_t /*postTime*/, nsecs_t /*desiredPresentTime*/, bool /*isAutoTimestamp*/, const client_cache_t& /*clientCacheId*/, - uint64_t /* frameNumber */) { + uint64_t /* frameNumber */, std::optional /* dequeueTime */) { return false; }; virtual bool setAcquireFence(const sp& /*fence*/) { return false; }; diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp index 6a511a85a0..32110e9547 100644 --- a/services/surfaceflinger/RefreshRateOverlay.cpp +++ b/services/surfaceflinger/RefreshRateOverlay.cpp @@ -237,7 +237,8 @@ void RefreshRateOverlay::changeRefreshRate(const RefreshRate& refreshRate) { mCurrentFps = refreshRate.getFps().getIntValue(); auto buffer = getOrCreateBuffers(*mCurrentFps)[mFrame]; mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, true, {}, - mLayer->getHeadFrameNumber(-1 /* expectedPresentTime */)); + mLayer->getHeadFrameNumber(-1 /* expectedPresentTime */), + std::nullopt /* dequeueTime */); mFlinger.mTransactionFlags.fetch_or(eTransactionMask); } @@ -249,7 +250,8 @@ void RefreshRateOverlay::onInvalidate() { mFrame = (mFrame + 1) % buffers.size(); auto buffer = buffers[mFrame]; mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, true, {}, - mLayer->getHeadFrameNumber(-1 /* expectedPresentTime */)); + mLayer->getHeadFrameNumber(-1 /* expectedPresentTime */), + std::nullopt /* dequeueTime */); mFlinger.mTransactionFlags.fetch_or(eTransactionMask); } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 6967f69876..6938d5de57 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3840,7 +3840,9 @@ uint32_t SurfaceFlinger::setClientStateLocked( ALOGE("Attempt to update InputWindowInfo without permission ACCESS_SURFACE_FLINGER"); } } + std::optional dequeueBufferTimestamp; if (what & layer_state_t::eMetadataChanged) { + dequeueBufferTimestamp = s.metadata.getInt64(METADATA_DEQUEUE_TIME); if (layer->setMetadata(s.metadata)) flags |= eTraversalNeeded; } if (what & layer_state_t::eColorSpaceAgnosticChanged) { @@ -3928,7 +3930,7 @@ uint32_t SurfaceFlinger::setClientStateLocked( : layer->getHeadFrameNumber(-1 /* expectedPresentTime */) + 1; if (layer->setBuffer(buffer, s.acquireFence, postTime, desiredPresentTime, isAutoTimestamp, - s.cachedBuffer, frameNumber)) { + s.cachedBuffer, frameNumber, dequeueBufferTimestamp)) { flags |= eTraversalNeeded; } } -- cgit v1.2.3-59-g8ed1b From ac977e6de0cdebddebc2db0efd8cbec94c2bc996 Mon Sep 17 00:00:00 2001 From: Adithya Srinivasan Date: Fri, 21 May 2021 22:50:56 +0000 Subject: SF - plumbing game mode for metrics (Part 1) This change adds a game mode in the Layer metadata that gets updated every time a game app comes to the foreground. The gameMode is then set on the Layer based on the metadata and reparenting. The game mode will then be updated in TimeStats as a dimension (Part 2, in a separate CL later). Bug: 186025682 Test: libsurfaceflinger_unittest:GameModeTest Change-Id: I09deffc01d1b318cc08d0475611289dec055c190 --- aidl/gui/android/view/LayerMetadataKey.aidl | 1 + libs/gui/LayerMetadata.cpp | 2 + libs/gui/include/gui/LayerMetadata.h | 3 +- services/surfaceflinger/Layer.cpp | 14 ++ services/surfaceflinger/Layer.h | 11 ++ services/surfaceflinger/SurfaceFlinger.cpp | 7 + services/surfaceflinger/tests/unittests/Android.bp | 1 + .../tests/unittests/GameModeTest.cpp | 159 +++++++++++++++++++++ 8 files changed, 197 insertions(+), 1 deletion(-) create mode 100644 services/surfaceflinger/tests/unittests/GameModeTest.cpp (limited to 'libs/gui/LayerMetadata.cpp') diff --git a/aidl/gui/android/view/LayerMetadataKey.aidl b/aidl/gui/android/view/LayerMetadataKey.aidl index a1d8ce5962..d6ca3db5d7 100644 --- a/aidl/gui/android/view/LayerMetadataKey.aidl +++ b/aidl/gui/android/view/LayerMetadataKey.aidl @@ -26,4 +26,5 @@ enum LayerMetadataKey { METADATA_ACCESSIBILITY_ID = 5, METADATA_OWNER_PID = 6, METADATA_DEQUEUE_TIME = 7, + METADATA_GAME_MODE = 8, } diff --git a/libs/gui/LayerMetadata.cpp b/libs/gui/LayerMetadata.cpp index 634d8b7df0..189d51a4c1 100644 --- a/libs/gui/LayerMetadata.cpp +++ b/libs/gui/LayerMetadata.cpp @@ -136,6 +136,8 @@ std::string LayerMetadata::itemToString(uint32_t key, const char* separator) con return StringPrintf("ownerPID%s%d", separator, getInt32(key, 0)); case view::LayerMetadataKey::METADATA_DEQUEUE_TIME: return StringPrintf("dequeueTime%s%" PRId64, separator, *getInt64(key)); + case view::LayerMetadataKey::METADATA_GAME_MODE: + return StringPrintf("gameMode%s%d", separator, getInt32(key, 0)); default: return StringPrintf("%d%s%dbytes", key, separator, static_cast(mMap.at(key).size())); diff --git a/libs/gui/include/gui/LayerMetadata.h b/libs/gui/include/gui/LayerMetadata.h index 41982c28a2..de14b3d785 100644 --- a/libs/gui/include/gui/LayerMetadata.h +++ b/libs/gui/include/gui/LayerMetadata.h @@ -29,7 +29,8 @@ enum { METADATA_MOUSE_CURSOR = 4, METADATA_ACCESSIBILITY_ID = 5, METADATA_OWNER_PID = 6, - METADATA_DEQUEUE_TIME = 7 + METADATA_DEQUEUE_TIME = 7, + METADATA_GAME_MODE = 8 }; struct LayerMetadata : public Parcelable { diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index a7c870483b..d78a8223c4 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -1651,12 +1651,25 @@ size_t Layer::getChildrenCount() const { return count; } +void Layer::setGameModeForTree(int parentGameMode) { + int gameMode = parentGameMode; + auto& currentState = getCurrentState(); + if (currentState.metadata.has(METADATA_GAME_MODE)) { + gameMode = currentState.metadata.getInt32(METADATA_GAME_MODE, 0); + } + setGameMode(gameMode); + for (const sp& child : mCurrentChildren) { + child->setGameModeForTree(gameMode); + } +} + void Layer::addChild(const sp& layer) { mChildrenChanged = true; setTransactionFlags(eTransactionNeeded); mCurrentChildren.add(layer); layer->setParent(this); + layer->setGameModeForTree(mGameMode); updateTreeHasFrameRateVote(); } @@ -1668,6 +1681,7 @@ ssize_t Layer::removeChild(const sp& layer) { const auto removeResult = mCurrentChildren.remove(layer); updateTreeHasFrameRateVote(); + layer->setGameModeForTree(0); layer->updateTreeHasFrameRateVote(); return removeResult; diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 66d70185a7..af2604582b 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -847,6 +847,13 @@ public: */ bool hasInputInfo() const; + // Sets the parent's gameMode for this layer and all its children. Parent's gameMode is applied + // only to layers that do not have the GAME_MODE_METADATA set by WMShell. Any layer(along with + // its children) that has the metadata set will use the gameMode from the metadata. + void setGameModeForTree(int parentGameMode); + void setGameMode(int gameMode) { mGameMode = gameMode; }; + int getGameMode() const { return mGameMode; } + virtual uid_t getOwnerUid() const { return mOwnerUid; } pid_t getOwnerPid() { return mOwnerPid; } @@ -1089,6 +1096,10 @@ private: // shadow radius is the set shadow radius, otherwise its the parent's shadow radius. float mEffectiveShadowRadius = 0.f; + // Game mode for the layer. Set by WindowManagerShell, game mode is used in + // metrics(SurfaceFlingerStats). + int mGameMode = 0; + // A list of regions on this layer that should have blurs. const std::vector getBlurRegions() const; }; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 881ee5b8f4..3f75af2908 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -4018,6 +4018,13 @@ uint32_t SurfaceFlinger::setClientStateLocked( std::optional dequeueBufferTimestamp; if (what & layer_state_t::eMetadataChanged) { dequeueBufferTimestamp = s.metadata.getInt64(METADATA_DEQUEUE_TIME); + auto gameMode = s.metadata.getInt32(METADATA_GAME_MODE, -1); + if (gameMode != -1) { + // The transaction will be received on the Task layer and needs to be applied to all + // child layers. Child layers that are added at a later point will obtain the game mode + // info through addChild(). + layer->setGameModeForTree(gameMode); + } if (layer->setMetadata(s.metadata)) flags |= eTraversalNeeded; } if (what & layer_state_t::eColorSpaceAgnosticChanged) { diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index 1b25a3684e..736ef30d7c 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -57,6 +57,7 @@ cc_test { "FpsTest.cpp", "FramebufferSurfaceTest.cpp", "FrameTimelineTest.cpp", + "GameModeTest.cpp", "HWComposerTest.cpp", "OneShotTimerTest.cpp", "LayerHistoryTest.cpp", diff --git a/services/surfaceflinger/tests/unittests/GameModeTest.cpp b/services/surfaceflinger/tests/unittests/GameModeTest.cpp new file mode 100644 index 0000000000..3fa1a2c2f5 --- /dev/null +++ b/services/surfaceflinger/tests/unittests/GameModeTest.cpp @@ -0,0 +1,159 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#undef LOG_TAG +#define LOG_TAG "LibSurfaceFlingerUnittests" + +#include +#include +#include +#include +#include + +#include "TestableSurfaceFlinger.h" +#include "mock/DisplayHardware/MockComposer.h" +#include "mock/MockEventThread.h" +#include "mock/MockVsyncController.h" + +namespace android { + +using testing::_; +using testing::Mock; +using testing::Return; +using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector; + +class GameModeTest : public testing::Test { +public: + GameModeTest() { + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name()); + setupScheduler(); + setupComposer(); + } + + ~GameModeTest() { + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name()); + } + + sp createBufferStateLayer() { + sp client; + LayerCreationArgs args(mFlinger.flinger(), client, "buffer-state-layer", 100, 100, 0, + LayerMetadata()); + return new BufferStateLayer(args); + } + + void setupScheduler() { + auto eventThread = std::make_unique(); + auto sfEventThread = std::make_unique(); + + EXPECT_CALL(*eventThread, registerDisplayEventConnection(_)); + EXPECT_CALL(*eventThread, createEventConnection(_, _)) + .WillOnce(Return(new EventThreadConnection(eventThread.get(), /*callingUid=*/0, + ResyncCallback()))); + + EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_)); + EXPECT_CALL(*sfEventThread, createEventConnection(_, _)) + .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), /*callingUid=*/0, + ResyncCallback()))); + + auto vsyncController = std::make_unique(); + auto vsyncTracker = std::make_unique(); + + EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); + EXPECT_CALL(*vsyncTracker, currentPeriod()) + .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD)); + EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); + mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker), + std::move(eventThread), std::move(sfEventThread)); + } + + void setupComposer() { + mComposer = new Hwc2::mock::Composer(); + mFlinger.setupComposer(std::unique_ptr(mComposer)); + + Mock::VerifyAndClear(mComposer); + } + + // Mocks the behavior of applying a transaction from WMShell + void setGameModeMetadata(sp layer, int gameMode) { + mLayerMetadata.setInt32(METADATA_GAME_MODE, gameMode); + layer->setMetadata(mLayerMetadata); + layer->setGameModeForTree(gameMode); + } + + TestableSurfaceFlinger mFlinger; + Hwc2::mock::Composer* mComposer = nullptr; + client_cache_t mClientCache; + LayerMetadata mLayerMetadata; +}; + +TEST_F(GameModeTest, SetGameModeSetsForAllCurrentChildren) { + sp rootLayer = createBufferStateLayer(); + sp childLayer1 = createBufferStateLayer(); + sp childLayer2 = createBufferStateLayer(); + rootLayer->addChild(childLayer1); + rootLayer->addChild(childLayer2); + rootLayer->setGameModeForTree(/*gameMode*/ 2); + + EXPECT_EQ(rootLayer->getGameMode(), 2); + EXPECT_EQ(childLayer1->getGameMode(), 2); + EXPECT_EQ(childLayer2->getGameMode(), 2); +} + +TEST_F(GameModeTest, AddChildAppliesGameModeFromParent) { + sp rootLayer = createBufferStateLayer(); + sp childLayer = createBufferStateLayer(); + rootLayer->setGameModeForTree(/*gameMode*/ 2); + rootLayer->addChild(childLayer); + + EXPECT_EQ(rootLayer->getGameMode(), 2); + EXPECT_EQ(childLayer->getGameMode(), 2); +} + +TEST_F(GameModeTest, RemoveChildResetsGameMode) { + sp rootLayer = createBufferStateLayer(); + sp childLayer = createBufferStateLayer(); + rootLayer->setGameModeForTree(/*gameMode*/ 2); + rootLayer->addChild(childLayer); + + EXPECT_EQ(rootLayer->getGameMode(), 2); + EXPECT_EQ(childLayer->getGameMode(), 2); + + rootLayer->removeChild(childLayer); + EXPECT_EQ(childLayer->getGameMode(), 0); +} + +TEST_F(GameModeTest, ReparentingDoesNotOverrideMetadata) { + sp rootLayer = createBufferStateLayer(); + sp childLayer1 = createBufferStateLayer(); + sp childLayer2 = createBufferStateLayer(); + rootLayer->setGameModeForTree(/*gameMode*/ 1); + rootLayer->addChild(childLayer1); + + setGameModeMetadata(childLayer2, /*gameMode*/ 2); + rootLayer->addChild(childLayer2); + + EXPECT_EQ(rootLayer->getGameMode(), 1); + EXPECT_EQ(childLayer1->getGameMode(), 1); + EXPECT_EQ(childLayer2->getGameMode(), 2); + + rootLayer->removeChild(childLayer2); + EXPECT_EQ(childLayer2->getGameMode(), 2); +} +} // namespace android \ No newline at end of file -- cgit v1.2.3-59-g8ed1b