diff options
22 files changed, 519 insertions, 226 deletions
diff --git a/data/etc/car_core_hardware.xml b/data/etc/car_core_hardware.xml index adfd6e297b..cc0ee825a8 100644 --- a/data/etc/car_core_hardware.xml +++ b/data/etc/car_core_hardware.xml @@ -47,12 +47,6 @@ <feature name="android.software.secure_lock_screen" /> <feature name="android.software.input_methods" /> - - <!-- Feature to support device admins --> - <!-- TODO(b/178412797): not fully supported yet, CTS tests are still - failing. --> - <feature name="android.software.device_admin" /> - <!-- devices with GPS must include android.hardware.location.gps.xml --> <!-- devices with an autofocus camera and/or flash must include either android.hardware.camera.autofocus.xml or diff --git a/opengl/libs/EGL/egl_platform_entries.cpp b/opengl/libs/EGL/egl_platform_entries.cpp index f57666077e..de36a7aea6 100644 --- a/opengl/libs/EGL/egl_platform_entries.cpp +++ b/opengl/libs/EGL/egl_platform_entries.cpp @@ -1453,7 +1453,9 @@ EGLBoolean eglSurfaceAttribImpl(EGLDisplay dpy, EGLSurface surface, EGLint attri if (attribute == EGL_TIMESTAMPS_ANDROID) { if (!s->getNativeWindow()) { - return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); + // According to the spec, "if surface is not a window surface this has no + // effect." + return EGL_TRUE; } int err = native_window_enable_frame_timestamps(s->getNativeWindow(), value != 0); return (err == 0) ? EGL_TRUE : setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp index e3e6c12485..b19b4195d1 100644 --- a/services/inputflinger/reader/EventHub.cpp +++ b/services/inputflinger/reader/EventHub.cpp @@ -67,6 +67,8 @@ static const char* DEVICE_PATH = "/dev/input"; // v4l2 devices go directly into /dev static const char* VIDEO_DEVICE_PATH = "/dev"; +static constexpr size_t OBFUSCATED_LENGTH = 8; + static constexpr int32_t FF_STRONG_MAGNITUDE_CHANNEL_IDX = 0; static constexpr int32_t FF_WEAK_MAGNITUDE_CHANNEL_IDX = 1; @@ -1828,9 +1830,21 @@ void EventHub::unregisterVideoDeviceFromEpollLocked(const TouchVideoDevice& vide void EventHub::reportDeviceAddedForStatisticsLocked(const InputDeviceIdentifier& identifier, Flags<InputDeviceClass> classes) { + SHA256_CTX ctx; + SHA256_Init(&ctx); + SHA256_Update(&ctx, reinterpret_cast<const uint8_t*>(identifier.uniqueId.c_str()), + identifier.uniqueId.size()); + std::array<uint8_t, SHA256_DIGEST_LENGTH> digest; + SHA256_Final(digest.data(), &ctx); + + std::string obfuscatedId; + for (size_t i = 0; i < OBFUSCATED_LENGTH; i++) { + obfuscatedId += StringPrintf("%02x", digest[i]); + } + android::util::stats_write(android::util::INPUTDEVICE_REGISTERED, identifier.name.c_str(), identifier.vendor, identifier.product, identifier.version, - identifier.bus, identifier.uniqueId.c_str(), classes.get()); + identifier.bus, obfuscatedId.c_str(), classes.get()); } void EventHub::openDeviceLocked(const std::string& devicePath) { diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp index cacad52410..23779be73a 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -425,7 +425,8 @@ bool BufferLayer::onPostComposition(const DisplayDevice* display, mFlinger->mTimeStats->setPresentFence(layerId, mCurrentFrameNumber, presentFence, refreshRate, renderRate, frameRateToSetFrameRateVotePayload( - mDrawingState.frameRate)); + mDrawingState.frameRate), + getGameMode()); mFlinger->mFrameTracer->traceFence(layerId, getCurrentBufferId(), mCurrentFrameNumber, presentFence, FrameTracer::FrameEvent::PRESENT_FENCE); mFrameTracker.setActualPresentFence(std::shared_ptr<FenceTime>(presentFence)); @@ -439,7 +440,8 @@ bool BufferLayer::onPostComposition(const DisplayDevice* display, mFlinger->mTimeStats->setPresentTime(layerId, mCurrentFrameNumber, actualPresentTime, refreshRate, renderRate, frameRateToSetFrameRateVotePayload( - mDrawingState.frameRate)); + mDrawingState.frameRate), + getGameMode()); mFlinger->mFrameTracer->traceTimestamp(layerId, getCurrentBufferId(), mCurrentFrameNumber, actualPresentTime, FrameTracer::FrameEvent::PRESENT_FENCE); diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index 0f0f08afc7..d68a0e0b47 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -448,7 +448,7 @@ bool BufferStateLayer::setBuffer(const std::shared_ptr<renderengine::ExternalTex const int32_t layerId = getSequence(); mFlinger->mTimeStats->setPostTime(layerId, mCurrentState.frameNumber, getName().c_str(), - mOwnerUid, postTime); + mOwnerUid, postTime, getGameMode()); mCurrentState.desiredPresentTime = desiredPresentTime; mCurrentState.isAutoTimestamp = isAutoTimestamp; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h index 269ddd5956..4e2f879291 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h @@ -93,6 +93,7 @@ public: mOutputDataspace = ui::Dataspace::UNKNOWN; mDrawFence = nullptr; mBlurLayer = nullptr; + mHolePunchLayer = nullptr; mLayers.insert(mLayers.end(), other.mLayers.cbegin(), other.mLayers.cend()); Region boundingRegion; @@ -132,6 +133,8 @@ public: compositionengine::OutputLayer* getBlurLayer() const; + bool hasHdrLayers() const; + private: CachedSet() = default; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h index 0b78cb8c0b..13b878192b 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h @@ -240,6 +240,15 @@ public: void resetFramesSinceBufferUpdate() { mFramesSinceBufferUpdate = 0; } int64_t getFramesSinceBufferUpdate() const { return mFramesSinceBufferUpdate; } + ui::Dataspace getDataspace() const { return mOutputDataspace.get(); } + + bool isHdr() const { + const ui::Dataspace transfer = + static_cast<ui::Dataspace>(getDataspace() & ui::Dataspace::TRANSFER_MASK); + return (transfer == ui::Dataspace::TRANSFER_ST2084 || + transfer == ui::Dataspace::TRANSFER_HLG); + } + void dump(std::string& result) const; std::optional<std::string> compare(const LayerState& other) const; diff --git a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp index 3cfb211482..9a294c766e 100644 --- a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp +++ b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp @@ -228,7 +228,6 @@ void CachedSet::render(renderengine::RenderEngine& renderEngine, // Assume that the final layer contains the buffer that we want to // replace with a hole punch. holePunchSettings = clientCompositionList.back(); - LOG_ALWAYS_FATAL_IF(!holePunchSettings.source.buffer.buffer, "Expected to have a buffer!"); // This mimics Layer::prepareClearClientComposition holePunchSettings.source.buffer.buffer = nullptr; holePunchSettings.source.solidColor = half3(0.0f, 0.0f, 0.0f); @@ -346,6 +345,11 @@ compositionengine::OutputLayer* CachedSet::getBlurLayer() const { return mBlurLayer ? mBlurLayer->getOutputLayer() : nullptr; } +bool CachedSet::hasHdrLayers() const { + return std::any_of(mLayers.cbegin(), mLayers.cend(), + [](const Layer& layer) { return layer.getState()->isHdr(); }); +} + void CachedSet::dump(std::string& result) const { const auto now = std::chrono::steady_clock::now(); diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp index ef4633568c..550fdebea4 100644 --- a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp +++ b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp @@ -231,6 +231,7 @@ bool Flattener::mergeWithCachedSets(const std::vector<const LayerState*>& layers return false; } + // the compiler should strip out the following no-op loops when ALOGV is off ALOGV("[%s] Incoming layers:", __func__); for (const LayerState* layer : layers) { ALOGV("%s", layer->getName().c_str()); @@ -238,9 +239,12 @@ bool Flattener::mergeWithCachedSets(const std::vector<const LayerState*>& layers ALOGV("[%s] Current layers:", __func__); for (const CachedSet& layer : mLayers) { - std::string dump; - layer.dump(dump); - ALOGV("%s", dump.c_str()); + const auto dumper = [&] { + std::string dump; + layer.dump(dump); + return dump; + }; + ALOGV("%s", dumper().c_str()); } auto currentLayerIter = mLayers.begin(); @@ -368,7 +372,8 @@ std::vector<Flattener::Run> Flattener::findCandidateRuns(time_point now) const { for (auto currentSet = mLayers.cbegin(); currentSet != mLayers.cend(); ++currentSet) { const bool layerIsInactive = now - currentSet->getLastUpdate() > kActiveLayerTimeout; const bool layerHasBlur = currentSet->hasBlurBehind(); - if (layerIsInactive && (firstLayer || runHasFirstLayer || !layerHasBlur)) { + if (layerIsInactive && (firstLayer || runHasFirstLayer || !layerHasBlur) && + !currentSet->hasHdrLayers()) { if (isPartOfRun) { builder.append(currentSet->getLayerCount()); } else { @@ -472,9 +477,14 @@ void Flattener::buildCachedSets(time_point now) { ++mCachedSetCreationCount; mCachedSetCreationCost += mNewCachedSet->getCreationCost(); - std::string setDump; - mNewCachedSet->dump(setDump); - ALOGV("[%s] Added new cached set:\n%s", __func__, setDump.c_str()); + + // note the compiler should strip the follow no-op statements when ALOGV is off + const auto dumper = [&] { + std::string setDump; + mNewCachedSet->dump(setDump); + return setDump; + }; + ALOGV("[%s] Added new cached set:\n%s", __func__, dumper().c_str()); } } // namespace android::compositionengine::impl::planner diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp index 591f9811ee..8eeb0bfa16 100644 --- a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp @@ -557,6 +557,75 @@ TEST_F(CachedSetTest, addHolePunch) { cachedSet.render(mRenderEngine, mOutputState); } +TEST_F(CachedSetTest, addHolePunch_noBuffer) { + // Same as addHolePunch, except that clientCompList3 does not contain a + // buffer. This imitates the case where the buffer had protected content, so + // BufferLayer did not add it to the LayerSettings. This should not assert. + mTestLayers[0]->outputLayerCompositionState.displayFrame = Rect(0, 0, 5, 5); + CachedSet::Layer& layer1 = *mTestLayers[0]->cachedSetLayer.get(); + sp<mock::LayerFE> layerFE1 = mTestLayers[0]->layerFE; + + CachedSet::Layer& layer2 = *mTestLayers[1]->cachedSetLayer.get(); + sp<mock::LayerFE> layerFE2 = mTestLayers[1]->layerFE; + + CachedSet::Layer& layer3 = *mTestLayers[2]->cachedSetLayer.get(); + sp<mock::LayerFE> layerFE3 = mTestLayers[2]->layerFE; + + CachedSet cachedSet(layer1); + cachedSet.addLayer(layer2.getState(), kStartTime + 10ms); + + cachedSet.addHolePunchLayerIfFeasible(layer3, true); + + std::vector<compositionengine::LayerFE::LayerSettings> clientCompList1; + clientCompList1.push_back({}); + std::vector<compositionengine::LayerFE::LayerSettings> clientCompList2; + clientCompList2.push_back({}); + std::vector<compositionengine::LayerFE::LayerSettings> clientCompList3; + clientCompList3.push_back({}); + + EXPECT_CALL(*layerFE1, prepareClientCompositionList(_)).WillOnce(Return(clientCompList1)); + EXPECT_CALL(*layerFE2, prepareClientCompositionList(_)).WillOnce(Return(clientCompList2)); + EXPECT_CALL(*layerFE3, prepareClientCompositionList(_)).WillOnce(Return(clientCompList3)); + + const auto drawLayers = [&](const renderengine::DisplaySettings&, + const std::vector<const renderengine::LayerSettings*>& layers, + const std::shared_ptr<renderengine::ExternalTexture>&, const bool, + base::unique_fd&&, base::unique_fd*) -> size_t { + // If the highlight layer is enabled, it will increase the size by 1. + // We're interested in the third layer either way. + EXPECT_GE(layers.size(), 3u); + const auto* holePunchSettings = layers[2]; + EXPECT_EQ(nullptr, holePunchSettings->source.buffer.buffer); + EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), holePunchSettings->source.solidColor); + EXPECT_TRUE(holePunchSettings->disableBlending); + EXPECT_EQ(0.0f, holePunchSettings->alpha); + + return NO_ERROR; + }; + + EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Invoke(drawLayers)); + cachedSet.render(mRenderEngine, mOutputState); +} + +TEST_F(CachedSetTest, append_removesHolePunch) { + mTestLayers[0]->outputLayerCompositionState.displayFrame = Rect(0, 0, 5, 5); + mTestLayers[0]->layerFECompositionState.isOpaque = true; + CachedSet::Layer& layer1 = *mTestLayers[0]->cachedSetLayer.get(); + CachedSet::Layer& layer2 = *mTestLayers[1]->cachedSetLayer.get(); + CachedSet::Layer& layer3 = *mTestLayers[2]->cachedSetLayer.get(); + + CachedSet cachedSet(layer1); + cachedSet.addLayer(layer2.getState(), kStartTime + 10ms); + + cachedSet.addHolePunchLayerIfFeasible(layer3, false); + + ASSERT_EQ(&mTestLayers[2]->outputLayer, cachedSet.getHolePunchLayer()); + + CachedSet cachedSet3(layer3); + cachedSet.append(cachedSet3); + ASSERT_EQ(nullptr, cachedSet.getHolePunchLayer()); +} + TEST_F(CachedSetTest, decompose_removesHolePunch) { mTestLayers[0]->outputLayerCompositionState.displayFrame = Rect(0, 0, 5, 5); CachedSet::Layer& layer1 = *mTestLayers[0]->cachedSetLayer.get(); diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp index 9b03287242..3523b565dc 100644 --- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp +++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp @@ -304,7 +304,7 @@ SurfaceFrame::SurfaceFrame(const FrameTimelineInfo& frameTimelineInfo, pid_t own frametimeline::TimelineItem&& predictions, std::shared_ptr<TimeStats> timeStats, JankClassificationThresholds thresholds, - TraceCookieCounter* traceCookieCounter, bool isBuffer) + TraceCookieCounter* traceCookieCounter, bool isBuffer, int32_t gameMode) : mToken(frameTimelineInfo.vsyncId), mInputEventId(frameTimelineInfo.inputEventId), mOwnerPid(ownerPid), @@ -319,7 +319,8 @@ SurfaceFrame::SurfaceFrame(const FrameTimelineInfo& frameTimelineInfo, pid_t own mTimeStats(timeStats), mJankClassificationThresholds(thresholds), mTraceCookieCounter(*traceCookieCounter), - mIsBuffer(isBuffer) {} + mIsBuffer(isBuffer), + mGameMode(gameMode) {} void SurfaceFrame::setActualStartTime(nsecs_t actualStartTime) { std::scoped_lock lock(mMutex); @@ -607,8 +608,8 @@ void SurfaceFrame::onPresent(nsecs_t presentTime, int32_t displayFrameJankType, if (mPredictionState != PredictionState::None) { // Only update janky frames if the app used vsync predictions mTimeStats->incrementJankyFrames({refreshRate, mRenderRate, mOwnerUid, mLayerName, - mJankType, displayDeadlineDelta, displayPresentDelta, - deadlineDelta}); + mGameMode, mJankType, displayDeadlineDelta, + displayPresentDelta, deadlineDelta}); } } @@ -776,14 +777,14 @@ void FrameTimeline::registerDataSource() { std::shared_ptr<SurfaceFrame> FrameTimeline::createSurfaceFrameForToken( const FrameTimelineInfo& frameTimelineInfo, pid_t ownerPid, uid_t ownerUid, int32_t layerId, - std::string layerName, std::string debugName, bool isBuffer) { + std::string layerName, std::string debugName, bool isBuffer, int32_t gameMode) { ATRACE_CALL(); if (frameTimelineInfo.vsyncId == FrameTimelineInfo::INVALID_VSYNC_ID) { return std::make_shared<SurfaceFrame>(frameTimelineInfo, ownerPid, ownerUid, layerId, std::move(layerName), std::move(debugName), PredictionState::None, TimelineItem(), mTimeStats, mJankClassificationThresholds, &mTraceCookieCounter, - isBuffer); + isBuffer, gameMode); } std::optional<TimelineItem> predictions = mTokenManager.getPredictionsForToken(frameTimelineInfo.vsyncId); @@ -792,13 +793,13 @@ std::shared_ptr<SurfaceFrame> FrameTimeline::createSurfaceFrameForToken( std::move(layerName), std::move(debugName), PredictionState::Valid, std::move(*predictions), mTimeStats, mJankClassificationThresholds, - &mTraceCookieCounter, isBuffer); + &mTraceCookieCounter, isBuffer, gameMode); } return std::make_shared<SurfaceFrame>(frameTimelineInfo, ownerPid, ownerUid, layerId, std::move(layerName), std::move(debugName), PredictionState::Expired, TimelineItem(), mTimeStats, mJankClassificationThresholds, &mTraceCookieCounter, - isBuffer); + isBuffer, gameMode); } FrameTimeline::DisplayFrame::DisplayFrame(std::shared_ptr<TimeStats> timeStats, diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.h b/services/surfaceflinger/FrameTimeline/FrameTimeline.h index 42be55ae2c..15ecf130e7 100644 --- a/services/surfaceflinger/FrameTimeline/FrameTimeline.h +++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.h @@ -154,7 +154,7 @@ public: int32_t layerId, std::string layerName, std::string debugName, PredictionState predictionState, TimelineItem&& predictions, std::shared_ptr<TimeStats> timeStats, JankClassificationThresholds thresholds, - TraceCookieCounter* traceCookieCounter, bool isBuffer); + TraceCookieCounter* traceCookieCounter, bool isBuffer, int32_t gameMode); ~SurfaceFrame() = default; // Returns std::nullopt if the frame hasn't been classified yet. @@ -259,6 +259,8 @@ private: // Tells if the SurfaceFrame is representing a buffer or a transaction without a // buffer(animations) bool mIsBuffer; + // GameMode from the layer. Used in metrics. + int32_t mGameMode = 0; }; /* @@ -278,7 +280,8 @@ public: // Debug name is the human-readable debugging string for dumpsys. virtual std::shared_ptr<SurfaceFrame> createSurfaceFrameForToken( const FrameTimelineInfo& frameTimelineInfo, pid_t ownerPid, uid_t ownerUid, - int32_t layerId, std::string layerName, std::string debugName, bool isBuffer) = 0; + int32_t layerId, std::string layerName, std::string debugName, bool isBuffer, + int32_t gameMode) = 0; // Adds a new SurfaceFrame to the current DisplayFrame. Frames from multiple layers can be // composited into one display frame. @@ -437,7 +440,8 @@ public: frametimeline::TokenManager* getTokenManager() override { return &mTokenManager; } std::shared_ptr<SurfaceFrame> createSurfaceFrameForToken( const FrameTimelineInfo& frameTimelineInfo, pid_t ownerPid, uid_t ownerUid, - int32_t layerId, std::string layerName, std::string debugName, bool isBuffer) override; + int32_t layerId, std::string layerName, std::string debugName, bool isBuffer, + int32_t gameMode) override; void addSurfaceFrame(std::shared_ptr<frametimeline::SurfaceFrame> surfaceFrame) override; void setSfWakeUp(int64_t token, nsecs_t wakeupTime, Fps refreshRate) override; void setSfPresent(nsecs_t sfPresentTime, const std::shared_ptr<FenceTime>& presentFence, diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 9fcc17c4b4..e50087f819 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -1357,7 +1357,7 @@ std::shared_ptr<frametimeline::SurfaceFrame> Layer::createSurfaceFrameForTransac mFlinger->mFrameTimeline->createSurfaceFrameForToken(info, mOwnerPid, mOwnerUid, getSequence(), mName, mTransactionName, - /*isBuffer*/ false); + /*isBuffer*/ false, getGameMode()); // For Transactions, the post time is considered to be both queue and acquire fence time. surfaceFrame->setActualQueueTime(postTime); surfaceFrame->setAcquireFenceTime(postTime); @@ -1374,7 +1374,7 @@ std::shared_ptr<frametimeline::SurfaceFrame> Layer::createSurfaceFrameForBuffer( auto surfaceFrame = mFlinger->mFrameTimeline->createSurfaceFrameForToken(info, mOwnerPid, mOwnerUid, getSequence(), mName, debugName, - /*isBuffer*/ true); + /*isBuffer*/ true, getGameMode()); // For buffers, acquire fence time will set during latch. surfaceFrame->setActualQueueTime(queueTime); const auto fps = mFlinger->mScheduler->getFrameRateOverride(getOwnerUid()); @@ -1635,7 +1635,8 @@ void Layer::addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps, FrameEventHistoryDelta* outDelta) { if (newTimestamps) { mFlinger->mTimeStats->setPostTime(getSequence(), newTimestamps->frameNumber, - getName().c_str(), mOwnerUid, newTimestamps->postedTime); + getName().c_str(), mOwnerUid, newTimestamps->postedTime, + getGameMode()); mFlinger->mTimeStats->setAcquireFence(getSequence(), newTimestamps->frameNumber, newTimestamps->acquireFence); } diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index af2604582b..dde0031201 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -850,9 +850,9 @@ public: // 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; } + void setGameModeForTree(int32_t parentGameMode); + void setGameMode(int32_t gameMode) { mGameMode = gameMode; }; + int32_t getGameMode() const { return mGameMode; } virtual uid_t getOwnerUid() const { return mOwnerUid; } @@ -1098,7 +1098,7 @@ private: // Game mode for the layer. Set by WindowManagerShell, game mode is used in // metrics(SurfaceFlingerStats). - int mGameMode = 0; + int32_t mGameMode = 0; // A list of regions on this layer that should have blurs. const std::vector<BlurRegion> getBlurRegions() const; diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp index d6a0787ddc..f1b153fe7e 100644 --- a/services/surfaceflinger/TimeStats/TimeStats.cpp +++ b/services/surfaceflinger/TimeStats/TimeStats.cpp @@ -58,6 +58,21 @@ FrameTimingHistogram histogramToProto(const std::unordered_map<int32_t, int32_t> return histogramProto; } +SurfaceflingerStatsLayerInfo_GameMode gameModeToProto(int32_t gameMode) { + switch (gameMode) { + case TimeStatsHelper::GameModeUnsupported: + return SurfaceflingerStatsLayerInfo::GAME_MODE_UNSUPPORTED; + case TimeStatsHelper::GameModeStandard: + return SurfaceflingerStatsLayerInfo::GAME_MODE_STANDARD; + case TimeStatsHelper::GameModePerformance: + return SurfaceflingerStatsLayerInfo::GAME_MODE_PERFORMANCE; + case TimeStatsHelper::GameModeBattery: + return SurfaceflingerStatsLayerInfo::GAME_MODE_BATTERY; + default: + return SurfaceflingerStatsLayerInfo::GAME_MODE_UNSPECIFIED; + } +} + SurfaceflingerStatsLayerInfo_SetFrameRateVote frameRateVoteToProto( const TimeStats::SetFrameRateVote& setFrameRateVote) { using FrameRateCompatibilityEnum = @@ -206,6 +221,7 @@ bool TimeStats::populateLayerAtom(std::string* pulledData) { *atom->mutable_app_deadline_misses() = histogramToProto(layer->deltas["appDeadlineDeltas"].hist, mMaxPulledHistogramBuckets); + atom->set_game_mode(gameModeToProto(layer->gameMode)); } // Always clear data. @@ -437,7 +453,8 @@ static int32_t clampToNearestBucket(Fps fps, size_t bucketWidth) { void TimeStats::flushAvailableRecordsToStatsLocked(int32_t layerId, Fps displayRefreshRate, std::optional<Fps> renderRate, - SetFrameRateVote frameRateVote) { + SetFrameRateVote frameRateVote, + int32_t gameMode) { ATRACE_CALL(); ALOGV("[%d]-flushAvailableRecordsToStatsLocked", layerId); @@ -464,12 +481,13 @@ void TimeStats::flushAvailableRecordsToStatsLocked(int32_t layerId, Fps displayR TimeStatsHelper::TimelineStats& displayStats = mTimeStats.stats[timelineKey]; - TimeStatsHelper::LayerStatsKey layerKey = {uid, layerName}; + TimeStatsHelper::LayerStatsKey layerKey = {uid, layerName, gameMode}; if (!displayStats.stats.count(layerKey)) { displayStats.stats[layerKey].displayRefreshRateBucket = refreshRateBucket; displayStats.stats[layerKey].renderRateBucket = renderRateBucket; displayStats.stats[layerKey].uid = uid; displayStats.stats[layerKey].layerName = layerName; + displayStats.stats[layerKey].gameMode = gameMode; } if (frameRateVote.frameRate > 0.0f) { displayStats.stats[layerKey].setFrameRateVote = frameRateVote; @@ -535,10 +553,11 @@ static bool layerNameIsValid(const std::string& layerName) { layerName.compare(0, kMinLenLayerName, kPopupWindowPrefix) != 0; } -bool TimeStats::canAddNewAggregatedStats(uid_t uid, const std::string& layerName) { +bool TimeStats::canAddNewAggregatedStats(uid_t uid, const std::string& layerName, + int32_t gameMode) { uint32_t layerRecords = 0; for (const auto& record : mTimeStats.stats) { - if (record.second.stats.count({uid, layerName}) > 0) { + if (record.second.stats.count({uid, layerName, gameMode}) > 0) { return true; } @@ -549,7 +568,7 @@ bool TimeStats::canAddNewAggregatedStats(uid_t uid, const std::string& layerName } void TimeStats::setPostTime(int32_t layerId, uint64_t frameNumber, const std::string& layerName, - uid_t uid, nsecs_t postTime) { + uid_t uid, nsecs_t postTime, int32_t gameMode) { if (!mEnabled.load()) return; ATRACE_CALL(); @@ -557,13 +576,14 @@ void TimeStats::setPostTime(int32_t layerId, uint64_t frameNumber, const std::st postTime); std::lock_guard<std::mutex> lock(mMutex); - if (!canAddNewAggregatedStats(uid, layerName)) { + if (!canAddNewAggregatedStats(uid, layerName, gameMode)) { return; } if (!mTimeStatsTracker.count(layerId) && mTimeStatsTracker.size() < MAX_NUM_LAYER_RECORDS && layerNameIsValid(layerName)) { mTimeStatsTracker[layerId].uid = uid; mTimeStatsTracker[layerId].layerName = layerName; + mTimeStatsTracker[layerId].gameMode = gameMode; } if (!mTimeStatsTracker.count(layerId)) return; LayerRecord& layerRecord = mTimeStatsTracker[layerId]; @@ -698,7 +718,7 @@ void TimeStats::setAcquireFence(int32_t layerId, uint64_t frameNumber, void TimeStats::setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t presentTime, Fps displayRefreshRate, std::optional<Fps> renderRate, - SetFrameRateVote frameRateVote) { + SetFrameRateVote frameRateVote, int32_t gameMode) { if (!mEnabled.load()) return; ATRACE_CALL(); @@ -717,13 +737,14 @@ void TimeStats::setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t pr layerRecord.waitData++; } - flushAvailableRecordsToStatsLocked(layerId, displayRefreshRate, renderRate, frameRateVote); + flushAvailableRecordsToStatsLocked(layerId, displayRefreshRate, renderRate, frameRateVote, + gameMode); } void TimeStats::setPresentFence(int32_t layerId, uint64_t frameNumber, const std::shared_ptr<FenceTime>& presentFence, Fps displayRefreshRate, std::optional<Fps> renderRate, - SetFrameRateVote frameRateVote) { + SetFrameRateVote frameRateVote, int32_t gameMode) { if (!mEnabled.load()) return; ATRACE_CALL(); @@ -743,7 +764,8 @@ void TimeStats::setPresentFence(int32_t layerId, uint64_t frameNumber, layerRecord.waitData++; } - flushAvailableRecordsToStatsLocked(layerId, displayRefreshRate, renderRate, frameRateVote); + flushAvailableRecordsToStatsLocked(layerId, displayRefreshRate, renderRate, frameRateVote, + gameMode); } static const constexpr int32_t kValidJankyReason = JankType::DisplayHAL | @@ -801,6 +823,7 @@ void TimeStats::incrementJankyFrames(const JankyFramesInfo& info) { // the first jank record is not dropped. static const std::string kDefaultLayerName = "none"; + static constexpr int32_t kDefaultGameMode = TimeStatsHelper::GameModeUnsupported; const int32_t refreshRateBucket = clampToNearestBucket(info.refreshRate, REFRESH_RATE_BUCKET_WIDTH); @@ -817,13 +840,14 @@ void TimeStats::incrementJankyFrames(const JankyFramesInfo& info) { updateJankPayload<TimeStatsHelper::TimelineStats>(timelineStats, info.reasons); - TimeStatsHelper::LayerStatsKey layerKey = {info.uid, info.layerName}; + TimeStatsHelper::LayerStatsKey layerKey = {info.uid, info.layerName, info.gameMode}; if (!timelineStats.stats.count(layerKey)) { - layerKey = {info.uid, kDefaultLayerName}; + layerKey = {info.uid, kDefaultLayerName, kDefaultGameMode}; timelineStats.stats[layerKey].displayRefreshRateBucket = refreshRateBucket; timelineStats.stats[layerKey].renderRateBucket = renderRateBucket; timelineStats.stats[layerKey].uid = info.uid; - timelineStats.stats[layerKey].layerName = kDefaultLayerName; + timelineStats.stats[layerKey].layerName = kDefaultGameMode; + timelineStats.stats[layerKey].gameMode = info.gameMode; } TimeStatsHelper::TimeStatsLayer& timeStatsLayer = timelineStats.stats[layerKey]; diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h index 5b0f5bd13d..dd48950fd0 100644 --- a/services/surfaceflinger/TimeStats/TimeStats.h +++ b/services/surfaceflinger/TimeStats/TimeStats.h @@ -87,7 +87,7 @@ public: const std::shared_ptr<FenceTime>& readyFence) = 0; virtual void setPostTime(int32_t layerId, uint64_t frameNumber, const std::string& layerName, - uid_t uid, nsecs_t postTime) = 0; + uid_t uid, nsecs_t postTime, int32_t gameMode) = 0; virtual void setLatchTime(int32_t layerId, uint64_t frameNumber, nsecs_t latchTime) = 0; // Reasons why latching a particular buffer may be skipped enum class LatchSkipReason { @@ -109,11 +109,11 @@ public: // rendering path, as they flush prior fences if those fences have fired. virtual void setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t presentTime, Fps displayRefreshRate, std::optional<Fps> renderRate, - SetFrameRateVote frameRateVote) = 0; + SetFrameRateVote frameRateVote, int32_t gameMode) = 0; virtual void setPresentFence(int32_t layerId, uint64_t frameNumber, const std::shared_ptr<FenceTime>& presentFence, Fps displayRefreshRate, std::optional<Fps> renderRate, - SetFrameRateVote frameRateVote) = 0; + SetFrameRateVote frameRateVote, int32_t gameMode) = 0; // Increments janky frames, blamed to the provided {refreshRate, renderRate, uid, layerName} // key, with JankMetadata as supplementary reasons for the jank. Because FrameTimeline is the @@ -131,6 +131,7 @@ public: std::optional<Fps> renderRate; uid_t uid = 0; std::string layerName; + int32_t gameMode = 0; int32_t reasons = 0; nsecs_t displayDeadlineDelta = 0; nsecs_t displayPresentJitter = 0; @@ -141,8 +142,8 @@ public: ((renderRate == std::nullopt && o.renderRate == std::nullopt) || (renderRate != std::nullopt && o.renderRate != std::nullopt && Fps::EqualsInBuckets{}(*renderRate, *o.renderRate))) && - uid == o.uid && layerName == o.layerName && reasons == o.reasons && - displayDeadlineDelta == o.displayDeadlineDelta && + uid == o.uid && layerName == o.layerName && gameMode == o.gameMode && + reasons == o.reasons && displayDeadlineDelta == o.displayDeadlineDelta && displayPresentJitter == o.displayPresentJitter && appDeadlineDelta == o.appDeadlineDelta; } @@ -199,6 +200,7 @@ class TimeStats : public android::TimeStats { struct LayerRecord { uid_t uid; std::string layerName; + int32_t gameMode = 0; // This is the index in timeRecords, at which the timestamps for that // specific frame are still not fully received. This is not waiting for // fences to signal, but rather waiting to receive those fences/timestamps. @@ -251,7 +253,7 @@ public: const std::shared_ptr<FenceTime>& readyFence) override; void setPostTime(int32_t layerId, uint64_t frameNumber, const std::string& layerName, uid_t uid, - nsecs_t postTime) override; + nsecs_t postTime, int32_t gameMode) override; void setLatchTime(int32_t layerId, uint64_t frameNumber, nsecs_t latchTime) override; void incrementLatchSkipped(int32_t layerId, LatchSkipReason reason) override; void incrementBadDesiredPresent(int32_t layerId) override; @@ -261,10 +263,11 @@ public: const std::shared_ptr<FenceTime>& acquireFence) override; void setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t presentTime, Fps displayRefreshRate, std::optional<Fps> renderRate, - SetFrameRateVote frameRateVote) override; + SetFrameRateVote frameRateVote, int32_t gameMode) override; void setPresentFence(int32_t layerId, uint64_t frameNumber, const std::shared_ptr<FenceTime>& presentFence, Fps displayRefreshRate, - std::optional<Fps> renderRate, SetFrameRateVote frameRateVote) override; + std::optional<Fps> renderRate, SetFrameRateVote frameRateVote, + int32_t gameMode) override; void incrementJankyFrames(const JankyFramesInfo& info) override; // Clean up the layer record @@ -286,10 +289,10 @@ private: bool recordReadyLocked(int32_t layerId, TimeRecord* timeRecord); void flushAvailableRecordsToStatsLocked(int32_t layerId, Fps displayRefreshRate, std::optional<Fps> renderRate, - SetFrameRateVote frameRateVote); + SetFrameRateVote frameRateVote, int32_t gameMode); void flushPowerTimeLocked(); void flushAvailableGlobalRecordsToStatsLocked(); - bool canAddNewAggregatedStats(uid_t uid, const std::string& layerName); + bool canAddNewAggregatedStats(uid_t uid, const std::string& layerName, int32_t gameMode); void enable(); void disable(); diff --git a/services/surfaceflinger/TimeStats/timestatsatomsproto/timestats_atoms.proto b/services/surfaceflinger/TimeStats/timestatsatomsproto/timestats_atoms.proto index 133a5419b5..e45757ddfd 100644 --- a/services/surfaceflinger/TimeStats/timestatsatomsproto/timestats_atoms.proto +++ b/services/surfaceflinger/TimeStats/timestatsatomsproto/timestats_atoms.proto @@ -166,6 +166,23 @@ message SurfaceflingerStatsLayerInfo { // This is intended to be used as a dimension in collecting per-render rate // jank statistics. optional int32 render_rate_bucket = 23; + + enum GameMode { + GAME_MODE_UNSPECIFIED = 0; + GAME_MODE_UNSUPPORTED = 1; + GAME_MODE_STANDARD = 2; + GAME_MODE_PERFORMANCE = 3; + GAME_MODE_BATTERY = 4; + } + + // Game mode that the layer was running at. Used to track user engagement + // in different modes. The modes are defined in GameManager.java + // Game modes are used only for integrating with GameManager. All non-game + // layers will have this field set to UNSUPPORTED. + // Introduced in Android 12 + // This is intended to be used as a dimension in collecting per-game mode + // fps and frame related metrics. + optional GameMode game_mode = 26; // The layer for this set of metrics // In many scenarios the package name is included in the layer name, e.g., // layers created by Window Manager. But this is not a guarantee - in the @@ -271,7 +288,7 @@ message SurfaceflingerStatsLayerInfo { // Introduced in Android 12. optional FrameTimingHistogram app_deadline_misses = 25; - // Next ID: 26 + // Next ID: 27 } /** diff --git a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp index a7e7db25d7..ffb2f0921d 100644 --- a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp +++ b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp @@ -122,6 +122,20 @@ std::string TimeStatsHelper::SetFrameRateVote::toString() const { return result; } +std::string TimeStatsHelper::TimeStatsLayer::toString(int32_t gameMode) const { + switch (gameMode) { + case TimeStatsHelper::GameModeUnsupported: + return "GameModeUnsupported"; + case TimeStatsHelper::GameModeStandard: + return "GameModeStandard"; + case TimeStatsHelper::GameModePerformance: + return "GameModePerformance"; + case TimeStatsHelper::GameModeBattery: + return "GameModeBattery"; + default: + return "GameModeUnspecified"; + } +} std::string TimeStatsHelper::TimeStatsLayer::toString() const { std::string result = "\n"; StringAppendF(&result, "displayRefreshRate = %d fps\n", displayRefreshRateBucket); @@ -129,6 +143,7 @@ std::string TimeStatsHelper::TimeStatsLayer::toString() const { StringAppendF(&result, "uid = %d\n", uid); StringAppendF(&result, "layerName = %s\n", layerName.c_str()); StringAppendF(&result, "packageName = %s\n", packageName.c_str()); + StringAppendF(&result, "gameMode = %s\n", toString(gameMode).c_str()); StringAppendF(&result, "totalFrames = %d\n", totalFrames); StringAppendF(&result, "droppedFrames = %d\n", droppedFrames); StringAppendF(&result, "lateAcquireFrames = %d\n", lateAcquireFrames); diff --git a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h index 2b37ffef30..2afff8d313 100644 --- a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h +++ b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h @@ -77,6 +77,18 @@ public: std::string toString() const; }; + /** + * GameMode of the layer. GameModes are set by SysUI through WMShell. + * Actual game mode definitions are managed by GameManager.java + * The values defined here should always be in sync with the ones in GameManager. + */ + enum GameMode { + GameModeUnsupported = 0, + GameModeStandard = 1, + GameModePerformance = 2, + GameModeBattery = 3, + }; + class TimeStatsLayer { public: uid_t uid; @@ -84,6 +96,7 @@ public: std::string packageName; int32_t displayRefreshRateBucket = 0; int32_t renderRateBucket = 0; + int32_t gameMode = 0; int32_t totalFrames = 0; int32_t droppedFrames = 0; int32_t lateAcquireFrames = 0; @@ -93,6 +106,7 @@ public: std::unordered_map<std::string, Histogram> deltas; std::string toString() const; + std::string toString(int32_t gameMode) const; SFTimeStatsLayerProto toProto() const; }; @@ -123,24 +137,19 @@ public: struct LayerStatsKey { uid_t uid = 0; std::string layerName; + int32_t gameMode = 0; struct Hasher { size_t operator()(const LayerStatsKey& key) const { - size_t result = std::hash<uid_t>{}(key.uid); - return HashCombine(result, std::hash<std::string>{}(key.layerName)); + size_t uidHash = std::hash<uid_t>{}(key.uid); + size_t layerNameHash = std::hash<std::string>{}(key.layerName); + size_t gameModeHash = std::hash<int32_t>{}(key.gameMode); + return HashCombine(uidHash, HashCombine(layerNameHash, gameModeHash)); } }; bool operator==(const LayerStatsKey& o) const { - return uid == o.uid && layerName == o.layerName; - } - }; - - struct LayerStatsHasher { - size_t operator()(const std::pair<uid_t, std::string>& p) const { - // Normally this isn't a very good hash function due to symmetry reasons, - // but these are distinct types so this should be good enough - return std::hash<uid_t>{}(p.first) ^ std::hash<std::string>{}(p.second); + return uid == o.uid && layerName == o.layerName && gameMode == o.gameMode; } }; diff --git a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp index c6a41159c1..71a567a23f 100644 --- a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp +++ b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp @@ -175,6 +175,7 @@ static constexpr pid_t sPidTwo = 20; static constexpr int32_t sInputEventId = 5; static constexpr int32_t sLayerIdOne = 1; static constexpr int32_t sLayerIdTwo = 2; +static constexpr int32_t sGameMode = 0; TEST_F(FrameTimelineTest, tokenManagerRemovesStalePredictions) { int64_t token1 = mTokenManager->generateTokenForPredictions({0, 0, 0}); @@ -194,11 +195,11 @@ TEST_F(FrameTimelineTest, createSurfaceFrameForToken_getOwnerPidReturnsCorrectPi auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, sLayerNameOne, - /*isBuffer*/ true); + /*isBuffer*/ true, sGameMode); auto surfaceFrame2 = mFrameTimeline->createSurfaceFrameForToken({}, sPidTwo, sUidOne, sLayerIdOne, sLayerNameOne, sLayerNameOne, - /*isBuffer*/ true); + /*isBuffer*/ true, sGameMode); EXPECT_EQ(surfaceFrame1->getOwnerPid(), sPidOne); EXPECT_EQ(surfaceFrame2->getOwnerPid(), sPidTwo); } @@ -207,7 +208,7 @@ TEST_F(FrameTimelineTest, createSurfaceFrameForToken_noToken) { auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, sLayerNameOne, - /*isBuffer*/ true); + /*isBuffer*/ true, sGameMode); EXPECT_EQ(surfaceFrame->getPredictionState(), PredictionState::None); } @@ -217,7 +218,7 @@ TEST_F(FrameTimelineTest, createSurfaceFrameForToken_expiredToken) { auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken({token1, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, sLayerNameOne, - /*isBuffer*/ true); + /*isBuffer*/ true, sGameMode); EXPECT_EQ(surfaceFrame->getPredictionState(), PredictionState::Expired); } @@ -227,7 +228,7 @@ TEST_F(FrameTimelineTest, createSurfaceFrameForToken_validToken) { auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken({token1, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, sLayerNameOne, - /*isBuffer*/ true); + /*isBuffer*/ true, sGameMode); EXPECT_EQ(surfaceFrame->getPredictionState(), PredictionState::Valid); EXPECT_EQ(compareTimelineItems(surfaceFrame->getPredictions(), TimelineItem(10, 20, 30)), true); @@ -239,7 +240,7 @@ TEST_F(FrameTimelineTest, createSurfaceFrameForToken_validInputEventId) { auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken({token1, inputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, sLayerNameOne, - /*isBuffer*/ true); + /*isBuffer*/ true, sGameMode); EXPECT_EQ(inputEventId, surfaceFrame->getInputEventId()); } @@ -250,7 +251,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_droppedFramesNotUpdated) { auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({token1, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, sLayerNameOne, - /*isBuffer*/ true); + /*isBuffer*/ true, sGameMode); // Set up the display frame mFrameTimeline->setSfWakeUp(token1, 20, Fps::fromPeriodNsecs(11)); @@ -278,11 +279,11 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_presentedFramesUpdated) { auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true); + sLayerNameOne, /*isBuffer*/ true, sGameMode); auto surfaceFrame2 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, sUidOne, sLayerIdTwo, sLayerNameTwo, - sLayerNameTwo, /*isBuffer*/ true); + sLayerNameTwo, /*isBuffer*/ true, sGameMode); mFrameTimeline->setSfWakeUp(sfToken1, 22, Fps::fromPeriodNsecs(11)); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame1); @@ -325,7 +326,7 @@ TEST_F(FrameTimelineTest, displayFramesSlidingWindowMovesAfterLimit) { mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, sLayerNameOne, - /*isBuffer*/ true); + /*isBuffer*/ true, sGameMode); mFrameTimeline->setSfWakeUp(sfToken, 22 + frameTimeFactor, Fps::fromPeriodNsecs(11)); surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame); @@ -347,7 +348,7 @@ TEST_F(FrameTimelineTest, displayFramesSlidingWindowMovesAfterLimit) { auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true); + sLayerNameOne, /*isBuffer*/ true, sGameMode); mFrameTimeline->setSfWakeUp(sfToken, 22 + frameTimeFactor, Fps::fromPeriodNsecs(11)); surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame); @@ -361,20 +362,20 @@ TEST_F(FrameTimelineTest, displayFramesSlidingWindowMovesAfterLimit) { } TEST_F(FrameTimelineTest, surfaceFrameEndTimeAcquireFenceAfterQueue) { - auto surfaceFrame = - mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, 0, sLayerIdOne, - "acquireFenceAfterQueue", - "acquireFenceAfterQueue", /*isBuffer*/ true); + auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, 0, sLayerIdOne, + "acquireFenceAfterQueue", + "acquireFenceAfterQueue", + /*isBuffer*/ true, sGameMode); surfaceFrame->setActualQueueTime(123); surfaceFrame->setAcquireFenceTime(456); EXPECT_EQ(surfaceFrame->getActuals().endTime, 456); } TEST_F(FrameTimelineTest, surfaceFrameEndTimeAcquireFenceBeforeQueue) { - auto surfaceFrame = - mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, 0, sLayerIdOne, - "acquireFenceAfterQueue", - "acquireFenceAfterQueue", /*isBuffer*/ true); + auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, 0, sLayerIdOne, + "acquireFenceAfterQueue", + "acquireFenceAfterQueue", + /*isBuffer*/ true, sGameMode); surfaceFrame->setActualQueueTime(456); surfaceFrame->setAcquireFenceTime(123); EXPECT_EQ(surfaceFrame->getActuals().endTime, 456); @@ -389,7 +390,7 @@ TEST_F(FrameTimelineTest, setMaxDisplayFramesSetsSizeProperly) { auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, sLayerNameOne, - /*isBuffer*/ true); + /*isBuffer*/ true, sGameMode); int64_t sfToken = mTokenManager->generateTokenForPredictions({22, 26, 30}); mFrameTimeline->setSfWakeUp(sfToken, 22, Fps::fromPeriodNsecs(11)); surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented); @@ -406,7 +407,7 @@ TEST_F(FrameTimelineTest, setMaxDisplayFramesSetsSizeProperly) { auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, sLayerNameOne, - /*isBuffer*/ true); + /*isBuffer*/ true, sGameMode); int64_t sfToken = mTokenManager->generateTokenForPredictions({22, 26, 30}); mFrameTimeline->setSfWakeUp(sfToken, 22, Fps::fromPeriodNsecs(11)); surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented); @@ -423,7 +424,7 @@ TEST_F(FrameTimelineTest, setMaxDisplayFramesSetsSizeProperly) { auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, sLayerNameOne, - /*isBuffer*/ true); + /*isBuffer*/ true, sGameMode); int64_t sfToken = mTokenManager->generateTokenForPredictions({22, 26, 30}); mFrameTimeline->setSfWakeUp(sfToken, 22, Fps::fromPeriodNsecs(11)); surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented); @@ -443,7 +444,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_invalidSignalTime) { auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true); + sLayerNameOne, /*isBuffer*/ true, sGameMode); mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate); surfaceFrame1->setAcquireFenceTime(20); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); @@ -471,7 +472,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_doesNotReportForInvalidTokens) { auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true); + sLayerNameOne, /*isBuffer*/ true, sGameMode); mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate); surfaceFrame1->setAcquireFenceTime(20); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); @@ -486,7 +487,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsLongSfCpu) { EXPECT_CALL(*mTimeStats, incrementJankyFrames( TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne, - sLayerNameOne, + sLayerNameOne, sGameMode, JankType::SurfaceFlingerCpuDeadlineMissed, 2, 10, 0})); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); @@ -496,7 +497,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsLongSfCpu) { auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true); + sLayerNameOne, /*isBuffer*/ true, sGameMode); mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate); surfaceFrame1->setAcquireFenceTime(20); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); @@ -511,7 +512,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsLongSfGpu) { EXPECT_CALL(*mTimeStats, incrementJankyFrames( TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne, - sLayerNameOne, + sLayerNameOne, sGameMode, JankType::SurfaceFlingerGpuDeadlineMissed, 4, 10, 0})); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); @@ -522,7 +523,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsLongSfGpu) { auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true); + sLayerNameOne, /*isBuffer*/ true, sGameMode); mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate); surfaceFrame1->setAcquireFenceTime(20); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); @@ -537,8 +538,8 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsDisplayMiss) { Fps refreshRate = Fps::fromPeriodNsecs(30); EXPECT_CALL(*mTimeStats, incrementJankyFrames(TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne, - sLayerNameOne, JankType::DisplayHAL, - -4, 0, 0})); + sLayerNameOne, sGameMode, + JankType::DisplayHAL, -4, 0, 0})); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 60}); @@ -547,7 +548,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsDisplayMiss) { auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true); + sLayerNameOne, /*isBuffer*/ true, sGameMode); mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); surfaceFrame1->setAcquireFenceTime(20); @@ -561,7 +562,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppMiss) { Fps refreshRate = Fps(11.0); EXPECT_CALL(*mTimeStats, incrementJankyFrames(TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne, - sLayerNameOne, + sLayerNameOne, sGameMode, JankType::AppDeadlineMissed, -4, 0, 25})); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); @@ -571,7 +572,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppMiss) { auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true); + sLayerNameOne, /*isBuffer*/ true, sGameMode); surfaceFrame1->setAcquireFenceTime(45); mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate); @@ -587,7 +588,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsSfScheduling) { Fps refreshRate = Fps::fromPeriodNsecs(32); EXPECT_CALL(*mTimeStats, incrementJankyFrames(TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne, - sLayerNameOne, + sLayerNameOne, sGameMode, JankType::SurfaceFlingerScheduling, -4, 0, -10})); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); @@ -597,7 +598,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsSfScheduling) { auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true); + sLayerNameOne, /*isBuffer*/ true, sGameMode); surfaceFrame1->setAcquireFenceTime(50); mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate); @@ -613,7 +614,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsSfPredictionError) { Fps refreshRate = Fps::fromPeriodNsecs(16); EXPECT_CALL(*mTimeStats, incrementJankyFrames(TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne, - sLayerNameOne, + sLayerNameOne, sGameMode, JankType::PredictionError, -4, 5, 0})); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); @@ -623,7 +624,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsSfPredictionError) { auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true); + sLayerNameOne, /*isBuffer*/ true, sGameMode); surfaceFrame1->setAcquireFenceTime(40); mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate); @@ -639,7 +640,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppBufferStuffing) { Fps refreshRate = Fps::fromPeriodNsecs(32); EXPECT_CALL(*mTimeStats, incrementJankyFrames(TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne, - sLayerNameOne, + sLayerNameOne, sGameMode, JankType::BufferStuffing, -4, 0, 0})); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); @@ -649,7 +650,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppBufferStuffing) { auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true); + sLayerNameOne, /*isBuffer*/ true, sGameMode); surfaceFrame1->setAcquireFenceTime(40); mFrameTimeline->setSfWakeUp(sfToken1, 82, refreshRate); @@ -666,9 +667,10 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppMissWithRenderRate) { Fps refreshRate = Fps::fromPeriodNsecs(11); Fps renderRate = Fps::fromPeriodNsecs(30); EXPECT_CALL(*mTimeStats, - incrementJankyFrames( - TimeStats::JankyFramesInfo{refreshRate, renderRate, sUidOne, sLayerNameOne, - JankType::AppDeadlineMissed, -4, 0, 25})); + incrementJankyFrames(TimeStats::JankyFramesInfo{refreshRate, renderRate, sUidOne, + sLayerNameOne, sGameMode, + JankType::AppDeadlineMissed, -4, 0, + 25})); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 60}); int64_t sfToken1 = mTokenManager->generateTokenForPredictions({82, 90, 90}); @@ -676,7 +678,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppMissWithRenderRate) { auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true); + sLayerNameOne, /*isBuffer*/ true, sGameMode); surfaceFrame1->setAcquireFenceTime(45); mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate); @@ -696,6 +698,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_displayFramePredictionExpiredPres EXPECT_CALL(*mTimeStats, incrementJankyFrames( TimeStats::JankyFramesInfo{refreshRate, renderRate, sUidOne, sLayerNameOne, + sGameMode, JankType::Unknown | JankType::AppDeadlineMissed, 0, 0, 25})); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); @@ -705,7 +708,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_displayFramePredictionExpiredPres auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true); + sLayerNameOne, /*isBuffer*/ true, sGameMode); surfaceFrame1->setAcquireFenceTime(45); // Trigger a prediction expiry flushTokens(); @@ -742,7 +745,7 @@ TEST_F(FrameTimelineTest, tracing_noPacketsSentWithoutTraceStart) { auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({token1, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, sLayerNameOne, - /*isBuffer*/ true); + /*isBuffer*/ true, sGameMode); // Set up the display frame mFrameTimeline->setSfWakeUp(token1, 20, Fps::fromPeriodNsecs(11)); @@ -769,7 +772,7 @@ TEST_F(FrameTimelineTest, tracing_sanityTest) { auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({token1, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, sLayerNameOne, - /*isBuffer*/ true); + /*isBuffer*/ true, sGameMode); // Set up the display frame mFrameTimeline->setSfWakeUp(token2, 20, Fps::fromPeriodNsecs(11)); @@ -815,7 +818,7 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_invalidTokenDoesNotEmitTracePacket) auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, sLayerNameOne, - /*isBuffer*/ true); + /*isBuffer*/ true, sGameMode); // Set up the display frame mFrameTimeline->setSfWakeUp(token1, 20, Fps::fromPeriodNsecs(11)); @@ -1128,11 +1131,11 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_emitsValidTracePacket) { auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true); + sLayerNameOne, /*isBuffer*/ true, sGameMode); auto surfaceFrame2 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true); + sLayerNameOne, /*isBuffer*/ true, sGameMode); surfaceFrame1->setActualQueueTime(10); surfaceFrame1->setDropTime(15); @@ -1288,7 +1291,7 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_predictionExpiredDoesNotTraceExpecte auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, /*inputEventId*/ 0}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true); + sLayerNameOne, /*isBuffer*/ true, sGameMode); surfaceFrame1->setActualQueueTime(appEndTime); surfaceFrame1->setAcquireFenceTime(appEndTime); @@ -1364,7 +1367,7 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_predictionExpiredDroppedFramesTraced auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, /*inputEventId*/ 0}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true); + sLayerNameOne, /*isBuffer*/ true, sGameMode); constexpr nsecs_t sfStartTime = std::chrono::nanoseconds(22ms).count(); constexpr nsecs_t sfEndTime = std::chrono::nanoseconds(30ms).count(); @@ -1433,7 +1436,7 @@ TEST_F(FrameTimelineTest, jankClassification_presentOnTimeDoesNotClassify) { auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true); + sLayerNameOne, /*isBuffer*/ true, sGameMode); mFrameTimeline->setSfWakeUp(sfToken1, 22, Fps::fromPeriodNsecs(11)); surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame); @@ -1649,7 +1652,7 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishEarlyPresen auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true); + sLayerNameOne, /*isBuffer*/ true, sGameMode); surfaceFrame1->setAcquireFenceTime(16); mFrameTimeline->setSfWakeUp(sfToken1, 22, Fps::fromPeriodNsecs(11)); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); @@ -1669,7 +1672,7 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishEarlyPresen auto surfaceFrame2 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true); + sLayerNameOne, /*isBuffer*/ true, sGameMode); surfaceFrame2->setAcquireFenceTime(36); mFrameTimeline->setSfWakeUp(sfToken2, 52, Fps::fromPeriodNsecs(11)); surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented); @@ -1701,8 +1704,8 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishEarlyPresen EXPECT_CALL(*mTimeStats, incrementJankyFrames( TimeStats::JankyFramesInfo{Fps::fromPeriodNsecs(11), std::nullopt, sUidOne, - sLayerNameOne, JankType::PredictionError, -3, 5, - 0})); + sLayerNameOne, sGameMode, + JankType::PredictionError, -3, 5, 0})); addEmptyDisplayFrame(); @@ -1729,7 +1732,7 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishLatePresent auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true); + sLayerNameOne, /*isBuffer*/ true, sGameMode); surfaceFrame1->setAcquireFenceTime(16); mFrameTimeline->setSfWakeUp(sfToken1, 22, Fps::fromPeriodNsecs(11)); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); @@ -1749,7 +1752,7 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishLatePresent auto surfaceFrame2 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true); + sLayerNameOne, /*isBuffer*/ true, sGameMode); surfaceFrame2->setAcquireFenceTime(36); mFrameTimeline->setSfWakeUp(sfToken2, 52, Fps::fromPeriodNsecs(11)); surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented); @@ -1781,8 +1784,8 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishLatePresent EXPECT_CALL(*mTimeStats, incrementJankyFrames( TimeStats::JankyFramesInfo{Fps::fromPeriodNsecs(11), std::nullopt, sUidOne, - sLayerNameOne, JankType::PredictionError, -3, 5, - 0})); + sLayerNameOne, sGameMode, + JankType::PredictionError, -3, 5, 0})); addEmptyDisplayFrame(); @@ -1808,7 +1811,7 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameLateFinishEarlyPresent) auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true); + sLayerNameOne, /*isBuffer*/ true, sGameMode); surfaceFrame1->setAcquireFenceTime(40); mFrameTimeline->setSfWakeUp(sfToken1, 42, Fps::fromPeriodNsecs(11)); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); @@ -1852,7 +1855,7 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameLateFinishLatePresent) auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true); + sLayerNameOne, /*isBuffer*/ true, sGameMode); surfaceFrame1->setAcquireFenceTime(26); mFrameTimeline->setSfWakeUp(sfToken1, 32, Fps::fromPeriodNsecs(11)); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); @@ -1872,7 +1875,7 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameLateFinishLatePresent) auto surfaceFrame2 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true); + sLayerNameOne, /*isBuffer*/ true, sGameMode); surfaceFrame2->setAcquireFenceTime(40); mFrameTimeline->setSfWakeUp(sfToken2, 43, Fps::fromPeriodNsecs(11)); surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented); @@ -1927,7 +1930,7 @@ TEST_F(FrameTimelineTest, jankClassification_multiJankBufferStuffingAndAppDeadli auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true); + sLayerNameOne, /*isBuffer*/ true, sGameMode); surfaceFrame1->setAcquireFenceTime(50); mFrameTimeline->setSfWakeUp(sfToken1, 52, Fps::fromPeriodNsecs(30)); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); @@ -1947,7 +1950,7 @@ TEST_F(FrameTimelineTest, jankClassification_multiJankBufferStuffingAndAppDeadli auto surfaceFrame2 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true); + sLayerNameOne, /*isBuffer*/ true, sGameMode); surfaceFrame2->setAcquireFenceTime(84); mFrameTimeline->setSfWakeUp(sfToken2, 112, Fps::fromPeriodNsecs(30)); surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented, 54); @@ -2005,7 +2008,7 @@ TEST_F(FrameTimelineTest, jankClassification_appDeadlineAdjustedForBufferStuffin auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true); + sLayerNameOne, /*isBuffer*/ true, sGameMode); surfaceFrame1->setAcquireFenceTime(50); mFrameTimeline->setSfWakeUp(sfToken1, 52, Fps::fromPeriodNsecs(30)); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); @@ -2025,7 +2028,7 @@ TEST_F(FrameTimelineTest, jankClassification_appDeadlineAdjustedForBufferStuffin auto surfaceFrame2 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true); + sLayerNameOne, /*isBuffer*/ true, sGameMode); surfaceFrame2->setAcquireFenceTime(80); mFrameTimeline->setSfWakeUp(sfToken2, 82, Fps::fromPeriodNsecs(30)); // Setting previous latch time to 54, adjusted deadline will be 54 + vsyncTime(30) = 84 @@ -2081,7 +2084,7 @@ TEST_F(FrameTimelineTest, computeFps_singleDisplayFrame_returnsZero) { auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken(FrameTimelineInfo(), sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, sLayerNameOne, - /*isBuffer*/ true); + /*isBuffer*/ true, sGameMode); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame1); @@ -2097,7 +2100,7 @@ TEST_F(FrameTimelineTest, computeFps_twoDisplayFrames_oneLayer) { auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken(FrameTimelineInfo(), sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, sLayerNameOne, - /*isBuffer*/ true); + /*isBuffer*/ true, sGameMode); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame1); @@ -2107,7 +2110,7 @@ TEST_F(FrameTimelineTest, computeFps_twoDisplayFrames_oneLayer) { auto surfaceFrame2 = mFrameTimeline->createSurfaceFrameForToken(FrameTimelineInfo(), sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, sLayerNameOne, - /*isBuffer*/ true); + /*isBuffer*/ true, sGameMode); auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame2); @@ -2123,7 +2126,7 @@ TEST_F(FrameTimelineTest, computeFps_twoDisplayFrames_twoLayers) { auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken(FrameTimelineInfo(), sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, sLayerNameOne, - /*isBuffer*/ true); + /*isBuffer*/ true, sGameMode); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame1); @@ -2133,7 +2136,7 @@ TEST_F(FrameTimelineTest, computeFps_twoDisplayFrames_twoLayers) { auto surfaceFrame2 = mFrameTimeline->createSurfaceFrameForToken(FrameTimelineInfo(), sPidOne, sUidOne, sLayerIdTwo, sLayerNameTwo, sLayerNameTwo, - /*isBuffer*/ true); + /*isBuffer*/ true, sGameMode); auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame2); @@ -2149,7 +2152,7 @@ TEST_F(FrameTimelineTest, computeFps_filtersOutLayers) { auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken(FrameTimelineInfo(), sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, sLayerNameOne, - /*isBuffer*/ true); + /*isBuffer*/ true, sGameMode); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame1); @@ -2159,7 +2162,7 @@ TEST_F(FrameTimelineTest, computeFps_filtersOutLayers) { auto surfaceFrame2 = mFrameTimeline->createSurfaceFrameForToken(FrameTimelineInfo(), sPidOne, sUidOne, sLayerIdTwo, sLayerNameTwo, sLayerNameTwo, - /*isBuffer*/ true); + /*isBuffer*/ true, sGameMode); auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame2); @@ -2178,7 +2181,7 @@ TEST_F(FrameTimelineTest, computeFps_averagesOverMultipleFrames) { auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken(FrameTimelineInfo(), sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, sLayerNameOne, - /*isBuffer*/ true); + /*isBuffer*/ true, sGameMode); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame1); @@ -2188,7 +2191,7 @@ TEST_F(FrameTimelineTest, computeFps_averagesOverMultipleFrames) { auto surfaceFrame2 = mFrameTimeline->createSurfaceFrameForToken(FrameTimelineInfo(), sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, sLayerNameOne, - /*isBuffer*/ true); + /*isBuffer*/ true, sGameMode); auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame2); @@ -2198,7 +2201,7 @@ TEST_F(FrameTimelineTest, computeFps_averagesOverMultipleFrames) { auto surfaceFrame3 = mFrameTimeline->createSurfaceFrameForToken(FrameTimelineInfo(), sPidOne, sUidOne, sLayerIdTwo, sLayerNameTwo, sLayerNameTwo, - /*isBuffer*/ true); + /*isBuffer*/ true, sGameMode); auto presentFence3 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); surfaceFrame3->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame3); @@ -2208,7 +2211,7 @@ TEST_F(FrameTimelineTest, computeFps_averagesOverMultipleFrames) { auto surfaceFrame4 = mFrameTimeline->createSurfaceFrameForToken(FrameTimelineInfo(), sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, sLayerNameOne, - /*isBuffer*/ true); + /*isBuffer*/ true, sGameMode); auto presentFence4 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); surfaceFrame4->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame4); @@ -2218,7 +2221,7 @@ TEST_F(FrameTimelineTest, computeFps_averagesOverMultipleFrames) { auto surfaceFrame5 = mFrameTimeline->createSurfaceFrameForToken(FrameTimelineInfo(), sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, sLayerNameOne, - /*isBuffer*/ true); + /*isBuffer*/ true, sGameMode); auto presentFence5 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); // Dropped frames will be excluded from fps computation surfaceFrame5->setPresentState(SurfaceFrame::PresentState::Dropped); diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp index 3e4e130a14..317cdf1592 100644 --- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp +++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp @@ -54,6 +54,9 @@ using testing::StrEq; using testing::UnorderedElementsAre; using PowerMode = hardware::graphics::composer::V2_4::IComposerClient::PowerMode; +using SurfaceflingerStatsLayerInfo = android::surfaceflinger::SurfaceflingerStatsLayerInfo; +using SurfaceflingerStatsLayerInfoWrapper = + android::surfaceflinger::SurfaceflingerStatsLayerInfoWrapper; // clang-format off #define FMT_PROTO true @@ -71,6 +74,7 @@ using PowerMode = hardware::graphics::composer::V2_4::IComposerClient::PowerMode const constexpr Fps kRefreshRate0 = Fps(static_cast<float>(REFRESH_RATE_0)); const constexpr Fps kRenderRate0 = Fps(static_cast<float>(RENDER_RATE_0)); +static constexpr int32_t kGameMode = TimeStatsHelper::GameModeUnsupported; enum InputCommand : int32_t { ENABLE = 0, @@ -143,15 +147,16 @@ public: std::string inputCommand(InputCommand cmd, bool useProto); void setTimeStamp(TimeStamp type, int32_t id, uint64_t frameNumber, nsecs_t ts, - TimeStats::SetFrameRateVote frameRateVote); + TimeStats::SetFrameRateVote frameRateVote, int32_t gameMode); int32_t genRandomInt32(int32_t begin, int32_t end); template <size_t N> void insertTimeRecord(const TimeStamp (&sequence)[N], int32_t id, uint64_t frameNumber, - nsecs_t ts, TimeStats::SetFrameRateVote frameRateVote = {}) { + nsecs_t ts, TimeStats::SetFrameRateVote frameRateVote = {}, + int32_t gameMode = kGameMode) { for (size_t i = 0; i < N; i++, ts += 1000000) { - setTimeStamp(sequence[i], id, frameNumber, ts, frameRateVote); + setTimeStamp(sequence[i], id, frameNumber, ts, frameRateVote, gameMode); } } @@ -200,11 +205,11 @@ static std::string genLayerName(int32_t layerId) { } void TimeStatsTest::setTimeStamp(TimeStamp type, int32_t id, uint64_t frameNumber, nsecs_t ts, - TimeStats::SetFrameRateVote frameRateVote) { + TimeStats::SetFrameRateVote frameRateVote, int32_t gameMode) { switch (type) { case TimeStamp::POST: - ASSERT_NO_FATAL_FAILURE( - mTimeStats->setPostTime(id, frameNumber, genLayerName(id), UID_0, ts)); + ASSERT_NO_FATAL_FAILURE(mTimeStats->setPostTime(id, frameNumber, genLayerName(id), + UID_0, ts, gameMode)); break; case TimeStamp::ACQUIRE: ASSERT_NO_FATAL_FAILURE(mTimeStats->setAcquireTime(id, frameNumber, ts)); @@ -221,12 +226,14 @@ void TimeStatsTest::setTimeStamp(TimeStamp type, int32_t id, uint64_t frameNumbe break; case TimeStamp::PRESENT: ASSERT_NO_FATAL_FAILURE(mTimeStats->setPresentTime(id, frameNumber, ts, kRefreshRate0, - kRenderRate0, frameRateVote)); + kRenderRate0, frameRateVote, + gameMode)); break; case TimeStamp::PRESENT_FENCE: - ASSERT_NO_FATAL_FAILURE( - mTimeStats->setPresentFence(id, frameNumber, std::make_shared<FenceTime>(ts), - kRefreshRate0, kRenderRate0, frameRateVote)); + ASSERT_NO_FATAL_FAILURE(mTimeStats->setPresentFence(id, frameNumber, + std::make_shared<FenceTime>(ts), + kRefreshRate0, kRenderRate0, + frameRateVote, gameMode)); break; default: ALOGD("Invalid timestamp type"); @@ -319,22 +326,24 @@ TEST_F(TimeStatsTest, canIncreaseJankyFramesForLayer) { insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - JankType::SurfaceFlingerCpuDeadlineMissed, 1, 2, 3}); - mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - JankType::SurfaceFlingerGpuDeadlineMissed, 1, 2, 3}); + kGameMode, JankType::SurfaceFlingerCpuDeadlineMissed, 1, 2, + 3}); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - JankType::DisplayHAL, 1, 2, 3}); + kGameMode, JankType::SurfaceFlingerGpuDeadlineMissed, 1, 2, + 3}); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - JankType::AppDeadlineMissed, 1, 2, 3}); + kGameMode, JankType::DisplayHAL, 1, 2, 3}); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - JankType::SurfaceFlingerScheduling, 1, 2, 3}); + kGameMode, JankType::AppDeadlineMissed, 1, 2, 3}); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - JankType::PredictionError, 1, 2, 3}); + kGameMode, JankType::SurfaceFlingerScheduling, 1, 2, 3}); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - JankType::AppDeadlineMissed | JankType::BufferStuffing, 1, 2, - 3}); + kGameMode, JankType::PredictionError, 1, 2, 3}); + mTimeStats->incrementJankyFrames( + {kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), kGameMode, + JankType::AppDeadlineMissed | JankType::BufferStuffing, 1, 2, 3}); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - JankType::None, 1, 2, 3}); + kGameMode, JankType::None, 1, 2, 3}); const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING)); std::string expectedResult = @@ -872,22 +881,24 @@ TEST_F(TimeStatsTest, canClearDumpOnlyTimeStats) { std::make_shared<FenceTime>(std::chrono::nanoseconds(1ms).count())); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - JankType::SurfaceFlingerCpuDeadlineMissed, 1, 2, 3}); - mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - JankType::SurfaceFlingerGpuDeadlineMissed, 1, 2, 3}); + kGameMode, JankType::SurfaceFlingerCpuDeadlineMissed, 1, 2, + 3}); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - JankType::DisplayHAL, 1, 2, 3}); + kGameMode, JankType::SurfaceFlingerGpuDeadlineMissed, 1, 2, + 3}); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - JankType::AppDeadlineMissed, 1, 2, 3}); + kGameMode, JankType::DisplayHAL, 1, 2, 3}); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - JankType::SurfaceFlingerScheduling, 1, 2, 3}); + kGameMode, JankType::AppDeadlineMissed, 1, 2, 3}); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - JankType::PredictionError, 1, 2, 3}); + kGameMode, JankType::SurfaceFlingerScheduling, 1, 2, 3}); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - JankType::AppDeadlineMissed | JankType::BufferStuffing, 1, 2, - 3}); + kGameMode, JankType::PredictionError, 1, 2, 3}); + mTimeStats->incrementJankyFrames( + {kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), kGameMode, + JankType::AppDeadlineMissed | JankType::BufferStuffing, 1, 2, 3}); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - JankType::None, 1, 2, 3}); + kGameMode, JankType::None, 1, 2, 3}); EXPECT_TRUE(inputCommand(InputCommand::CLEAR, FMT_STRING).empty()); @@ -1039,34 +1050,36 @@ TEST_F(TimeStatsTest, globalStatsCallback) { mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(5000000)); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - JankType::SurfaceFlingerCpuDeadlineMissed, + kGameMode, JankType::SurfaceFlingerCpuDeadlineMissed, DISPLAY_DEADLINE_DELTA, DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA}); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - JankType::SurfaceFlingerGpuDeadlineMissed, + kGameMode, JankType::SurfaceFlingerGpuDeadlineMissed, DISPLAY_DEADLINE_DELTA, DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA}); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - JankType::DisplayHAL, DISPLAY_DEADLINE_DELTA, - DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA}); - mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - JankType::AppDeadlineMissed, DISPLAY_DEADLINE_DELTA, - DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA}); - mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - JankType::SurfaceFlingerScheduling, DISPLAY_DEADLINE_DELTA, + kGameMode, JankType::DisplayHAL, DISPLAY_DEADLINE_DELTA, DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA}); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - JankType::PredictionError, DISPLAY_DEADLINE_DELTA, - DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA}); + kGameMode, JankType::AppDeadlineMissed, + DISPLAY_DEADLINE_DELTA, DISPLAY_PRESENT_JITTER, + APP_DEADLINE_DELTA}); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - JankType::AppDeadlineMissed | JankType::BufferStuffing, + kGameMode, JankType::SurfaceFlingerScheduling, DISPLAY_DEADLINE_DELTA, DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA}); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - JankType::BufferStuffing, DISPLAY_DEADLINE_DELTA, + kGameMode, JankType::PredictionError, DISPLAY_DEADLINE_DELTA, + DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA}); + mTimeStats->incrementJankyFrames( + {kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), kGameMode, + JankType::AppDeadlineMissed | JankType::BufferStuffing, DISPLAY_DEADLINE_DELTA, + DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA}); + mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), + kGameMode, JankType::BufferStuffing, DISPLAY_DEADLINE_DELTA, DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA}); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - JankType::None, DISPLAY_DEADLINE_DELTA, + kGameMode, JankType::None, DISPLAY_DEADLINE_DELTA, DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA}); std::string pulledData; @@ -1157,7 +1170,8 @@ TEST_F(TimeStatsTest, layerStatsCallback_pullsAllAndClears) { constexpr nsecs_t APP_DEADLINE_DELTA_3MS = 3'000'000; EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty()); - insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000); + insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000, {}, + TimeStatsHelper::GameModeStandard); for (size_t i = 0; i < LATE_ACQUIRE_FRAMES; i++) { mTimeStats->incrementLatchSkipped(LAYER_ID_0, TimeStats::LatchSkipReason::LateAcquire); } @@ -1170,43 +1184,50 @@ TEST_F(TimeStatsTest, layerStatsCallback_pullsAllAndClears) { TimeStats::SetFrameRateVote::FrameRateCompatibility::ExactOrMultiple, .seamlessness = TimeStats::SetFrameRateVote::Seamlessness::NotRequired, }; - insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000, frameRate60); - - mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - JankType::SurfaceFlingerCpuDeadlineMissed, - DISPLAY_DEADLINE_DELTA, DISPLAY_PRESENT_JITTER, - APP_DEADLINE_DELTA_3MS}); + insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000, frameRate60, + TimeStatsHelper::GameModeStandard); + + mTimeStats->incrementJankyFrames( + {kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), + TimeStatsHelper::GameModeStandard, JankType::SurfaceFlingerCpuDeadlineMissed, + DISPLAY_DEADLINE_DELTA, DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA_3MS}); + mTimeStats->incrementJankyFrames( + {kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), + TimeStatsHelper::GameModeStandard, JankType::SurfaceFlingerGpuDeadlineMissed, + DISPLAY_DEADLINE_DELTA, DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA_3MS}); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - JankType::SurfaceFlingerGpuDeadlineMissed, + TimeStatsHelper::GameModeStandard, JankType::DisplayHAL, DISPLAY_DEADLINE_DELTA, DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA_3MS}); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - JankType::DisplayHAL, DISPLAY_DEADLINE_DELTA, - DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA_3MS}); - mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), + TimeStatsHelper::GameModeStandard, JankType::AppDeadlineMissed, DISPLAY_DEADLINE_DELTA, DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA_3MS}); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), + TimeStatsHelper::GameModeStandard, JankType::SurfaceFlingerScheduling, DISPLAY_DEADLINE_DELTA, DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA_2MS}); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - JankType::PredictionError, DISPLAY_DEADLINE_DELTA, - DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA_2MS}); + TimeStatsHelper::GameModeStandard, JankType::PredictionError, + DISPLAY_DEADLINE_DELTA, DISPLAY_PRESENT_JITTER, + APP_DEADLINE_DELTA_2MS}); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), + TimeStatsHelper::GameModeStandard, JankType::AppDeadlineMissed | JankType::BufferStuffing, DISPLAY_DEADLINE_DELTA, APP_DEADLINE_DELTA_2MS, APP_DEADLINE_DELTA_2MS}); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - JankType::None, DISPLAY_DEADLINE_DELTA, - DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA_3MS}); + TimeStatsHelper::GameModeStandard, JankType::None, + DISPLAY_DEADLINE_DELTA, DISPLAY_PRESENT_JITTER, + APP_DEADLINE_DELTA_3MS}); std::string pulledData; EXPECT_TRUE(mTimeStats->onPullAtom(10063 /*SURFACEFLINGER_STATS_LAYER_INFO*/, &pulledData)); - android::surfaceflinger::SurfaceflingerStatsLayerInfoWrapper atomList; + SurfaceflingerStatsLayerInfoWrapper atomList; ASSERT_TRUE(atomList.ParseFromString(pulledData)); ASSERT_EQ(atomList.atom_size(), 1); - const android::surfaceflinger::SurfaceflingerStatsLayerInfo& atom = atomList.atom(0); + const SurfaceflingerStatsLayerInfo& atom = atomList.atom(0); EXPECT_EQ(atom.layer_name(), genLayerName(LAYER_ID_0)); EXPECT_EQ(atom.total_frames(), 1); @@ -1236,6 +1257,7 @@ TEST_F(TimeStatsTest, layerStatsCallback_pullsAllAndClears) { (int)frameRate60.frameRateCompatibility); EXPECT_EQ((int)atom.set_frame_rate_vote().seamlessness(), (int)frameRate60.seamlessness); EXPECT_THAT(atom.app_deadline_misses(), HistogramEq(buildExpectedHistogram({3, 2}, {4, 3}))); + EXPECT_EQ(atom.game_mode(), SurfaceflingerStatsLayerInfo::GAME_MODE_STANDARD); SFTimeStatsGlobalProto globalProto; ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO))); @@ -1268,6 +1290,92 @@ TEST_F(TimeStatsTest, layerStatsCallback_pullsAllAndClears) { EXPECT_THAT(result, Not(HasSubstr(expectedMissing))); } +TEST_F(TimeStatsTest, layerStatsCallback_multipleGameModes) { + constexpr size_t LATE_ACQUIRE_FRAMES = 2; + constexpr size_t BAD_DESIRED_PRESENT_FRAMES = 3; + EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty()); + + insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000, {}, + TimeStatsHelper::GameModeStandard); + for (size_t i = 0; i < LATE_ACQUIRE_FRAMES; i++) { + mTimeStats->incrementLatchSkipped(LAYER_ID_0, TimeStats::LatchSkipReason::LateAcquire); + } + for (size_t i = 0; i < BAD_DESIRED_PRESENT_FRAMES; i++) { + mTimeStats->incrementBadDesiredPresent(LAYER_ID_0); + } + insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000, {}, + TimeStatsHelper::GameModeStandard); + + insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 3, 3000000, {}, + TimeStatsHelper::GameModePerformance); + + insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 4, 4000000, {}, TimeStatsHelper::GameModeBattery); + insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 5, 4000000, {}, TimeStatsHelper::GameModeBattery); + + std::string pulledData; + EXPECT_TRUE(mTimeStats->onPullAtom(10063 /*SURFACEFLINGER_STATS_LAYER_INFO*/, &pulledData)); + + SurfaceflingerStatsLayerInfoWrapper atomList; + ASSERT_TRUE(atomList.ParseFromString(pulledData)); + // The first time record is never uploaded to stats. + ASSERT_EQ(atomList.atom_size(), 3); + // Layers are ordered based on the hash in LayerStatsKey. For this test, the order happens to + // be: 0 - Battery 1 - Performance 2 - Standard + const SurfaceflingerStatsLayerInfo& atom0 = atomList.atom(0); + + EXPECT_EQ(atom0.layer_name(), genLayerName(LAYER_ID_0)); + EXPECT_EQ(atom0.total_frames(), 2); + EXPECT_EQ(atom0.dropped_frames(), 0); + EXPECT_THAT(atom0.present_to_present(), HistogramEq(buildExpectedHistogram({0, 1}, {1, 1}))); + EXPECT_THAT(atom0.post_to_present(), HistogramEq(buildExpectedHistogram({4}, {2}))); + EXPECT_THAT(atom0.acquire_to_present(), HistogramEq(buildExpectedHistogram({3}, {2}))); + EXPECT_THAT(atom0.latch_to_present(), HistogramEq(buildExpectedHistogram({2}, {2}))); + EXPECT_THAT(atom0.desired_to_present(), HistogramEq(buildExpectedHistogram({1}, {2}))); + EXPECT_THAT(atom0.post_to_acquire(), HistogramEq(buildExpectedHistogram({1}, {2}))); + EXPECT_EQ(atom0.late_acquire_frames(), 0); + EXPECT_EQ(atom0.bad_desired_present_frames(), 0); + EXPECT_EQ(atom0.uid(), UID_0); + EXPECT_EQ(atom0.display_refresh_rate_bucket(), REFRESH_RATE_BUCKET_0); + EXPECT_EQ(atom0.render_rate_bucket(), RENDER_RATE_BUCKET_0); + EXPECT_EQ(atom0.game_mode(), SurfaceflingerStatsLayerInfo::GAME_MODE_BATTERY); + + const SurfaceflingerStatsLayerInfo& atom1 = atomList.atom(1); + + EXPECT_EQ(atom1.layer_name(), genLayerName(LAYER_ID_0)); + EXPECT_EQ(atom1.total_frames(), 1); + EXPECT_EQ(atom1.dropped_frames(), 0); + EXPECT_THAT(atom1.present_to_present(), HistogramEq(buildExpectedHistogram({1}, {1}))); + EXPECT_THAT(atom1.post_to_present(), HistogramEq(buildExpectedHistogram({4}, {1}))); + EXPECT_THAT(atom1.acquire_to_present(), HistogramEq(buildExpectedHistogram({3}, {1}))); + EXPECT_THAT(atom1.latch_to_present(), HistogramEq(buildExpectedHistogram({2}, {1}))); + EXPECT_THAT(atom1.desired_to_present(), HistogramEq(buildExpectedHistogram({1}, {1}))); + EXPECT_THAT(atom1.post_to_acquire(), HistogramEq(buildExpectedHistogram({1}, {1}))); + EXPECT_EQ(atom1.late_acquire_frames(), 0); + EXPECT_EQ(atom1.bad_desired_present_frames(), 0); + EXPECT_EQ(atom1.uid(), UID_0); + EXPECT_EQ(atom1.display_refresh_rate_bucket(), REFRESH_RATE_BUCKET_0); + EXPECT_EQ(atom1.render_rate_bucket(), RENDER_RATE_BUCKET_0); + EXPECT_EQ(atom1.game_mode(), SurfaceflingerStatsLayerInfo::GAME_MODE_PERFORMANCE); + + const SurfaceflingerStatsLayerInfo& atom2 = atomList.atom(2); + + EXPECT_EQ(atom2.layer_name(), genLayerName(LAYER_ID_0)); + EXPECT_EQ(atom2.total_frames(), 1); + EXPECT_EQ(atom2.dropped_frames(), 0); + EXPECT_THAT(atom2.present_to_present(), HistogramEq(buildExpectedHistogram({1}, {1}))); + EXPECT_THAT(atom2.post_to_present(), HistogramEq(buildExpectedHistogram({4}, {1}))); + EXPECT_THAT(atom2.acquire_to_present(), HistogramEq(buildExpectedHistogram({3}, {1}))); + EXPECT_THAT(atom2.latch_to_present(), HistogramEq(buildExpectedHistogram({2}, {1}))); + EXPECT_THAT(atom2.desired_to_present(), HistogramEq(buildExpectedHistogram({1}, {1}))); + EXPECT_THAT(atom2.post_to_acquire(), HistogramEq(buildExpectedHistogram({1}, {1}))); + EXPECT_EQ(atom2.late_acquire_frames(), LATE_ACQUIRE_FRAMES); + EXPECT_EQ(atom2.bad_desired_present_frames(), BAD_DESIRED_PRESENT_FRAMES); + EXPECT_EQ(atom2.uid(), UID_0); + EXPECT_EQ(atom2.display_refresh_rate_bucket(), REFRESH_RATE_BUCKET_0); + EXPECT_EQ(atom2.render_rate_bucket(), RENDER_RATE_BUCKET_0); + EXPECT_EQ(atom2.game_mode(), SurfaceflingerStatsLayerInfo::GAME_MODE_STANDARD); +} + TEST_F(TimeStatsTest, layerStatsCallback_pullsMultipleLayers) { EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty()); @@ -1279,7 +1387,7 @@ TEST_F(TimeStatsTest, layerStatsCallback_pullsMultipleLayers) { std::string pulledData; EXPECT_TRUE(mTimeStats->onPullAtom(10063 /*SURFACEFLINGER_STATS_LAYER_INFO*/, &pulledData)); - android::surfaceflinger::SurfaceflingerStatsLayerInfoWrapper atomList; + SurfaceflingerStatsLayerInfoWrapper atomList; ASSERT_TRUE(atomList.ParseFromString(pulledData)); ASSERT_EQ(atomList.atom_size(), 2); std::vector<std::string> actualLayerNames = {atomList.atom(0).layer_name(), @@ -1304,10 +1412,10 @@ TEST_F(TimeStatsTest, layerStatsCallback_pullsMultipleBuckets) { std::string pulledData; EXPECT_TRUE(mTimeStats->onPullAtom(10063 /*SURFACEFLINGER_STATS_LAYER_INFO*/, &pulledData)); - android::surfaceflinger::SurfaceflingerStatsLayerInfoWrapper atomList; + SurfaceflingerStatsLayerInfoWrapper atomList; ASSERT_TRUE(atomList.ParseFromString(pulledData)); ASSERT_EQ(atomList.atom_size(), 1); - const android::surfaceflinger::SurfaceflingerStatsLayerInfo& atom = atomList.atom(0); + const SurfaceflingerStatsLayerInfo& atom = atomList.atom(0); EXPECT_THAT(atom.present_to_present(), HistogramEq(buildExpectedHistogram({1, 2}, {2, 1}))); } @@ -1323,10 +1431,10 @@ TEST_F(TimeStatsTest, layerStatsCallback_limitsHistogramBuckets) { std::string pulledData; EXPECT_TRUE(mTimeStats->onPullAtom(10063 /*SURFACEFLINGER_STATS_LAYER_INFO*/, &pulledData)); - android::surfaceflinger::SurfaceflingerStatsLayerInfoWrapper atomList; + SurfaceflingerStatsLayerInfoWrapper atomList; ASSERT_TRUE(atomList.ParseFromString(pulledData)); ASSERT_EQ(atomList.atom_size(), 1); - const android::surfaceflinger::SurfaceflingerStatsLayerInfo& atom = atomList.atom(0); + const SurfaceflingerStatsLayerInfo& atom = atomList.atom(0); EXPECT_THAT(atom.present_to_present(), HistogramEq(buildExpectedHistogram({1}, {2}))); } @@ -1343,7 +1451,7 @@ TEST_F(TimeStatsTest, layerStatsCallback_limitsLayers) { std::string pulledData; EXPECT_TRUE(mTimeStats->onPullAtom(10063 /*SURFACEFLINGER_STATS_LAYER_INFO*/, &pulledData)); - android::surfaceflinger::SurfaceflingerStatsLayerInfoWrapper atomList; + SurfaceflingerStatsLayerInfoWrapper atomList; ASSERT_TRUE(atomList.ParseFromString(pulledData)); ASSERT_EQ(atomList.atom_size(), 1); EXPECT_EQ(atomList.atom(0).layer_name(), genLayerName(LAYER_ID_1)); @@ -1372,7 +1480,7 @@ TEST_F(TimeStatsTest, canSurviveMonkey) { TimeStamp type = static_cast<TimeStamp>(genRandomInt32(TIME_STAMP_BEGIN, TIME_STAMP_END)); const int32_t ts = genRandomInt32(1, 1000000000); ALOGV("type[%d], layerId[%d], frameNumber[%d], ts[%d]", type, layerId, frameNumber, ts); - setTimeStamp(type, layerId, frameNumber, ts, {}); + setTimeStamp(type, layerId, frameNumber, ts, {}, kGameMode); } } @@ -1383,8 +1491,8 @@ TEST_F(TimeStatsTest, refreshRateIsClampedToNearestBucket) { EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty()); insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000); - mTimeStats->incrementJankyFrames( - {fps, std::nullopt, UID_0, genLayerName(LAYER_ID_0), JankType::None, 0, 0, 0}); + mTimeStats->incrementJankyFrames({fps, std::nullopt, UID_0, genLayerName(LAYER_ID_0), + kGameMode, JankType::None, 0, 0, 0}); const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING)); std::string expectedResult = "displayRefreshRate = " + std::to_string(bucket) + " fps"; EXPECT_THAT(result, HasSubstr(expectedResult)) << "failed for " << fps; diff --git a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h index 526a847614..5aebd2f20e 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h +++ b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h @@ -41,18 +41,19 @@ public: MOCK_METHOD2(recordFrameDuration, void(nsecs_t, nsecs_t)); MOCK_METHOD2(recordRenderEngineDuration, void(nsecs_t, nsecs_t)); MOCK_METHOD2(recordRenderEngineDuration, void(nsecs_t, const std::shared_ptr<FenceTime>&)); - MOCK_METHOD5(setPostTime, void(int32_t, uint64_t, const std::string&, uid_t, nsecs_t)); + MOCK_METHOD6(setPostTime, void(int32_t, uint64_t, const std::string&, uid_t, nsecs_t, int32_t)); MOCK_METHOD2(incrementLatchSkipped, void(int32_t layerId, LatchSkipReason reason)); MOCK_METHOD1(incrementBadDesiredPresent, void(int32_t layerId)); MOCK_METHOD3(setLatchTime, void(int32_t, uint64_t, nsecs_t)); MOCK_METHOD3(setDesiredTime, void(int32_t, uint64_t, nsecs_t)); MOCK_METHOD3(setAcquireTime, void(int32_t, uint64_t, nsecs_t)); MOCK_METHOD3(setAcquireFence, void(int32_t, uint64_t, const std::shared_ptr<FenceTime>&)); - MOCK_METHOD6(setPresentTime, - void(int32_t, uint64_t, nsecs_t, Fps, std::optional<Fps>, SetFrameRateVote)); - MOCK_METHOD6(setPresentFence, + MOCK_METHOD7(setPresentTime, + void(int32_t, uint64_t, nsecs_t, Fps, std::optional<Fps>, SetFrameRateVote, + int32_t)); + MOCK_METHOD7(setPresentFence, void(int32_t, uint64_t, const std::shared_ptr<FenceTime>&, Fps, std::optional<Fps>, - SetFrameRateVote)); + SetFrameRateVote, int32_t)); MOCK_METHOD1(incrementJankyFrames, void(const JankyFramesInfo&)); MOCK_METHOD1(onDestroy, void(int32_t)); MOCK_METHOD2(removeTimeRecord, void(int32_t, uint64_t)); |