Plumb refresh and render rates into shared timeline

* Make the overridden frame rate from the Scheduler public so that
SurfaceFlinger can access it for each uid.
* Add the display refresh rate on each display frame
* Add the application rendering rate on each SurfaceFrame created
* If there is no application rendering rate, then set it to the display
refresh rate.
* Plumb all those metrics into TimeStats.
* Change global metrics to increment for every SurfaceFrame instead of
every DisplayFrame, so that the rendering rate dimension can be
accurately captured.

Bug: 172937287
Test: builds, boots, timestats dump
Change-Id: Icfd4cecfdfa5d6c434661cab91c624eb08e8baea
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index ec81ff7..097f7de 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -366,8 +366,11 @@
         mFrameTracker.setFrameReadyTime(desiredPresentTime);
     }
 
+    const Fps refreshRate = mFlinger->mRefreshRateConfigs->getCurrentRefreshRate().getFps();
+    const std::optional<Fps> renderRate = mFlinger->mScheduler->getFrameRateOverride(getOwnerUid());
     if (presentFence->isValid()) {
-        mFlinger->mTimeStats->setPresentFence(layerId, mCurrentFrameNumber, presentFence);
+        mFlinger->mTimeStats->setPresentFence(layerId, mCurrentFrameNumber, presentFence,
+                                              refreshRate, renderRate);
         mFlinger->mFrameTracer->traceFence(layerId, getCurrentBufferId(), mCurrentFrameNumber,
                                            presentFence, FrameTracer::FrameEvent::PRESENT_FENCE);
         mFrameTracker.setActualPresentFence(std::shared_ptr<FenceTime>(presentFence));
@@ -378,7 +381,8 @@
         // The HWC doesn't support present fences, so use the refresh
         // timestamp instead.
         const nsecs_t actualPresentTime = display->getRefreshTimestamp();
-        mFlinger->mTimeStats->setPresentTime(layerId, mCurrentFrameNumber, actualPresentTime);
+        mFlinger->mTimeStats->setPresentTime(layerId, mCurrentFrameNumber, actualPresentTime,
+                                             refreshRate, renderRate);
         mFlinger->mFrameTracer->traceTimestamp(layerId, getCurrentBufferId(), mCurrentFrameNumber,
                                                actualPresentTime,
                                                FrameTracer::FrameEvent::PRESENT_FENCE);
diff --git a/services/surfaceflinger/Fps.h b/services/surfaceflinger/Fps.h
index 38a9af0..e9f06e5 100644
--- a/services/surfaceflinger/Fps.h
+++ b/services/surfaceflinger/Fps.h
@@ -27,7 +27,7 @@
 
 // Value which represents "frames per second". This class is a wrapper around
 // float, providing some useful utilities, such as comparisons with tolerance
-// and converting between period duruation and frequency.
+// and converting between period duration and frequency.
 class Fps {
 public:
     static constexpr Fps fromPeriodNsecs(nsecs_t period) { return Fps(1e9f / period, period); }
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
index 3f833f4..3f368c3 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
@@ -320,6 +320,11 @@
     mLastLatchTime = lastLatchTime;
 }
 
+void SurfaceFrame::setRenderRate(Fps renderRate) {
+    std::lock_guard<std::mutex> lock(mMutex);
+    mRenderRate = renderRate;
+}
+
 std::optional<int32_t> SurfaceFrame::getJankType() const {
     std::scoped_lock lock(mMutex);
     if (mActuals.presentTime == 0) {
@@ -367,6 +372,9 @@
     StringAppendF(&result, "%s", indent.c_str());
     StringAppendF(&result, "Owner Pid : %d\n", mOwnerPid);
     StringAppendF(&result, "%s", indent.c_str());
+    StringAppendF(&result, "Scheduled rendering rate: %d fps\n",
+                  mRenderRate ? mRenderRate->getIntValue() : 0);
+    StringAppendF(&result, "%s", indent.c_str());
     StringAppendF(&result, "Present State : %s\n", toString(mPresentState).c_str());
     StringAppendF(&result, "%s", indent.c_str());
     StringAppendF(&result, "Prediction State : %s\n", toString(mPredictionState).c_str());
@@ -391,9 +399,10 @@
     dumpTable(result, mPredictions, mActuals, indent, mPredictionState, baseTime);
 }
 
-void SurfaceFrame::onPresent(nsecs_t presentTime, int32_t displayFrameJankType,
-                             nsecs_t vsyncPeriod) {
+void SurfaceFrame::onPresent(nsecs_t presentTime, int32_t displayFrameJankType, Fps refreshRate) {
     std::scoped_lock lock(mMutex);
+
+    const Fps renderRate = mRenderRate ? *mRenderRate : refreshRate;
     if (mPresentState != PresentState::Presented) {
         // No need to update dropped buffers
         return;
@@ -412,13 +421,13 @@
         mJankType = JankType::Unknown;
         mFramePresentMetadata = FramePresentMetadata::UnknownPresent;
         mFrameReadyMetadata = FrameReadyMetadata::UnknownFinish;
-        mTimeStats->incrementJankyFrames(mOwnerUid, mLayerName, mJankType);
+        mTimeStats->incrementJankyFrames(refreshRate, renderRate, mOwnerUid, mLayerName, mJankType);
         return;
     }
 
     const nsecs_t presentDelta = mActuals.presentTime - mPredictions.presentTime;
     const nsecs_t deadlineDelta = mActuals.endTime - mPredictions.endTime;
-    const nsecs_t deltaToVsync = std::abs(presentDelta) % vsyncPeriod;
+    const nsecs_t deltaToVsync = std::abs(presentDelta) % refreshRate.getPeriodNsecs();
 
     if (deadlineDelta > mJankClassificationThresholds.deadlineThreshold) {
         mFrameReadyMetadata = FrameReadyMetadata::LateFinish;
@@ -440,7 +449,8 @@
         if (mFrameReadyMetadata == FrameReadyMetadata::OnTimeFinish) {
             // Finish on time, Present early
             if (deltaToVsync < mJankClassificationThresholds.presentThreshold ||
-                deltaToVsync >= vsyncPeriod - mJankClassificationThresholds.presentThreshold) {
+                deltaToVsync >= refreshRate.getPeriodNsecs() -
+                                mJankClassificationThresholds.presentThreshold) {
                 // Delta factor of vsync
                 mJankType = JankType::SurfaceFlingerScheduling;
             } else {
@@ -463,7 +473,8 @@
                 mJankType |= displayFrameJankType;
             } else {
                 if (deltaToVsync < mJankClassificationThresholds.presentThreshold ||
-                    deltaToVsync >= vsyncPeriod - mJankClassificationThresholds.presentThreshold) {
+                    deltaToVsync >= refreshRate.getPeriodNsecs() -
+                                    mJankClassificationThresholds.presentThreshold) {
                     // Delta factor of vsync
                     mJankType |= JankType::SurfaceFlingerScheduling;
                 } else {
@@ -482,7 +493,7 @@
             }
         }
     }
-    mTimeStats->incrementJankyFrames(mOwnerUid, mLayerName, mJankType);
+    mTimeStats->incrementJankyFrames(refreshRate, renderRate, mOwnerUid, mLayerName, mJankType);
 }
 
 /**
@@ -684,10 +695,10 @@
     mCurrentDisplayFrame->addSurfaceFrame(surfaceFrame);
 }
 
-void FrameTimeline::setSfWakeUp(int64_t token, nsecs_t wakeUpTime, nsecs_t vsyncPeriod) {
+void FrameTimeline::setSfWakeUp(int64_t token, nsecs_t wakeUpTime, Fps refreshRate) {
     ATRACE_CALL();
     std::scoped_lock lock(mMutex);
-    mCurrentDisplayFrame->onSfWakeUp(token, vsyncPeriod,
+    mCurrentDisplayFrame->onSfWakeUp(token, refreshRate,
                                      mTokenManager.getPredictionsForToken(token), wakeUpTime);
 }
 
@@ -705,11 +716,11 @@
     mSurfaceFrames.push_back(surfaceFrame);
 }
 
-void FrameTimeline::DisplayFrame::onSfWakeUp(int64_t token, nsecs_t vsyncPeriod,
+void FrameTimeline::DisplayFrame::onSfWakeUp(int64_t token, Fps refreshRate,
                                              std::optional<TimelineItem> predictions,
                                              nsecs_t wakeUpTime) {
     mToken = token;
-    mVsyncPeriod = vsyncPeriod;
+    mRefreshRate = refreshRate;
     if (!predictions) {
         mPredictionState = PredictionState::Expired;
     } else {
@@ -719,11 +730,6 @@
     mSurfaceFlingerActuals.startTime = wakeUpTime;
 }
 
-void FrameTimeline::DisplayFrame::setTokenAndVsyncPeriod(int64_t token, nsecs_t vsyncPeriod) {
-    mToken = token;
-    mVsyncPeriod = vsyncPeriod;
-}
-
 void FrameTimeline::DisplayFrame::setPredictions(PredictionState predictionState,
                                                  TimelineItem predictions) {
     mPredictionState = predictionState;
@@ -740,14 +746,13 @@
 
 void FrameTimeline::DisplayFrame::onPresent(nsecs_t signalTime) {
     mSurfaceFlingerActuals.presentTime = signalTime;
-    int32_t totalJankReasons = JankType::None;
 
     // Delta between the expected present and the actual present
     const nsecs_t presentDelta =
             mSurfaceFlingerActuals.presentTime - mSurfaceFlingerPredictions.presentTime;
     // How far off was the presentDelta when compared to the vsyncPeriod. Used in checking if there
     // was a prediction error or not.
-    nsecs_t deltaToVsync = std::abs(presentDelta) % mVsyncPeriod;
+    nsecs_t deltaToVsync = std::abs(presentDelta) % mRefreshRate.getPeriodNsecs();
     if (std::abs(presentDelta) > mJankClassificationThresholds.presentThreshold) {
         mFramePresentMetadata = presentDelta > 0 ? FramePresentMetadata::LatePresent
                                                  : FramePresentMetadata::EarlyPresent;
@@ -776,8 +781,8 @@
             if (mFrameReadyMetadata == FrameReadyMetadata::OnTimeFinish) {
                 // Finish on time, Present early
                 if (deltaToVsync < mJankClassificationThresholds.presentThreshold ||
-                    deltaToVsync >=
-                            (mVsyncPeriod - mJankClassificationThresholds.presentThreshold)) {
+                    deltaToVsync >= (mRefreshRate.getPeriodNsecs() -
+                                     mJankClassificationThresholds.presentThreshold)) {
                     // Delta is a factor of vsync if its within the presentTheshold on either side
                     // of the vsyncPeriod. Example: 0-2ms and 9-11ms are both within the threshold
                     // of the vsyncPeriod if the threshold was 2ms and the vsyncPeriod was 11ms.
@@ -797,8 +802,8 @@
             if (mFrameReadyMetadata == FrameReadyMetadata::OnTimeFinish) {
                 // Finish on time, Present late
                 if (deltaToVsync < mJankClassificationThresholds.presentThreshold ||
-                    deltaToVsync >=
-                            (mVsyncPeriod - mJankClassificationThresholds.presentThreshold)) {
+                    deltaToVsync >= (mRefreshRate.getPeriodNsecs() -
+                                     mJankClassificationThresholds.presentThreshold)) {
                     // Delta is a factor of vsync if its within the presentTheshold on either side
                     // of the vsyncPeriod. Example: 0-2ms and 9-11ms are both within the threshold
                     // of the vsyncPeriod if the threshold was 2ms and the vsyncPeriod was 11ms.
@@ -819,16 +824,9 @@
             mJankType = JankType::Unknown;
         }
     }
-    totalJankReasons |= mJankType;
-
     for (auto& surfaceFrame : mSurfaceFrames) {
-        surfaceFrame->onPresent(signalTime, mJankType, mVsyncPeriod);
-        auto surfaceFrameJankType = surfaceFrame->getJankType();
-        if (surfaceFrameJankType != std::nullopt) {
-            totalJankReasons |= *surfaceFrameJankType;
-        }
+        surfaceFrame->onPresent(signalTime, mJankType, mRefreshRate);
     }
-    mTimeStats->incrementJankyFrames(totalJankReasons);
 }
 
 void FrameTimeline::DisplayFrame::trace(pid_t surfaceFlingerPid) const {
@@ -988,7 +986,7 @@
     StringAppendF(&result, "Present Metadata : %s\n", toString(mFramePresentMetadata).c_str());
     StringAppendF(&result, "Finish Metadata: %s\n", toString(mFrameReadyMetadata).c_str());
     StringAppendF(&result, "Start Metadata: %s\n", toString(mFrameStartMetadata).c_str());
-    std::chrono::nanoseconds vsyncPeriod(mVsyncPeriod);
+    std::chrono::nanoseconds vsyncPeriod(mRefreshRate.getPeriodNsecs());
     StringAppendF(&result, "Vsync Period: %10f\n",
                   std::chrono::duration<double, std::milli>(vsyncPeriod).count());
     nsecs_t presentDelta =
@@ -996,7 +994,7 @@
     std::chrono::nanoseconds presentDeltaNs(std::abs(presentDelta));
     StringAppendF(&result, "Present delta: %10f\n",
                   std::chrono::duration<double, std::milli>(presentDeltaNs).count());
-    std::chrono::nanoseconds deltaToVsync(std::abs(presentDelta) % mVsyncPeriod);
+    std::chrono::nanoseconds deltaToVsync(std::abs(presentDelta) % mRefreshRate.getPeriodNsecs());
     StringAppendF(&result, "Present delta %% refreshrate: %10f\n",
                   std::chrono::duration<double, std::milli>(deltaToVsync).count());
     dumpTable(result, mSurfaceFlingerPredictions, mSurfaceFlingerActuals, "", mPredictionState,
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.h b/services/surfaceflinger/FrameTimeline/FrameTimeline.h
index 54e8efb..3ddd900 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.h
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.h
@@ -16,6 +16,7 @@
 
 #pragma once
 
+#include <../Fps.h>
 #include <../TimeStats/TimeStats.h>
 #include <gui/ISurfaceComposer.h>
 #include <gui/JankInfo.h>
@@ -175,13 +176,14 @@
     void setActualQueueTime(nsecs_t actualQueueTime);
     void setAcquireFenceTime(nsecs_t acquireFenceTime);
     void setPresentState(PresentState presentState, nsecs_t lastLatchTime = 0);
+    void setRenderRate(Fps renderRate);
 
     // Functions called by FrameTimeline
     // BaseTime is the smallest timestamp in this SurfaceFrame.
     // Used for dumping all timestamps relative to the oldest, making it easy to read.
     nsecs_t getBaseTime() const;
     // Sets the actual present time, appropriate metadata and classifies the jank.
-    void onPresent(nsecs_t presentTime, int32_t displayFrameJankType, nsecs_t vsyncPeriod);
+    void onPresent(nsecs_t presentTime, int32_t displayFrameJankType, Fps refreshRate);
     // All the timestamps are dumped relative to the baseTime
     void dump(std::string& result, const std::string& indent, nsecs_t baseTime) const;
     // Emits a packet for perfetto tracing. The function body will be executed only if tracing is
@@ -216,6 +218,8 @@
     int32_t mJankType GUARDED_BY(mMutex) = JankType::None;
     // Indicates if this frame was composited by the GPU or not
     bool mGpuComposition GUARDED_BY(mMutex) = false;
+    // Rendering rate for this frame.
+    std::optional<Fps> mRenderRate GUARDED_BY(mMutex);
     // Enum for the type of present
     FramePresentMetadata mFramePresentMetadata GUARDED_BY(mMutex) =
             FramePresentMetadata::UnknownPresent;
@@ -255,7 +259,7 @@
 
     // The first function called by SF for the current DisplayFrame. Fetches SF predictions based on
     // the token and sets the actualSfWakeTime for the current DisplayFrame.
-    virtual void setSfWakeUp(int64_t token, nsecs_t wakeupTime, nsecs_t vsyncPeriod) = 0;
+    virtual void setSfWakeUp(int64_t token, nsecs_t wakeupTime, Fps refreshRate) = 0;
 
     // Sets the sfPresentTime and finalizes the current DisplayFrame. Tracks the given present fence
     // until it's signaled, and updates the present timestamps of all presented SurfaceFrames in
@@ -325,14 +329,13 @@
         // is enabled.
         void trace(pid_t surfaceFlingerPid) const;
         // Sets the token, vsyncPeriod, predictions and SF start time.
-        void onSfWakeUp(int64_t token, nsecs_t vsyncPeriod, std::optional<TimelineItem> predictions,
+        void onSfWakeUp(int64_t token, Fps refreshRate, std::optional<TimelineItem> predictions,
                         nsecs_t wakeUpTime);
         // Sets the appropriate metadata, classifies the jank and returns the classified jankType.
         void onPresent(nsecs_t signalTime);
         // Adds the provided SurfaceFrame to the current display frame.
         void addSurfaceFrame(std::shared_ptr<SurfaceFrame> surfaceFrame);
 
-        void setTokenAndVsyncPeriod(int64_t token, nsecs_t vsyncPeriod);
         void setPredictions(PredictionState predictionState, TimelineItem predictions);
         void setActualStartTime(nsecs_t actualStartTime);
         void setActualEndTime(nsecs_t actualEndTime);
@@ -382,7 +385,7 @@
         FrameStartMetadata mFrameStartMetadata = FrameStartMetadata::UnknownStart;
         // The refresh rate (vsync period) in nanoseconds as seen by SF during this DisplayFrame's
         // timeline
-        nsecs_t mVsyncPeriod = 0;
+        Fps mRefreshRate;
         // TraceCookieCounter is used to obtain the cookie for sendig trace packets to perfetto.
         // Using a reference here because the counter is owned by FrameTimeline, which outlives
         // DisplayFrame.
@@ -398,7 +401,7 @@
             const FrameTimelineInfo& frameTimelineInfo, pid_t ownerPid, uid_t ownerUid,
             std::string layerName, std::string debugName) override;
     void addSurfaceFrame(std::shared_ptr<frametimeline::SurfaceFrame> surfaceFrame) override;
-    void setSfWakeUp(int64_t token, nsecs_t wakeupTime, nsecs_t vsyncPeriod) override;
+    void setSfWakeUp(int64_t token, nsecs_t wakeupTime, Fps refreshRate) override;
     void setSfPresent(nsecs_t sfPresentTime,
                       const std::shared_ptr<FenceTime>& presentFence) override;
     void parseArgs(const Vector<String16>& args, std::string& result) override;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index df14003..f271df8 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -1568,6 +1568,10 @@
     // For Transactions, the post time is considered to be both queue and acquire fence time.
     surfaceFrame->setActualQueueTime(postTime);
     surfaceFrame->setAcquireFenceTime(postTime);
+    const auto fps = mFlinger->mScheduler->getFrameRateOverride(getOwnerUid());
+    if (fps) {
+        mSurfaceFrame->setRenderRate(*fps);
+    }
     onSurfaceFrameCreated(surfaceFrame);
     return surfaceFrame;
 }
@@ -1579,6 +1583,10 @@
                                                                  debugName);
     // For buffers, acquire fence time will set during latch.
     surfaceFrame->setActualQueueTime(queueTime);
+    const auto fps = mFlinger->mScheduler->getFrameRateOverride(getOwnerUid());
+    if (fps) {
+        mSurfaceFrame->setRenderRate(*fps);
+    }
     // TODO(b/178542907): Implement onSurfaceFrameCreated for BQLayer as well.
     onSurfaceFrameCreated(surfaceFrame);
     return surfaceFrame;
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 5237516..0e9eba7 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -174,6 +174,8 @@
     // Stores the preferred refresh rate that an app should run at.
     // FrameRateOverride.refreshRateHz == 0 means no preference.
     void setPreferredRefreshRateForUid(FrameRateOverride) EXCLUDES(mFrameRateOverridesMutex);
+    // Retrieves the overridden refresh rate for a given uid.
+    std::optional<Fps> getFrameRateOverride(uid_t uid) const EXCLUDES(mFrameRateOverridesMutex);
 
 private:
     friend class TestableScheduler;
@@ -236,7 +238,6 @@
                                   Fps displayRefreshRate) REQUIRES(mFeatureStateLock)
             EXCLUDES(mFrameRateOverridesMutex);
 
-    std::optional<Fps> getFrameRateOverride(uid_t uid) const EXCLUDES(mFrameRateOverridesMutex);
     impl::EventThread::ThrottleVsyncCallback makeThrottleVsyncCallback() const;
 
     // Stores EventThread associated with a given VSyncSource, and an initial EventThreadConnection.
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index f785cae..4f274b6 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1899,7 +1899,7 @@
         const bool tracePreComposition = mTracingEnabled && !mTracePostComposition;
         ConditionalLockGuard<std::mutex> lock(mTracingLock, tracePreComposition);
 
-        mFrameTimeline->setSfWakeUp(vsyncId, frameStart, stats.vsyncPeriod);
+        mFrameTimeline->setSfWakeUp(vsyncId, frameStart, Fps::fromPeriodNsecs(stats.vsyncPeriod));
 
         refreshNeeded = handleMessageTransaction();
         refreshNeeded |= handleMessageInvalidate();
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index 5d387d6..c3f3671 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -105,53 +105,63 @@
 AStatsManager_PullAtomCallbackReturn TimeStats::populateGlobalAtom(AStatsEventList* data) {
     std::lock_guard<std::mutex> lock(mMutex);
 
-    if (mTimeStats.statsStart == 0) {
+    if (mTimeStats.statsStartLegacy == 0) {
         return AStatsManager_PULL_SKIP;
     }
     flushPowerTimeLocked();
 
-    AStatsEvent* event = mStatsDelegate->addStatsEventToPullData(data);
-    mStatsDelegate->statsEventSetAtomId(event, android::util::SURFACEFLINGER_STATS_GLOBAL_INFO);
-    mStatsDelegate->statsEventWriteInt64(event, mTimeStats.totalFrames);
-    mStatsDelegate->statsEventWriteInt64(event, mTimeStats.missedFrames);
-    mStatsDelegate->statsEventWriteInt64(event, mTimeStats.clientCompositionFrames);
-    mStatsDelegate->statsEventWriteInt64(event, mTimeStats.displayOnTime);
-    mStatsDelegate->statsEventWriteInt64(event, mTimeStats.presentToPresent.totalTime());
-    mStatsDelegate->statsEventWriteInt32(event, mTimeStats.displayEventConnectionsCount);
-    std::string frameDurationBytes =
-            histogramToProtoByteString(mTimeStats.frameDuration.hist, mMaxPulledHistogramBuckets);
-    mStatsDelegate->statsEventWriteByteArray(event, (const uint8_t*)frameDurationBytes.c_str(),
-                                             frameDurationBytes.size());
-    std::string renderEngineTimingBytes =
-            histogramToProtoByteString(mTimeStats.renderEngineTiming.hist,
-                                       mMaxPulledHistogramBuckets);
-    mStatsDelegate->statsEventWriteByteArray(event, (const uint8_t*)renderEngineTimingBytes.c_str(),
-                                             renderEngineTimingBytes.size());
+    for (const auto& globalSlice : mTimeStats.stats) {
+        AStatsEvent* event = mStatsDelegate->addStatsEventToPullData(data);
+        mStatsDelegate->statsEventSetAtomId(event, android::util::SURFACEFLINGER_STATS_GLOBAL_INFO);
+        mStatsDelegate->statsEventWriteInt64(event, mTimeStats.totalFramesLegacy);
+        mStatsDelegate->statsEventWriteInt64(event, mTimeStats.missedFramesLegacy);
+        mStatsDelegate->statsEventWriteInt64(event, mTimeStats.clientCompositionFramesLegacy);
+        mStatsDelegate->statsEventWriteInt64(event, mTimeStats.displayOnTimeLegacy);
+        mStatsDelegate->statsEventWriteInt64(event, mTimeStats.presentToPresentLegacy.totalTime());
+        mStatsDelegate->statsEventWriteInt32(event, mTimeStats.displayEventConnectionsCountLegacy);
+        std::string frameDurationBytes =
+                histogramToProtoByteString(mTimeStats.frameDurationLegacy.hist,
+                                           mMaxPulledHistogramBuckets);
+        mStatsDelegate->statsEventWriteByteArray(event, (const uint8_t*)frameDurationBytes.c_str(),
+                                                 frameDurationBytes.size());
+        std::string renderEngineTimingBytes =
+                histogramToProtoByteString(mTimeStats.renderEngineTimingLegacy.hist,
+                                           mMaxPulledHistogramBuckets);
+        mStatsDelegate->statsEventWriteByteArray(event,
+                                                 (const uint8_t*)renderEngineTimingBytes.c_str(),
+                                                 renderEngineTimingBytes.size());
 
-    mStatsDelegate->statsEventWriteInt32(event, mTimeStats.jankPayload.totalFrames);
-    mStatsDelegate->statsEventWriteInt32(event, mTimeStats.jankPayload.totalJankyFrames);
-    mStatsDelegate->statsEventWriteInt32(event, mTimeStats.jankPayload.totalSFLongCpu);
-    mStatsDelegate->statsEventWriteInt32(event, mTimeStats.jankPayload.totalSFLongGpu);
-    mStatsDelegate->statsEventWriteInt32(event, mTimeStats.jankPayload.totalSFUnattributed);
-    mStatsDelegate->statsEventWriteInt32(event, mTimeStats.jankPayload.totalAppUnattributed);
+        mStatsDelegate->statsEventWriteInt32(event, globalSlice.second.jankPayload.totalFrames);
+        mStatsDelegate->statsEventWriteInt32(event,
+                                             globalSlice.second.jankPayload.totalJankyFrames);
+        mStatsDelegate->statsEventWriteInt32(event, globalSlice.second.jankPayload.totalSFLongCpu);
+        mStatsDelegate->statsEventWriteInt32(event, globalSlice.second.jankPayload.totalSFLongGpu);
+        mStatsDelegate->statsEventWriteInt32(event,
+                                             globalSlice.second.jankPayload.totalSFUnattributed);
+        mStatsDelegate->statsEventWriteInt32(event,
+                                             globalSlice.second.jankPayload.totalAppUnattributed);
 
-    // TODO: populate these with real values
-    mStatsDelegate->statsEventWriteInt32(event, 0); // total_janky_frames_sf_scheduling
-    mStatsDelegate->statsEventWriteInt32(event, 0); // total_jank_frames_sf_prediction_error
-    mStatsDelegate->statsEventWriteInt32(event, 0); // total_jank_frames_app_buffer_stuffing
-    mStatsDelegate->statsEventWriteInt32(event, 0); // display_refresh_rate_bucket
-    std::string sfDeadlineMissedBytes =
-            histogramToProtoByteString(std::unordered_map<int32_t, int32_t>(),
-                                       mMaxPulledHistogramBuckets);
-    mStatsDelegate->statsEventWriteByteArray(event, (const uint8_t*)sfDeadlineMissedBytes.c_str(),
-                                             sfDeadlineMissedBytes.size()); // sf_deadline_misses
-    std::string sfPredictionErrorBytes =
-            histogramToProtoByteString(std::unordered_map<int32_t, int32_t>(),
-                                       mMaxPulledHistogramBuckets);
-    mStatsDelegate->statsEventWriteByteArray(event, (const uint8_t*)sfPredictionErrorBytes.c_str(),
-                                             sfPredictionErrorBytes.size()); // sf_prediction_errors
-    mStatsDelegate->statsEventWriteInt32(event, 0); // render_rate_bucket
-    mStatsDelegate->statsEventBuild(event);
+        // TODO: populate these with real values
+        mStatsDelegate->statsEventWriteInt32(event, 0); // total_janky_frames_sf_scheduling
+        mStatsDelegate->statsEventWriteInt32(event, 0); // total_jank_frames_sf_prediction_error
+        mStatsDelegate->statsEventWriteInt32(event, 0); // total_jank_frames_app_buffer_stuffing
+        mStatsDelegate->statsEventWriteInt32(event, globalSlice.first.displayRefreshRateBucket);
+        std::string sfDeadlineMissedBytes =
+                histogramToProtoByteString(std::unordered_map<int32_t, int32_t>(),
+                                           mMaxPulledHistogramBuckets);
+        mStatsDelegate
+                ->statsEventWriteByteArray(event, (const uint8_t*)sfDeadlineMissedBytes.c_str(),
+                                           sfDeadlineMissedBytes.size()); // sf_deadline_misses
+        std::string sfPredictionErrorBytes =
+                histogramToProtoByteString(std::unordered_map<int32_t, int32_t>(),
+                                           mMaxPulledHistogramBuckets);
+        mStatsDelegate
+                ->statsEventWriteByteArray(event, (const uint8_t*)sfPredictionErrorBytes.c_str(),
+                                           sfPredictionErrorBytes.size()); // sf_prediction_errors
+        mStatsDelegate->statsEventWriteInt32(event, globalSlice.first.renderRateBucket);
+        mStatsDelegate->statsEventBuild(event);
+    }
+
     clearGlobalLocked();
 
     return AStatsManager_PULL_SUCCESS;
@@ -161,8 +171,17 @@
     std::lock_guard<std::mutex> lock(mMutex);
 
     std::vector<TimeStatsHelper::TimeStatsLayer const*> dumpStats;
-    for (const auto& ele : mTimeStats.stats) {
-        dumpStats.push_back(&ele.second);
+    uint32_t numLayers = 0;
+    for (const auto& globalSlice : mTimeStats.stats) {
+        numLayers += globalSlice.second.stats.size();
+    }
+
+    dumpStats.reserve(numLayers);
+
+    for (const auto& globalSlice : mTimeStats.stats) {
+        for (const auto& layerSlice : globalSlice.second.stats) {
+            dumpStats.push_back(&layerSlice.second);
+        }
     }
 
     std::sort(dumpStats.begin(), dumpStats.end(),
@@ -208,8 +227,9 @@
         mStatsDelegate->statsEventWriteInt32(event, 0); // total_janky_frames_sf_scheduling
         mStatsDelegate->statsEventWriteInt32(event, 0); // total_jank_frames_sf_prediction_error
         mStatsDelegate->statsEventWriteInt32(event, 0); // total_jank_frames_app_buffer_stuffing
-        mStatsDelegate->statsEventWriteInt32(event, 0); // display_refresh_rate_bucket
-        mStatsDelegate->statsEventWriteInt32(event, 0); // render_rate_bucket
+        mStatsDelegate->statsEventWriteInt32(
+                event, layer->displayRefreshRateBucket); // display_refresh_rate_bucket
+        mStatsDelegate->statsEventWriteInt32(event, layer->renderRateBucket); // render_rate_bucket
         std::string frameRateVoteBytes = frameRateVoteToProtoByteString(0.0, 0, 0);
         mStatsDelegate->statsEventWriteByteArray(event, (const uint8_t*)frameRateVoteBytes.c_str(),
                                                  frameRateVoteBytes.size()); // set_frame_rate_vote
@@ -310,7 +330,7 @@
     ATRACE_CALL();
 
     std::lock_guard<std::mutex> lock(mMutex);
-    mTimeStats.totalFrames++;
+    mTimeStats.totalFramesLegacy++;
 }
 
 void TimeStats::incrementMissedFrames() {
@@ -319,7 +339,7 @@
     ATRACE_CALL();
 
     std::lock_guard<std::mutex> lock(mMutex);
-    mTimeStats.missedFrames++;
+    mTimeStats.missedFramesLegacy++;
 }
 
 void TimeStats::incrementClientCompositionFrames() {
@@ -328,7 +348,7 @@
     ATRACE_CALL();
 
     std::lock_guard<std::mutex> lock(mMutex);
-    mTimeStats.clientCompositionFrames++;
+    mTimeStats.clientCompositionFramesLegacy++;
 }
 
 void TimeStats::incrementClientCompositionReusedFrames() {
@@ -337,7 +357,7 @@
     ATRACE_CALL();
 
     std::lock_guard<std::mutex> lock(mMutex);
-    mTimeStats.clientCompositionReusedFrames++;
+    mTimeStats.clientCompositionReusedFramesLegacy++;
 }
 
 void TimeStats::incrementRefreshRateSwitches() {
@@ -346,7 +366,7 @@
     ATRACE_CALL();
 
     std::lock_guard<std::mutex> lock(mMutex);
-    mTimeStats.refreshRateSwitches++;
+    mTimeStats.refreshRateSwitchesLegacy++;
 }
 
 void TimeStats::incrementCompositionStrategyChanges() {
@@ -355,7 +375,7 @@
     ATRACE_CALL();
 
     std::lock_guard<std::mutex> lock(mMutex);
-    mTimeStats.compositionStrategyChanges++;
+    mTimeStats.compositionStrategyChangesLegacy++;
 }
 
 void TimeStats::recordDisplayEventConnectionCount(int32_t count) {
@@ -364,8 +384,8 @@
     ATRACE_CALL();
 
     std::lock_guard<std::mutex> lock(mMutex);
-    mTimeStats.displayEventConnectionsCount =
-            std::max(mTimeStats.displayEventConnectionsCount, count);
+    mTimeStats.displayEventConnectionsCountLegacy =
+            std::max(mTimeStats.displayEventConnectionsCountLegacy, count);
 }
 
 static int32_t msBetween(nsecs_t start, nsecs_t end) {
@@ -381,7 +401,7 @@
 
     std::lock_guard<std::mutex> lock(mMutex);
     if (mPowerTime.powerMode == PowerMode::ON) {
-        mTimeStats.frameDuration.insert(msBetween(startTime, endTime));
+        mTimeStats.frameDurationLegacy.insert(msBetween(startTime, endTime));
     }
 }
 
@@ -444,12 +464,22 @@
     return true;
 }
 
-void TimeStats::flushAvailableRecordsToStatsLocked(int32_t layerId) {
+static int32_t clampToSmallestBucket(Fps fps, size_t bucketWidth) {
+    return (fps.getIntValue() / bucketWidth) * bucketWidth;
+}
+
+void TimeStats::flushAvailableRecordsToStatsLocked(int32_t layerId, Fps displayRefreshRate,
+                                                   std::optional<Fps> renderRate) {
     ATRACE_CALL();
 
     LayerRecord& layerRecord = mTimeStatsTracker[layerId];
     TimeRecord& prevTimeRecord = layerRecord.prevTimeRecord;
     std::deque<TimeRecord>& timeRecords = layerRecord.timeRecords;
+    const int32_t refreshRateBucket =
+            clampToSmallestBucket(displayRefreshRate, REFRESH_RATE_BUCKET_WIDTH);
+    const int32_t renderRateBucket =
+            clampToSmallestBucket(renderRate ? *renderRate : displayRefreshRate,
+                                  RENDER_RATE_BUCKET_WIDTH);
     while (!timeRecords.empty()) {
         if (!recordReadyLocked(layerId, &timeRecords[0])) break;
         ALOGV("[%d]-[%" PRIu64 "]-presentFenceTime[%" PRId64 "]", layerId,
@@ -458,11 +488,21 @@
         if (prevTimeRecord.ready) {
             uid_t uid = layerRecord.uid;
             const std::string& layerName = layerRecord.layerName;
-            if (!mTimeStats.stats.count({uid, layerName})) {
-                mTimeStats.stats[{uid, layerName}].uid = uid;
-                mTimeStats.stats[{uid, layerName}].layerName = layerName;
+            TimeStatsHelper::TimelineStatsKey timelineKey = {refreshRateBucket, renderRateBucket};
+            if (!mTimeStats.stats.count(timelineKey)) {
+                mTimeStats.stats[timelineKey].key = timelineKey;
             }
-            TimeStatsHelper::TimeStatsLayer& timeStatsLayer = mTimeStats.stats[{uid, layerName}];
+
+            TimeStatsHelper::TimelineStats& displayStats = mTimeStats.stats[timelineKey];
+
+            TimeStatsHelper::LayerStatsKey layerKey = {uid, layerName};
+            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;
+            }
+            TimeStatsHelper::TimeStatsLayer& timeStatsLayer = displayStats.stats[layerKey];
             timeStatsLayer.totalFrames++;
             timeStatsLayer.droppedFrames += layerRecord.droppedFrames;
             timeStatsLayer.lateAcquireFrames += layerRecord.lateAcquireFrames;
@@ -524,8 +564,16 @@
 }
 
 bool TimeStats::canAddNewAggregatedStats(uid_t uid, const std::string& layerName) {
-    return mTimeStats.stats.count({uid, layerName}) > 0 ||
-            mTimeStats.stats.size() < MAX_NUM_LAYER_STATS;
+    uint32_t layerRecords = 0;
+    for (const auto& record : mTimeStats.stats) {
+        if (record.second.stats.count({uid, layerName}) > 0) {
+            return true;
+        }
+
+        layerRecords += record.second.stats.size();
+    }
+
+    return mTimeStats.stats.size() < MAX_NUM_LAYER_STATS;
 }
 
 void TimeStats::setPostTime(int32_t layerId, uint64_t frameNumber, const std::string& layerName,
@@ -676,7 +724,8 @@
     }
 }
 
-void TimeStats::setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t presentTime) {
+void TimeStats::setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t presentTime,
+                               Fps displayRefreshRate, std::optional<Fps> renderRate) {
     if (!mEnabled.load()) return;
 
     ATRACE_CALL();
@@ -695,11 +744,12 @@
         layerRecord.waitData++;
     }
 
-    flushAvailableRecordsToStatsLocked(layerId);
+    flushAvailableRecordsToStatsLocked(layerId, displayRefreshRate, renderRate);
 }
 
 void TimeStats::setPresentFence(int32_t layerId, uint64_t frameNumber,
-                                const std::shared_ptr<FenceTime>& presentFence) {
+                                const std::shared_ptr<FenceTime>& presentFence,
+                                Fps displayRefreshRate, std::optional<Fps> renderRate) {
     if (!mEnabled.load()) return;
 
     ATRACE_CALL();
@@ -719,7 +769,7 @@
         layerRecord.waitData++;
     }
 
-    flushAvailableRecordsToStatsLocked(layerId);
+    flushAvailableRecordsToStatsLocked(layerId, displayRefreshRate, renderRate);
 }
 
 template <class T>
@@ -746,16 +796,8 @@
     }
 }
 
-void TimeStats::incrementJankyFrames(int32_t reasons) {
-    if (!mEnabled.load()) return;
-
-    ATRACE_CALL();
-    std::lock_guard<std::mutex> lock(mMutex);
-
-    updateJankPayload<TimeStatsHelper::TimeStatsGlobal>(mTimeStats, reasons);
-}
-
-void TimeStats::incrementJankyFrames(uid_t uid, const std::string& layerName, int32_t reasons) {
+void TimeStats::incrementJankyFrames(Fps refreshRate, std::optional<Fps> renderRate, uid_t uid,
+                                     const std::string& layerName, int32_t reasons) {
     if (!mEnabled.load()) return;
 
     ATRACE_CALL();
@@ -772,16 +814,31 @@
     // TimeStats will flush the first present fence for a layer *before* FrameTimeline does so that
     // the first jank record is not dropped.
 
-    bool useDefaultLayerKey = false;
     static const std::string kDefaultLayerName = "none";
-    if (!mTimeStats.stats.count({uid, layerName})) {
-        mTimeStats.stats[{uid, kDefaultLayerName}].uid = uid;
-        mTimeStats.stats[{uid, kDefaultLayerName}].layerName = kDefaultLayerName;
-        useDefaultLayerKey = true;
+
+    const int32_t refreshRateBucket = clampToSmallestBucket(refreshRate, REFRESH_RATE_BUCKET_WIDTH);
+    const int32_t renderRateBucket =
+            clampToSmallestBucket(renderRate ? *renderRate : refreshRate, RENDER_RATE_BUCKET_WIDTH);
+    const TimeStatsHelper::TimelineStatsKey timelineKey = {refreshRateBucket, renderRateBucket};
+
+    if (!mTimeStats.stats.count(timelineKey)) {
+        mTimeStats.stats[timelineKey].key = timelineKey;
     }
 
-    TimeStatsHelper::TimeStatsLayer& timeStatsLayer =
-            mTimeStats.stats[{uid, useDefaultLayerKey ? kDefaultLayerName : layerName}];
+    TimeStatsHelper::TimelineStats& timelineStats = mTimeStats.stats[timelineKey];
+
+    updateJankPayload<TimeStatsHelper::TimelineStats>(timelineStats, reasons);
+
+    TimeStatsHelper::LayerStatsKey layerKey = {uid, layerName};
+    if (!timelineStats.stats.count(layerKey)) {
+        layerKey = {uid, kDefaultLayerName};
+        timelineStats.stats[layerKey].displayRefreshRateBucket = refreshRateBucket;
+        timelineStats.stats[layerKey].renderRateBucket = renderRateBucket;
+        timelineStats.stats[layerKey].uid = uid;
+        timelineStats.stats[layerKey].layerName = kDefaultLayerName;
+    }
+
+    TimeStatsHelper::TimeStatsLayer& timeStatsLayer = timelineStats.stats[layerKey];
     updateJankPayload<TimeStatsHelper::TimeStatsLayer>(timeStatsLayer, reasons);
 }
 
@@ -823,7 +880,7 @@
 
     switch (mPowerTime.powerMode) {
         case PowerMode::ON:
-            mTimeStats.displayOnTime += elapsedTime;
+            mTimeStats.displayOnTimeLegacy += elapsedTime;
             break;
         case PowerMode::OFF:
         case PowerMode::DOZE:
@@ -852,10 +909,10 @@
 
 void TimeStats::recordRefreshRate(uint32_t fps, nsecs_t duration) {
     std::lock_guard<std::mutex> lock(mMutex);
-    if (mTimeStats.refreshRateStats.count(fps)) {
-        mTimeStats.refreshRateStats[fps] += duration;
+    if (mTimeStats.refreshRateStatsLegacy.count(fps)) {
+        mTimeStats.refreshRateStatsLegacy[fps] += duration;
     } else {
-        mTimeStats.refreshRateStats.insert({fps, duration});
+        mTimeStats.refreshRateStatsLegacy.insert({fps, duration});
     }
 }
 
@@ -881,7 +938,7 @@
                     msBetween(mGlobalRecord.prevPresentTime, curPresentTime);
             ALOGV("Global present2present[%d] prev[%" PRId64 "] curr[%" PRId64 "]",
                   presentToPresentMs, mGlobalRecord.prevPresentTime, curPresentTime);
-            mTimeStats.presentToPresent.insert(presentToPresentMs);
+            mTimeStats.presentToPresentLegacy.insert(presentToPresentMs);
         }
 
         mGlobalRecord.prevPresentTime = curPresentTime;
@@ -908,7 +965,7 @@
         }
 
         const int32_t renderEngineMs = msBetween(duration.startTime, endNs);
-        mTimeStats.renderEngineTiming.insert(renderEngineMs);
+        mTimeStats.renderEngineTimingLegacy.insert(renderEngineMs);
 
         mGlobalRecord.renderEngineDurations.pop_front();
     }
@@ -951,7 +1008,7 @@
 
     std::lock_guard<std::mutex> lock(mMutex);
     mEnabled.store(true);
-    mTimeStats.statsStart = static_cast<int64_t>(std::time(0));
+    mTimeStats.statsStartLegacy = static_cast<int64_t>(std::time(0));
     mPowerTime.prevTime = systemTime();
     ALOGD("Enabled");
 }
@@ -964,7 +1021,7 @@
     std::lock_guard<std::mutex> lock(mMutex);
     flushPowerTimeLocked();
     mEnabled.store(false);
-    mTimeStats.statsEnd = static_cast<int64_t>(std::time(0));
+    mTimeStats.statsEndLegacy = static_cast<int64_t>(std::time(0));
     ALOGD("Disabled");
 }
 
@@ -977,21 +1034,20 @@
 void TimeStats::clearGlobalLocked() {
     ATRACE_CALL();
 
-    mTimeStats.statsStart = (mEnabled.load() ? static_cast<int64_t>(std::time(0)) : 0);
-    mTimeStats.statsEnd = 0;
-    mTimeStats.totalFrames = 0;
-    mTimeStats.missedFrames = 0;
-    mTimeStats.clientCompositionFrames = 0;
-    mTimeStats.clientCompositionReusedFrames = 0;
-    mTimeStats.refreshRateSwitches = 0;
-    mTimeStats.compositionStrategyChanges = 0;
-    mTimeStats.displayEventConnectionsCount = 0;
-    mTimeStats.displayOnTime = 0;
-    mTimeStats.presentToPresent.hist.clear();
-    mTimeStats.frameDuration.hist.clear();
-    mTimeStats.renderEngineTiming.hist.clear();
-    mTimeStats.jankPayload = TimeStatsHelper::JankPayload();
-    mTimeStats.refreshRateStats.clear();
+    mTimeStats.statsStartLegacy = (mEnabled.load() ? static_cast<int64_t>(std::time(0)) : 0);
+    mTimeStats.statsEndLegacy = 0;
+    mTimeStats.totalFramesLegacy = 0;
+    mTimeStats.missedFramesLegacy = 0;
+    mTimeStats.clientCompositionFramesLegacy = 0;
+    mTimeStats.clientCompositionReusedFramesLegacy = 0;
+    mTimeStats.refreshRateSwitchesLegacy = 0;
+    mTimeStats.compositionStrategyChangesLegacy = 0;
+    mTimeStats.displayEventConnectionsCountLegacy = 0;
+    mTimeStats.displayOnTimeLegacy = 0;
+    mTimeStats.presentToPresentLegacy.hist.clear();
+    mTimeStats.frameDurationLegacy.hist.clear();
+    mTimeStats.renderEngineTimingLegacy.hist.clear();
+    mTimeStats.refreshRateStatsLegacy.clear();
     mPowerTime.prevTime = systemTime();
     mGlobalRecord.prevPresentTime = 0;
     mGlobalRecord.presentFences.clear();
@@ -1014,11 +1070,11 @@
     ATRACE_CALL();
 
     std::lock_guard<std::mutex> lock(mMutex);
-    if (mTimeStats.statsStart == 0) {
+    if (mTimeStats.statsStartLegacy == 0) {
         return;
     }
 
-    mTimeStats.statsEnd = static_cast<int64_t>(std::time(0));
+    mTimeStats.statsEndLegacy = static_cast<int64_t>(std::time(0));
 
     flushPowerTimeLocked();
 
diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h
index df40ef6..e76849f 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.h
+++ b/services/surfaceflinger/TimeStats/TimeStats.h
@@ -27,12 +27,13 @@
 // TODO(b/129481165): remove the #pragma below and fix conversion issues
 #pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
 
+#include <../Fps.h>
+#include <gui/JankInfo.h>
 #include <stats_event.h>
 #include <stats_pull_atom_callback.h>
 #include <statslog.h>
 #include <timestatsproto/TimeStatsHelper.h>
 #include <timestatsproto/TimeStatsProtoHeader.h>
-#include <gui/JankInfo.h>
 #include <ui/FenceTime.h>
 #include <utils/String16.h>
 #include <utils/Vector.h>
@@ -108,23 +109,22 @@
                                  const std::shared_ptr<FenceTime>& acquireFence) = 0;
     // SetPresent{Time, Fence} are not expected to be called in the critical
     // rendering path, as they flush prior fences if those fences have fired.
-    virtual void setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t presentTime) = 0;
+    virtual void setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t presentTime,
+                                Fps displayRefreshRate, std::optional<Fps> renderRate) = 0;
     virtual void setPresentFence(int32_t layerId, uint64_t frameNumber,
-                                 const std::shared_ptr<FenceTime>& presentFence) = 0;
+                                 const std::shared_ptr<FenceTime>& presentFence,
+                                 Fps displayRefreshRate, std::optional<Fps> renderRate) = 0;
 
-    // Increments janky frames, tracked globally. Because FrameTimeline is the infrastructure
-    // responsible for computing jank in the system, this is expected to be called from
-    // FrameTimeline, rather than directly from SurfaceFlinger or individual layers. If there are no
-    // jank reasons, then total frames are incremented but jank is not, for accurate accounting of
-    // janky frames.
-    virtual void incrementJankyFrames(int32_t reasons) = 0;
-    // Increments janky frames, blamed to the provided {uid, layerName} key, with JankMetadata as
-    // supplementary reasons for the jank. Because FrameTimeline is the infrastructure responsible
-    // for computing jank in the system, this is expected to be called from FrameTimeline, rather
-    // than directly from SurfaceFlinger or individual layers.
-    // If there are no jank reasons, then total frames are incremented but jank is not, for accurate
+    // Increments janky frames, blamed to the provided {refreshRate, renderRate, uid, layerName}
+    // key, with JankMetadata as supplementary reasons for the jank. Because FrameTimeline is the
+    // infrastructure responsible for computing jank in the system, this is expected to be called
+    // from FrameTimeline, rather than directly from SurfaceFlinger or individual layers. If there
+    // are no jank reasons, then total frames are incremented but jank is not, for accurate
     // accounting of janky frames.
-    virtual void incrementJankyFrames(uid_t uid, const std::string& layerName, int32_t reasons) = 0;
+    // When these frame counts are incremented, these are also aggregated into a global reporting
+    // packet to help with data validation and assessing of overall device health.
+    virtual void incrementJankyFrames(Fps refreshRate, std::optional<Fps> renderRate, uid_t uid,
+                                      const std::string& layerName, int32_t reasons) = 0;
     // Clean up the layer record
     virtual void onDestroy(int32_t layerId) = 0;
     // If SF skips or rejects a buffer, remove the corresponding TimeRecord.
@@ -268,11 +268,13 @@
     void setAcquireTime(int32_t layerId, uint64_t frameNumber, nsecs_t acquireTime) override;
     void setAcquireFence(int32_t layerId, uint64_t frameNumber,
                          const std::shared_ptr<FenceTime>& acquireFence) override;
-    void setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t presentTime) override;
+    void setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t presentTime,
+                        Fps displayRefreshRate, std::optional<Fps> renderRate) override;
     void setPresentFence(int32_t layerId, uint64_t frameNumber,
-                         const std::shared_ptr<FenceTime>& presentFence) override;
-    void incrementJankyFrames(int32_t reasons) override;
-    void incrementJankyFrames(uid_t uid, const std::string& layerName, int32_t reasons) override;
+                         const std::shared_ptr<FenceTime>& presentFence, Fps displayRefreshRate,
+                         std::optional<Fps> renderRate) override;
+    void incrementJankyFrames(Fps refreshRate, std::optional<Fps> renderRate, uid_t uid,
+                              const std::string& layerName, int32_t reasons) override;
     // Clean up the layer record
     void onDestroy(int32_t layerId) override;
     // If SF skips or rejects a buffer, remove the corresponding TimeRecord.
@@ -293,7 +295,8 @@
     AStatsManager_PullAtomCallbackReturn populateGlobalAtom(AStatsEventList* data);
     AStatsManager_PullAtomCallbackReturn populateLayerAtom(AStatsEventList* data);
     bool recordReadyLocked(int32_t layerId, TimeRecord* timeRecord);
-    void flushAvailableRecordsToStatsLocked(int32_t layerId);
+    void flushAvailableRecordsToStatsLocked(int32_t layerId, Fps displayRefreshRate,
+                                            std::optional<Fps> renderRate);
     void flushPowerTimeLocked();
     void flushAvailableGlobalRecordsToStatsLocked();
     bool canAddNewAggregatedStats(uid_t uid, const std::string& layerName);
@@ -314,6 +317,9 @@
     GlobalRecord mGlobalRecord;
 
     static const size_t MAX_NUM_LAYER_RECORDS = 200;
+
+    static const size_t REFRESH_RATE_BUCKET_WIDTH = 30;
+    static const size_t RENDER_RATE_BUCKET_WIDTH = REFRESH_RATE_BUCKET_WIDTH;
     static const size_t MAX_NUM_LAYER_STATS = 200;
     static const size_t MAX_NUM_PULLED_LAYERS = MAX_NUM_LAYER_STATS;
     std::unique_ptr<StatsEventDelegate> mStatsDelegate = std::make_unique<StatsEventDelegate>();
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
index 0fb748f..df7be1f 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
+++ b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
@@ -90,6 +90,8 @@
 
 std::string TimeStatsHelper::TimeStatsLayer::toString() const {
     std::string result = "\n";
+    StringAppendF(&result, "displayRefreshRate = %d fps\n", displayRefreshRateBucket);
+    StringAppendF(&result, "renderRate = %d fps\n", renderRateBucket);
     StringAppendF(&result, "uid = %d\n", uid);
     StringAppendF(&result, "layerName = %s\n", layerName.c_str());
     StringAppendF(&result, "packageName = %s\n", packageName.c_str());
@@ -115,35 +117,45 @@
 
 std::string TimeStatsHelper::TimeStatsGlobal::toString(std::optional<uint32_t> maxLayers) const {
     std::string result = "SurfaceFlinger TimeStats:\n";
-    StringAppendF(&result, "statsStart = %" PRId64 "\n", statsStart);
-    StringAppendF(&result, "statsEnd = %" PRId64 "\n", statsEnd);
-    StringAppendF(&result, "totalFrames = %d\n", totalFrames);
-    StringAppendF(&result, "missedFrames = %d\n", missedFrames);
-    StringAppendF(&result, "clientCompositionFrames = %d\n", clientCompositionFrames);
-    StringAppendF(&result, "clientCompositionReusedFrames = %d\n", clientCompositionReusedFrames);
-    StringAppendF(&result, "refreshRateSwitches = %d\n", refreshRateSwitches);
-    StringAppendF(&result, "compositionStrategyChanges = %d\n", compositionStrategyChanges);
-    StringAppendF(&result, "displayOnTime = %" PRId64 " ms\n", displayOnTime);
-    result.append("Global aggregated jank payload:\n");
-    result.append(jankPayload.toString());
+    result.append("Legacy stats are as follows:\n");
+    StringAppendF(&result, "statsStart = %" PRId64 "\n", statsStartLegacy);
+    StringAppendF(&result, "statsEnd = %" PRId64 "\n", statsEndLegacy);
+    StringAppendF(&result, "totalFrames = %d\n", totalFramesLegacy);
+    StringAppendF(&result, "missedFrames = %d\n", missedFramesLegacy);
+    StringAppendF(&result, "clientCompositionFrames = %d\n", clientCompositionFramesLegacy);
+    StringAppendF(&result, "clientCompositionReusedFrames = %d\n",
+                  clientCompositionReusedFramesLegacy);
+    StringAppendF(&result, "refreshRateSwitches = %d\n", refreshRateSwitchesLegacy);
+    StringAppendF(&result, "compositionStrategyChanges = %d\n", compositionStrategyChangesLegacy);
+    StringAppendF(&result, "displayOnTime = %" PRId64 " ms\n", displayOnTimeLegacy);
     StringAppendF(&result, "displayConfigStats is as below:\n");
-    for (const auto& [fps, duration] : refreshRateStats) {
+    for (const auto& [fps, duration] : refreshRateStatsLegacy) {
         StringAppendF(&result, "%dfps = %ldms\n", fps, ns2ms(duration));
     }
     result.back() = '\n';
-    StringAppendF(&result, "totalP2PTime = %" PRId64 " ms\n", presentToPresent.totalTime());
+    StringAppendF(&result, "totalP2PTime = %" PRId64 " ms\n", presentToPresentLegacy.totalTime());
     StringAppendF(&result, "presentToPresent histogram is as below:\n");
-    result.append(presentToPresent.toString());
-    const float averageFrameDuration = frameDuration.averageTime();
+    result.append(presentToPresentLegacy.toString());
+    const float averageFrameDuration = frameDurationLegacy.averageTime();
     StringAppendF(&result, "averageFrameDuration = %.3f ms\n",
                   std::isnan(averageFrameDuration) ? 0.0f : averageFrameDuration);
     StringAppendF(&result, "frameDuration histogram is as below:\n");
-    result.append(frameDuration.toString());
-    const float averageRenderEngineTiming = renderEngineTiming.averageTime();
+    result.append(frameDurationLegacy.toString());
+    const float averageRenderEngineTiming = renderEngineTimingLegacy.averageTime();
     StringAppendF(&result, "averageRenderEngineTiming = %.3f ms\n",
                   std::isnan(averageRenderEngineTiming) ? 0.0f : averageRenderEngineTiming);
     StringAppendF(&result, "renderEngineTiming histogram is as below:\n");
-    result.append(renderEngineTiming.toString());
+    result.append(renderEngineTimingLegacy.toString());
+
+    result.append("\nGlobal aggregated jank payload (Timeline stats):");
+    for (const auto& ele : stats) {
+        result.append("\n");
+        StringAppendF(&result, "displayRefreshRate = %d fps\n",
+                      ele.second.key.displayRefreshRateBucket);
+        StringAppendF(&result, "renderRate = %d fps\n", ele.second.key.renderRateBucket);
+        result.append(ele.second.jankPayload.toString());
+    }
+
     const auto dumpStats = generateDumpStats(maxLayers);
     for (const auto& ele : dumpStats) {
         result.append(ele->toString());
@@ -173,30 +185,30 @@
 SFTimeStatsGlobalProto TimeStatsHelper::TimeStatsGlobal::toProto(
         std::optional<uint32_t> maxLayers) const {
     SFTimeStatsGlobalProto globalProto;
-    globalProto.set_stats_start(statsStart);
-    globalProto.set_stats_end(statsEnd);
-    globalProto.set_total_frames(totalFrames);
-    globalProto.set_missed_frames(missedFrames);
-    globalProto.set_client_composition_frames(clientCompositionFrames);
-    globalProto.set_display_on_time(displayOnTime);
-    for (const auto& ele : refreshRateStats) {
+    globalProto.set_stats_start(statsStartLegacy);
+    globalProto.set_stats_end(statsEndLegacy);
+    globalProto.set_total_frames(totalFramesLegacy);
+    globalProto.set_missed_frames(missedFramesLegacy);
+    globalProto.set_client_composition_frames(clientCompositionFramesLegacy);
+    globalProto.set_display_on_time(displayOnTimeLegacy);
+    for (const auto& ele : refreshRateStatsLegacy) {
         SFTimeStatsDisplayConfigBucketProto* configBucketProto =
                 globalProto.add_display_config_stats();
         SFTimeStatsDisplayConfigProto* configProto = configBucketProto->mutable_config();
         configProto->set_fps(ele.first);
         configBucketProto->set_duration_millis(ns2ms(ele.second));
     }
-    for (const auto& histEle : presentToPresent.hist) {
+    for (const auto& histEle : presentToPresentLegacy.hist) {
         SFTimeStatsHistogramBucketProto* histProto = globalProto.add_present_to_present();
         histProto->set_time_millis(histEle.first);
         histProto->set_frame_count(histEle.second);
     }
-    for (const auto& histEle : frameDuration.hist) {
+    for (const auto& histEle : frameDurationLegacy.hist) {
         SFTimeStatsHistogramBucketProto* histProto = globalProto.add_frame_duration();
         histProto->set_time_millis(histEle.first);
         histProto->set_frame_count(histEle.second);
     }
-    for (const auto& histEle : renderEngineTiming.hist) {
+    for (const auto& histEle : renderEngineTimingLegacy.hist) {
         SFTimeStatsHistogramBucketProto* histProto = globalProto.add_render_engine_timing();
         histProto->set_time_millis(histEle.first);
         histProto->set_frame_count(histEle.second);
@@ -212,8 +224,18 @@
 std::vector<TimeStatsHelper::TimeStatsLayer const*>
 TimeStatsHelper::TimeStatsGlobal::generateDumpStats(std::optional<uint32_t> maxLayers) const {
     std::vector<TimeStatsLayer const*> dumpStats;
+
+    int numLayers = 0;
     for (const auto& ele : stats) {
-        dumpStats.push_back(&ele.second);
+        numLayers += ele.second.stats.size();
+    }
+
+    dumpStats.reserve(numLayers);
+
+    for (const auto& ele : stats) {
+        for (const auto& layerEle : ele.second.stats) {
+            dumpStats.push_back(&layerEle.second);
+        }
     }
 
     std::sort(dumpStats.begin(), dumpStats.end(),
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
index 033eb5d..0144abc0 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
+++ b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
@@ -57,6 +57,8 @@
         uid_t uid;
         std::string layerName;
         std::string packageName;
+        int32_t displayRefreshRateBucket = 0;
+        int32_t renderRateBucket = 0;
         int32_t totalFrames = 0;
         int32_t droppedFrames = 0;
         int32_t lateAcquireFrames = 0;
@@ -68,32 +70,82 @@
         SFTimeStatsLayerProto toProto() const;
     };
 
-    class TimeStatsGlobal {
-    public:
-        int64_t statsStart = 0;
-        int64_t statsEnd = 0;
-        int32_t totalFrames = 0;
-        int32_t missedFrames = 0;
-        int32_t clientCompositionFrames = 0;
-        int32_t clientCompositionReusedFrames = 0;
-        int32_t refreshRateSwitches = 0;
-        int32_t compositionStrategyChanges = 0;
-        int32_t displayEventConnectionsCount = 0;
-        int64_t displayOnTime = 0;
-        Histogram presentToPresent;
-        Histogram frameDuration;
-        Histogram renderEngineTiming;
+    // Lifted from SkiaGLRenderEngine's LinearEffect class.
+    // Which in turn was inspired by art/runtime/class_linker.cc
+    // Also this is what boost:hash_combine does so this is a pretty good hash.
+    static size_t HashCombine(size_t seed, size_t val) {
+        return seed ^ (val + 0x9e3779b9 + (seed << 6) + (seed >> 2));
+    }
 
-        struct StatsHasher {
-            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);
+    struct TimelineStatsKey {
+        int32_t displayRefreshRateBucket = 0;
+        int32_t renderRateBucket = 0;
+
+        struct Hasher {
+            size_t operator()(const TimelineStatsKey& key) const {
+                size_t result = std::hash<int32_t>{}(key.displayRefreshRateBucket);
+                return HashCombine(result, std::hash<int32_t>{}(key.renderRateBucket));
             }
         };
-        std::unordered_map<std::pair<uid_t, std::string>, TimeStatsLayer, StatsHasher> stats;
-        std::unordered_map<uint32_t, nsecs_t> refreshRateStats;
+
+        bool operator==(const TimelineStatsKey& o) const {
+            return displayRefreshRateBucket == o.displayRefreshRateBucket &&
+                    renderRateBucket == o.renderRateBucket;
+        }
+    };
+
+    struct LayerStatsKey {
+        uid_t uid = 0;
+        std::string layerName;
+
+        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));
+            }
+        };
+
+        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);
+        }
+    };
+
+    struct TimelineStats {
+        TimelineStatsKey key;
         JankPayload jankPayload;
+        std::unordered_map<LayerStatsKey, TimeStatsLayer, LayerStatsKey::Hasher> stats;
+    };
+
+    class TimeStatsGlobal {
+    public:
+        // Note: these are all legacy statistics, we're keeping these around because a variety of
+        // systems and form-factors find these useful when comparing with older releases. However,
+        // the current recommendation is that the new timeline-based metrics are used, and the old
+        // ones are deprecated.
+        int64_t statsStartLegacy = 0;
+        int64_t statsEndLegacy = 0;
+        int32_t totalFramesLegacy = 0;
+        int32_t missedFramesLegacy = 0;
+        int32_t clientCompositionFramesLegacy = 0;
+        int32_t clientCompositionReusedFramesLegacy = 0;
+        int32_t refreshRateSwitchesLegacy = 0;
+        int32_t compositionStrategyChangesLegacy = 0;
+        int32_t displayEventConnectionsCountLegacy = 0;
+        int64_t displayOnTimeLegacy = 0;
+        Histogram presentToPresentLegacy;
+        Histogram frameDurationLegacy;
+        Histogram renderEngineTimingLegacy;
+        std::unordered_map<uint32_t, nsecs_t> refreshRateStatsLegacy;
+
+        std::unordered_map<TimelineStatsKey, TimelineStats, TimelineStatsKey::Hasher> stats;
 
         std::string toString(std::optional<uint32_t> maxLayers) const;
         SFTimeStatsGlobalProto toProto(std::optional<uint32_t> maxLayers) const;
diff --git a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
index 6e9f09b..a53655d 100644
--- a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
@@ -238,7 +238,6 @@
 
 TEST_F(FrameTimelineTest, presentFenceSignaled_droppedFramesNotUpdated) {
     // Global increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_));
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
 
@@ -249,14 +248,14 @@
                                                        sLayerNameOne, sLayerNameOne);
 
     // Set up the display frame
-    mFrameTimeline->setSfWakeUp(token1, 20, 11);
+    mFrameTimeline->setSfWakeUp(token1, 20, Fps::fromPeriodNsecs(11));
     surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Dropped);
     mFrameTimeline->addSurfaceFrame(surfaceFrame1);
     mFrameTimeline->setSfPresent(25, presentFence1);
     presentFence1->signalForTest(30);
 
     // Trigger a flush by calling setSfPresent for the next frame
-    mFrameTimeline->setSfWakeUp(token2, 50, 11);
+    mFrameTimeline->setSfWakeUp(token2, 50, Fps::fromPeriodNsecs(11));
     mFrameTimeline->setSfPresent(55, presentFence2);
 
     auto& droppedSurfaceFrame = getSurfaceFrame(0, 0);
@@ -265,10 +264,10 @@
 }
 
 TEST_F(FrameTimelineTest, presentFenceSignaled_presentedFramesUpdated) {
-    // Global increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_));
     // Layer specific increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_, testing::_, testing::_)).Times(2);
+    EXPECT_CALL(*mTimeStats,
+                incrementJankyFrames(testing::_, testing::_, testing::_, testing::_, testing::_))
+            .Times(2);
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 30});
     int64_t surfaceFrameToken2 = mTokenManager->generateTokenForPredictions({40, 50, 60});
@@ -280,7 +279,7 @@
     auto surfaceFrame2 =
             mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
                                                        sUidOne, sLayerNameTwo, sLayerNameTwo);
-    mFrameTimeline->setSfWakeUp(sfToken1, 22, 11);
+    mFrameTimeline->setSfWakeUp(sfToken1, 22, Fps::fromPeriodNsecs(11));
     surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
     mFrameTimeline->addSurfaceFrame(surfaceFrame1);
     surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented);
@@ -301,7 +300,7 @@
     auto surfaceFrame3 =
             mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne,
                                                        sUidOne, sLayerNameOne, sLayerNameOne);
-    mFrameTimeline->setSfWakeUp(sfToken2, 52, 11);
+    mFrameTimeline->setSfWakeUp(sfToken2, 52, Fps::fromPeriodNsecs(11));
     surfaceFrame3->setPresentState(SurfaceFrame::PresentState::Dropped);
     mFrameTimeline->addSurfaceFrame(surfaceFrame3);
     mFrameTimeline->setSfPresent(56, presentFence2);
@@ -318,11 +317,9 @@
 TEST_F(FrameTimelineTest, displayFramesSlidingWindowMovesAfterLimit) {
     // Insert kMaxDisplayFrames' count of DisplayFrames to fill the deque
     int frameTimeFactor = 0;
-    // Global increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_))
-            .Times(static_cast<int32_t>(*maxDisplayFrames));
     // Layer specific increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_, testing::_, testing::_))
+    EXPECT_CALL(*mTimeStats,
+                incrementJankyFrames(testing::_, testing::_, testing::_, testing::_, testing::_))
             .Times(static_cast<int32_t>(*maxDisplayFrames));
     for (size_t i = 0; i < *maxDisplayFrames; i++) {
         auto presentFence = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
@@ -334,7 +331,7 @@
                 mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId},
                                                            sPidOne, sUidOne, sLayerNameOne,
                                                            sLayerNameOne);
-        mFrameTimeline->setSfWakeUp(sfToken, 22 + frameTimeFactor, 11);
+        mFrameTimeline->setSfWakeUp(sfToken, 22 + frameTimeFactor, Fps::fromPeriodNsecs(11));
         surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented);
         mFrameTimeline->addSurfaceFrame(surfaceFrame);
         mFrameTimeline->setSfPresent(27 + frameTimeFactor, presentFence);
@@ -355,7 +352,7 @@
     auto surfaceFrame =
             mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId}, sPidOne,
                                                        sUidOne, sLayerNameOne, sLayerNameOne);
-    mFrameTimeline->setSfWakeUp(sfToken, 22 + frameTimeFactor, 11);
+    mFrameTimeline->setSfWakeUp(sfToken, 22 + frameTimeFactor, Fps::fromPeriodNsecs(11));
     surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented);
     mFrameTimeline->addSurfaceFrame(surfaceFrame);
     mFrameTimeline->setSfPresent(27 + frameTimeFactor, presentFence);
@@ -386,9 +383,6 @@
 }
 
 TEST_F(FrameTimelineTest, setMaxDisplayFramesSetsSizeProperly) {
-    // Global increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_))
-            .Times(static_cast<int32_t>(*maxDisplayFrames + 10));
     auto presentFence = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     presentFence->signalForTest(2);
 
@@ -398,7 +392,7 @@
                 mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, sUidOne, sLayerNameOne,
                                                            sLayerNameOne);
         int64_t sfToken = mTokenManager->generateTokenForPredictions({22, 26, 30});
-        mFrameTimeline->setSfWakeUp(sfToken, 22, 11);
+        mFrameTimeline->setSfWakeUp(sfToken, 22, Fps::fromPeriodNsecs(11));
         surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented);
         mFrameTimeline->addSurfaceFrame(surfaceFrame);
         mFrameTimeline->setSfPresent(27, presentFence);
@@ -408,16 +402,13 @@
     // Increase the size to 256
     mFrameTimeline->setMaxDisplayFrames(256);
     EXPECT_EQ(*maxDisplayFrames, 256u);
-    // Global increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_))
-            .Times(static_cast<int32_t>(*maxDisplayFrames + 10));
 
     for (size_t i = 0; i < *maxDisplayFrames + 10; i++) {
         auto surfaceFrame =
                 mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, sUidOne, sLayerNameOne,
                                                            sLayerNameOne);
         int64_t sfToken = mTokenManager->generateTokenForPredictions({22, 26, 30});
-        mFrameTimeline->setSfWakeUp(sfToken, 22, 11);
+        mFrameTimeline->setSfWakeUp(sfToken, 22, Fps::fromPeriodNsecs(11));
         surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented);
         mFrameTimeline->addSurfaceFrame(surfaceFrame);
         mFrameTimeline->setSfPresent(27, presentFence);
@@ -427,16 +418,13 @@
     // Shrink the size to 128
     mFrameTimeline->setMaxDisplayFrames(128);
     EXPECT_EQ(*maxDisplayFrames, 128u);
-    // Global increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_))
-            .Times(static_cast<int32_t>(*maxDisplayFrames + 10));
 
     for (size_t i = 0; i < *maxDisplayFrames + 10; i++) {
         auto surfaceFrame =
                 mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, sUidOne, sLayerNameOne,
                                                            sLayerNameOne);
         int64_t sfToken = mTokenManager->generateTokenForPredictions({22, 26, 30});
-        mFrameTimeline->setSfWakeUp(sfToken, 22, 11);
+        mFrameTimeline->setSfWakeUp(sfToken, 22, Fps::fromPeriodNsecs(11));
         surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented);
         mFrameTimeline->addSurfaceFrame(surfaceFrame);
         mFrameTimeline->setSfPresent(27, presentFence);
@@ -447,10 +435,8 @@
 // Tests related to TimeStats
 TEST_F(FrameTimelineTest, presentFenceSignaled_reportsLongSfCpu) {
     EXPECT_CALL(*mTimeStats,
-                incrementJankyFrames(sUidOne, sLayerNameOne,
+                incrementJankyFrames(testing::_, testing::_, sUidOne, sLayerNameOne,
                                      HasBit(JankType::SurfaceFlingerCpuDeadlineMissed)));
-    EXPECT_CALL(*mTimeStats,
-                incrementJankyFrames(HasBit(JankType::SurfaceFlingerCpuDeadlineMissed)));
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions(
             {std::chrono::duration_cast<std::chrono::nanoseconds>(10ms).count(),
@@ -465,7 +451,7 @@
                                                        sUidOne, sLayerNameOne, sLayerNameOne);
     mFrameTimeline->setSfWakeUp(sfToken1,
                                 std::chrono::duration_cast<std::chrono::nanoseconds>(52ms).count(),
-                                11);
+                                Fps::fromPeriodNsecs(11));
     surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
     mFrameTimeline->addSurfaceFrame(surfaceFrame1);
     presentFence1->signalForTest(
@@ -477,8 +463,8 @@
 
 TEST_F(FrameTimelineTest, presentFenceSignaled_reportsDisplayMiss) {
     EXPECT_CALL(*mTimeStats,
-                incrementJankyFrames(sUidOne, sLayerNameOne, HasBit(JankType::DisplayHAL)));
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(HasBit(JankType::DisplayHAL)));
+                incrementJankyFrames(testing::_, testing::_, sUidOne, sLayerNameOne,
+                                     HasBit(JankType::DisplayHAL)));
 
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions(
@@ -494,7 +480,7 @@
                                                        sUidOne, sLayerNameOne, sLayerNameOne);
     mFrameTimeline->setSfWakeUp(sfToken1,
                                 std::chrono::duration_cast<std::chrono::nanoseconds>(52ms).count(),
-                                30);
+                                Fps::fromPeriodNsecs(30));
     surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
     mFrameTimeline->addSurfaceFrame(surfaceFrame1);
     presentFence1->signalForTest(
@@ -506,9 +492,8 @@
 
 TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppMiss) {
     EXPECT_CALL(*mTimeStats,
-                incrementJankyFrames(sUidOne, sLayerNameOne,
+                incrementJankyFrames(testing::_, testing::_, sUidOne, sLayerNameOne,
                                      HasBit(JankType::AppDeadlineMissed)));
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(HasBit(JankType::AppDeadlineMissed)));
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions(
             {std::chrono::duration_cast<std::chrono::nanoseconds>(10ms).count(),
@@ -525,7 +510,7 @@
             std::chrono::duration_cast<std::chrono::nanoseconds>(45ms).count());
     mFrameTimeline->setSfWakeUp(sfToken1,
                                 std::chrono::duration_cast<std::chrono::nanoseconds>(52ms).count(),
-                                11);
+                                Fps::fromPeriodNsecs(11));
 
     surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
     mFrameTimeline->addSurfaceFrame(surfaceFrame1);
@@ -547,8 +532,6 @@
  */
 TEST_F(FrameTimelineTest, tracing_noPacketsSentWithoutTraceStart) {
     auto tracingSession = getTracingSessionForTest();
-    // Global increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_));
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
 
@@ -559,7 +542,7 @@
                                                        sLayerNameOne, sLayerNameOne);
 
     // Set up the display frame
-    mFrameTimeline->setSfWakeUp(token1, 20, 11);
+    mFrameTimeline->setSfWakeUp(token1, 20, Fps::fromPeriodNsecs(11));
     surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Dropped);
     mFrameTimeline->addSurfaceFrame(surfaceFrame1);
     mFrameTimeline->setSfPresent(25, presentFence1);
@@ -567,7 +550,7 @@
 
     // Trigger a flushPresentFence (which will call trace function) by calling setSfPresent for the
     // next frame
-    mFrameTimeline->setSfWakeUp(token2, 50, 11);
+    mFrameTimeline->setSfWakeUp(token2, 50, Fps::fromPeriodNsecs(11));
     mFrameTimeline->setSfPresent(55, presentFence2);
 
     auto packets = readFrameTimelinePacketsBlocking(tracingSession.get());
@@ -576,10 +559,9 @@
 
 TEST_F(FrameTimelineTest, tracing_sanityTest) {
     auto tracingSession = getTracingSessionForTest();
-    // Global increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_));
     // Layer specific increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_, testing::_, testing::_));
+    EXPECT_CALL(*mTimeStats,
+                incrementJankyFrames(testing::_, testing::_, testing::_, testing::_, testing::_));
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
 
@@ -591,7 +573,7 @@
                                                        sLayerNameOne, sLayerNameOne);
 
     // Set up the display frame
-    mFrameTimeline->setSfWakeUp(token2, 20, 11);
+    mFrameTimeline->setSfWakeUp(token2, 20, Fps::fromPeriodNsecs(11));
     surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
     mFrameTimeline->addSurfaceFrame(surfaceFrame1);
     mFrameTimeline->setSfPresent(25, presentFence1);
@@ -599,7 +581,7 @@
 
     // Trigger a flushPresentFence (which will call trace function) by calling setSfPresent for the
     // next frame
-    mFrameTimeline->setSfWakeUp(token2, 50, 11);
+    mFrameTimeline->setSfWakeUp(token2, 50, Fps::fromPeriodNsecs(11));
     mFrameTimeline->setSfPresent(55, presentFence2);
     presentFence2->signalForTest(55);
 
@@ -613,8 +595,6 @@
 
 TEST_F(FrameTimelineTest, traceDisplayFrame_invalidTokenDoesNotEmitTracePacket) {
     auto tracingSession = getTracingSessionForTest();
-    // Global increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_));
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
 
@@ -622,13 +602,13 @@
     int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30});
 
     // Set up the display frame
-    mFrameTimeline->setSfWakeUp(-1, 20, 11);
+    mFrameTimeline->setSfWakeUp(-1, 20, Fps::fromPeriodNsecs(11));
     mFrameTimeline->setSfPresent(25, presentFence1);
     presentFence1->signalForTest(30);
 
     // Trigger a flushPresentFence (which will call trace function) by calling setSfPresent for the
     // next frame
-    mFrameTimeline->setSfWakeUp(token1, 50, 11);
+    mFrameTimeline->setSfWakeUp(token1, 50, Fps::fromPeriodNsecs(11));
     mFrameTimeline->setSfPresent(55, presentFence2);
     presentFence2->signalForTest(60);
 
@@ -641,8 +621,6 @@
 
 TEST_F(FrameTimelineTest, traceSurfaceFrame_invalidTokenDoesNotEmitTracePacket) {
     auto tracingSession = getTracingSessionForTest();
-    // Global increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_));
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
 
@@ -653,7 +631,7 @@
                                                                     sLayerNameOne, sLayerNameOne);
 
     // Set up the display frame
-    mFrameTimeline->setSfWakeUp(token1, 20, 11);
+    mFrameTimeline->setSfWakeUp(token1, 20, Fps::fromPeriodNsecs(11));
     surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Dropped);
     mFrameTimeline->addSurfaceFrame(surfaceFrame1);
     mFrameTimeline->setSfPresent(25, presentFence1);
@@ -661,7 +639,7 @@
 
     // Trigger a flushPresentFence (which will call trace function) by calling setSfPresent for the
     // next frame
-    mFrameTimeline->setSfWakeUp(token2, 50, 11);
+    mFrameTimeline->setSfWakeUp(token2, 50, Fps::fromPeriodNsecs(11));
     mFrameTimeline->setSfPresent(55, presentFence2);
     presentFence2->signalForTest(60);
 
@@ -759,8 +737,6 @@
 
 TEST_F(FrameTimelineTest, traceDisplayFrame_emitsValidTracePacket) {
     auto tracingSession = getTracingSessionForTest();
-    // Global increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_));
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
 
@@ -769,7 +745,7 @@
     int64_t displayFrameToken2 = mTokenManager->generateTokenForPredictions({40, 50, 60});
 
     // Set up the display frame
-    mFrameTimeline->setSfWakeUp(displayFrameToken1, 20, 11);
+    mFrameTimeline->setSfWakeUp(displayFrameToken1, 20, Fps::fromPeriodNsecs(11));
     mFrameTimeline->setSfPresent(26, presentFence1);
     presentFence1->signalForTest(31);
 
@@ -797,7 +773,7 @@
 
     // Trigger a flushPresentFence (which will call trace function) by calling setSfPresent for the
     // next frame
-    mFrameTimeline->setSfWakeUp(displayFrameToken2, 50, 11);
+    mFrameTimeline->setSfWakeUp(displayFrameToken2, 50, Fps::fromPeriodNsecs(11));
     mFrameTimeline->setSfPresent(55, presentFence2);
     presentFence2->signalForTest(55);
 
@@ -854,10 +830,9 @@
 
 TEST_F(FrameTimelineTest, traceSurfaceFrame_emitsValidTracePacket) {
     auto tracingSession = getTracingSessionForTest();
-    // Global increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_));
     // Layer specific increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_, testing::_, testing::_));
+    EXPECT_CALL(*mTimeStats,
+                incrementJankyFrames(testing::_, testing::_, testing::_, testing::_, testing::_));
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
 
@@ -902,7 +877,7 @@
     protoActualSurfaceFrameEnd.set_cookie(traceCookie + 2);
 
     // Set up the display frame
-    mFrameTimeline->setSfWakeUp(displayFrameToken1, 20, 11);
+    mFrameTimeline->setSfWakeUp(displayFrameToken1, 20, Fps::fromPeriodNsecs(11));
     surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
     mFrameTimeline->addSurfaceFrame(surfaceFrame1);
     mFrameTimeline->setSfPresent(26, presentFence1);
@@ -910,7 +885,7 @@
 
     // Trigger a flushPresentFence (which will call trace function) by calling setSfPresent for the
     // next frame
-    mFrameTimeline->setSfWakeUp(displayFrameToken2, 50, 11);
+    mFrameTimeline->setSfWakeUp(displayFrameToken2, 50, Fps::fromPeriodNsecs(11));
     mFrameTimeline->setSfPresent(55, presentFence2);
     presentFence2->signalForTest(55);
 
@@ -967,17 +942,16 @@
 
 // Tests for Jank classification
 TEST_F(FrameTimelineTest, jankClassification_presentOnTimeDoesNotClassify) {
-    // Global increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_));
     // Layer specific increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_, testing::_, testing::_));
+    EXPECT_CALL(*mTimeStats,
+                incrementJankyFrames(testing::_, testing::_, testing::_, testing::_, testing::_));
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     int64_t surfaceFrameToken = mTokenManager->generateTokenForPredictions({10, 20, 30});
     int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 30});
     auto surfaceFrame =
             mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId}, sPidOne,
                                                        sUidOne, sLayerNameOne, sLayerNameOne);
-    mFrameTimeline->setSfWakeUp(sfToken1, 22, 11);
+    mFrameTimeline->setSfWakeUp(sfToken1, 22, Fps::fromPeriodNsecs(11));
     surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented);
     mFrameTimeline->addSurfaceFrame(surfaceFrame);
     mFrameTimeline->setSfPresent(26, presentFence1);
@@ -1001,12 +975,10 @@
 }
 
 TEST_F(FrameTimelineTest, jankClassification_displayFrameOnTimeFinishEarlyPresent) {
-    // Global increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_)).Times(2);
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 40});
     int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 56, 70});
-    mFrameTimeline->setSfWakeUp(sfToken1, 22, 11);
+    mFrameTimeline->setSfWakeUp(sfToken1, 22, Fps::fromPeriodNsecs(11));
     mFrameTimeline->setSfPresent(26, presentFence1);
     auto displayFrame = getDisplayFrame(0);
     presentFence1->signalForTest(30);
@@ -1016,7 +988,7 @@
 
     // Trigger a flush by finalizing the next DisplayFrame
     auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
-    mFrameTimeline->setSfWakeUp(sfToken2, 52, 11);
+    mFrameTimeline->setSfWakeUp(sfToken2, 52, Fps::fromPeriodNsecs(11));
     mFrameTimeline->setSfPresent(56, presentFence2);
     displayFrame = getDisplayFrame(0);
 
@@ -1042,12 +1014,10 @@
 }
 
 TEST_F(FrameTimelineTest, jankClassification_displayFrameOnTimeFinishLatePresent) {
-    // Global increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_)).Times(2);
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 40});
     int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 56, 70});
-    mFrameTimeline->setSfWakeUp(sfToken1, 22, 11);
+    mFrameTimeline->setSfWakeUp(sfToken1, 22, Fps::fromPeriodNsecs(11));
     mFrameTimeline->setSfPresent(26, presentFence1);
     auto displayFrame = getDisplayFrame(0);
     presentFence1->signalForTest(50);
@@ -1057,7 +1027,7 @@
 
     // Trigger a flush by finalizing the next DisplayFrame
     auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
-    mFrameTimeline->setSfWakeUp(sfToken2, 52, 11);
+    mFrameTimeline->setSfWakeUp(sfToken2, 52, Fps::fromPeriodNsecs(11));
     mFrameTimeline->setSfPresent(56, presentFence2);
     displayFrame = getDisplayFrame(0);
 
@@ -1083,11 +1053,9 @@
 }
 
 TEST_F(FrameTimelineTest, jankClassification_displayFrameLateFinishEarlyPresent) {
-    // Global increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_));
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     int64_t sfToken1 = mTokenManager->generateTokenForPredictions({12, 18, 40});
-    mFrameTimeline->setSfWakeUp(sfToken1, 12, 11);
+    mFrameTimeline->setSfWakeUp(sfToken1, 12, Fps::fromPeriodNsecs(11));
 
     mFrameTimeline->setSfPresent(22, presentFence1);
     auto displayFrame = getDisplayFrame(0);
@@ -1107,11 +1075,9 @@
 }
 
 TEST_F(FrameTimelineTest, jankClassification_displayFrameLateFinishLatePresent) {
-    // Global increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_));
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 40});
-    mFrameTimeline->setSfWakeUp(sfToken1, 12, 11);
+    mFrameTimeline->setSfWakeUp(sfToken1, 12, Fps::fromPeriodNsecs(11));
     mFrameTimeline->setSfPresent(36, presentFence1);
     auto displayFrame = getDisplayFrame(0);
     presentFence1->signalForTest(52);
@@ -1130,10 +1096,9 @@
 }
 
 TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishEarlyPresent) {
-    // Global increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_)).Times(2);
-    // Layer specific increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_, testing::_, testing::_)).Times(2);
+    EXPECT_CALL(*mTimeStats,
+                incrementJankyFrames(testing::_, testing::_, testing::_, testing::_, testing::_))
+            .Times(2);
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 40});
     int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 56, 70});
@@ -1143,7 +1108,7 @@
             mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
                                                        sUidOne, sLayerNameOne, sLayerNameOne);
     surfaceFrame1->setAcquireFenceTime(16);
-    mFrameTimeline->setSfWakeUp(sfToken1, 22, 11);
+    mFrameTimeline->setSfWakeUp(sfToken1, 22, Fps::fromPeriodNsecs(11));
     surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
     mFrameTimeline->addSurfaceFrame(surfaceFrame1);
     mFrameTimeline->setSfPresent(26, presentFence1);
@@ -1162,7 +1127,7 @@
             mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne,
                                                        sUidOne, sLayerNameOne, sLayerNameOne);
     surfaceFrame2->setAcquireFenceTime(36);
-    mFrameTimeline->setSfWakeUp(sfToken2, 52, 11);
+    mFrameTimeline->setSfWakeUp(sfToken2, 52, Fps::fromPeriodNsecs(11));
     surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented);
     mFrameTimeline->addSurfaceFrame(surfaceFrame2);
     mFrameTimeline->setSfPresent(56, presentFence2);
@@ -1203,10 +1168,9 @@
 }
 
 TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishLatePresent) {
-    // Global increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_)).Times(2);
-    // Layer specific increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_, testing::_, testing::_)).Times(2);
+    EXPECT_CALL(*mTimeStats,
+                incrementJankyFrames(testing::_, testing::_, testing::_, testing::_, testing::_))
+            .Times(2);
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 40});
     int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 56, 70});
@@ -1216,7 +1180,7 @@
             mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
                                                        sUidOne, sLayerNameOne, sLayerNameOne);
     surfaceFrame1->setAcquireFenceTime(16);
-    mFrameTimeline->setSfWakeUp(sfToken1, 22, 11);
+    mFrameTimeline->setSfWakeUp(sfToken1, 22, Fps::fromPeriodNsecs(11));
     surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
     mFrameTimeline->addSurfaceFrame(surfaceFrame1);
     mFrameTimeline->setSfPresent(26, presentFence1);
@@ -1235,7 +1199,7 @@
             mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne,
                                                        sUidOne, sLayerNameOne, sLayerNameOne);
     surfaceFrame2->setAcquireFenceTime(36);
-    mFrameTimeline->setSfWakeUp(sfToken2, 52, 11);
+    mFrameTimeline->setSfWakeUp(sfToken2, 52, Fps::fromPeriodNsecs(11));
     surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented);
     mFrameTimeline->addSurfaceFrame(surfaceFrame2);
     mFrameTimeline->setSfPresent(56, presentFence2);
@@ -1276,10 +1240,9 @@
 }
 
 TEST_F(FrameTimelineTest, jankClassification_surfaceFrameLateFinishEarlyPresent) {
-    // Global increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_));
-    // Layer specific increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_, testing::_, testing::_));
+    EXPECT_CALL(*mTimeStats,
+                incrementJankyFrames(testing::_, testing::_, testing::_, testing::_, testing::_));
+
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     int64_t sfToken1 = mTokenManager->generateTokenForPredictions({42, 46, 50});
     int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({5, 26, 60});
@@ -1287,7 +1250,7 @@
             mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
                                                        sUidOne, sLayerNameOne, sLayerNameOne);
     surfaceFrame1->setAcquireFenceTime(40);
-    mFrameTimeline->setSfWakeUp(sfToken1, 42, 11);
+    mFrameTimeline->setSfWakeUp(sfToken1, 42, Fps::fromPeriodNsecs(11));
     surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
     mFrameTimeline->addSurfaceFrame(surfaceFrame1);
     mFrameTimeline->setSfPresent(46, presentFence1);
@@ -1320,10 +1283,9 @@
     // AppDeadlineMissed. Second frame - DisplayFrame is janky. This should propagate DisplayFrame's
     // jank to the SurfaceFrame.
 
-    // Global increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_)).Times(2);
-    // Layer specific increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_, testing::_, testing::_)).Times(2);
+    EXPECT_CALL(*mTimeStats,
+                incrementJankyFrames(testing::_, testing::_, testing::_, testing::_, testing::_))
+            .Times(2);
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     int64_t sfToken1 = mTokenManager->generateTokenForPredictions({32, 36, 40});
     int64_t sfToken2 = mTokenManager->generateTokenForPredictions({42, 46, 50});
@@ -1333,7 +1295,7 @@
             mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
                                                        sUidOne, sLayerNameOne, sLayerNameOne);
     surfaceFrame1->setAcquireFenceTime(26);
-    mFrameTimeline->setSfWakeUp(sfToken1, 32, 11);
+    mFrameTimeline->setSfWakeUp(sfToken1, 32, Fps::fromPeriodNsecs(11));
     surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
     mFrameTimeline->addSurfaceFrame(surfaceFrame1);
     mFrameTimeline->setSfPresent(36, presentFence1);
@@ -1352,7 +1314,7 @@
             mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne,
                                                        sUidOne, sLayerNameOne, sLayerNameOne);
     surfaceFrame2->setAcquireFenceTime(40);
-    mFrameTimeline->setSfWakeUp(sfToken2, 43, 11);
+    mFrameTimeline->setSfWakeUp(sfToken2, 43, Fps::fromPeriodNsecs(11));
     surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented);
     mFrameTimeline->addSurfaceFrame(surfaceFrame2);
     mFrameTimeline->setSfPresent(56, presentFence2);
@@ -1393,10 +1355,10 @@
 }
 
 TEST_F(FrameTimelineTest, jankClassification_multiJankBufferStuffingAndAppDeadlineMissed) {
-    // Global increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_)).Times(2);
     // Layer specific increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_, testing::_, testing::_)).Times(2);
+    EXPECT_CALL(*mTimeStats,
+                incrementJankyFrames(testing::_, testing::_, testing::_, testing::_, testing::_))
+            .Times(2);
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 30});
     int64_t surfaceFrameToken2 = mTokenManager->generateTokenForPredictions({40, 50, 60});
@@ -1407,7 +1369,7 @@
             mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
                                                        sUidOne, sLayerNameOne, sLayerNameOne);
     surfaceFrame1->setAcquireFenceTime(50);
-    mFrameTimeline->setSfWakeUp(sfToken1, 52, 30);
+    mFrameTimeline->setSfWakeUp(sfToken1, 52, Fps::fromPeriodNsecs(30));
     surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
     mFrameTimeline->addSurfaceFrame(surfaceFrame1);
     mFrameTimeline->setSfPresent(56, presentFence1);
@@ -1426,7 +1388,7 @@
             mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne,
                                                        sUidOne, sLayerNameOne, sLayerNameOne);
     surfaceFrame2->setAcquireFenceTime(84);
-    mFrameTimeline->setSfWakeUp(sfToken2, 112, 30);
+    mFrameTimeline->setSfWakeUp(sfToken2, 112, Fps::fromPeriodNsecs(30));
     surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented, 54);
     mFrameTimeline->addSurfaceFrame(surfaceFrame2);
     mFrameTimeline->setSfPresent(116, presentFence2);
diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
index df4464e..303b4eb 100644
--- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
@@ -55,14 +55,21 @@
 using PowerMode = hardware::graphics::composer::V2_4::IComposerClient::PowerMode;
 
 // clang-format off
-#define FMT_PROTO          true
-#define FMT_STRING         false
-#define LAYER_ID_0         0
-#define LAYER_ID_1         1
-#define UID_0              123
-#define LAYER_ID_INVALID   -1
-#define NUM_LAYERS         1
-#define NUM_LAYERS_INVALID "INVALID"
+#define FMT_PROTO             true
+#define FMT_STRING            false
+#define LAYER_ID_0            0
+#define LAYER_ID_1            1
+#define UID_0                 123
+#define REFRESH_RATE_0        61
+#define RENDER_RATE_0         31
+#define REFRESH_RATE_BUCKET_0 60
+#define RENDER_RATE_BUCKET_0  30
+#define LAYER_ID_INVALID      -1
+#define NUM_LAYERS            1
+#define NUM_LAYERS_INVALID    "INVALID"
+
+const constexpr Fps kRefreshRate0 = Fps(static_cast<float>(REFRESH_RATE_0));
+const constexpr Fps kRenderRate0 = Fps(static_cast<float>(RENDER_RATE_0));
 
 enum InputCommand : int32_t {
     ENABLE                 = 0,
@@ -246,11 +253,13 @@
             ASSERT_NO_FATAL_FAILURE(mTimeStats->setDesiredTime(id, frameNumber, ts));
             break;
         case TimeStamp::PRESENT:
-            ASSERT_NO_FATAL_FAILURE(mTimeStats->setPresentTime(id, frameNumber, ts));
+            ASSERT_NO_FATAL_FAILURE(
+                    mTimeStats->setPresentTime(id, frameNumber, ts, kRefreshRate0, kRenderRate0));
             break;
         case TimeStamp::PRESENT_FENCE:
-            ASSERT_NO_FATAL_FAILURE(
-                    mTimeStats->setPresentFence(id, frameNumber, std::make_shared<FenceTime>(ts)));
+            ASSERT_NO_FATAL_FAILURE(mTimeStats->setPresentFence(id, frameNumber,
+                                                                std::make_shared<FenceTime>(ts),
+                                                                kRefreshRate0, kRenderRate0));
             break;
         default:
             ALOGD("Invalid timestamp type");
@@ -352,48 +361,29 @@
     EXPECT_THAT(result, HasSubstr(expectedResult));
 }
 
-TEST_F(TimeStatsTest, canIncreaseJankyFrames) {
-    // this stat is not in the proto so verify by checking the string dump
-    EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
-
-    insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
-    mTimeStats->incrementJankyFrames(JankType::SurfaceFlingerCpuDeadlineMissed);
-    mTimeStats->incrementJankyFrames(JankType::SurfaceFlingerGpuDeadlineMissed);
-    mTimeStats->incrementJankyFrames(JankType::DisplayHAL);
-    mTimeStats->incrementJankyFrames(JankType::AppDeadlineMissed);
-    mTimeStats->incrementJankyFrames(JankType::None);
-
-    const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
-    std::string expectedResult = "totalTimelineFrames = " + std::to_string(5);
-    EXPECT_THAT(result, HasSubstr(expectedResult));
-    expectedResult = "jankyFrames = " + std::to_string(4);
-    EXPECT_THAT(result, HasSubstr(expectedResult));
-    expectedResult = "sfLongCpuJankyFrames = " + std::to_string(1);
-    EXPECT_THAT(result, HasSubstr(expectedResult));
-    expectedResult = "sfLongGpuJankyFrames = " + std::to_string(1);
-    EXPECT_THAT(result, HasSubstr(expectedResult));
-    expectedResult = "sfUnattributedJankyFrame = " + std::to_string(1);
-    EXPECT_THAT(result, HasSubstr(expectedResult));
-    expectedResult = "appUnattributedJankyFrame = " + std::to_string(1);
-    EXPECT_THAT(result, HasSubstr(expectedResult));
-}
-
 TEST_F(TimeStatsTest, canIncreaseJankyFramesForLayer) {
     // this stat is not in the proto so verify by checking the string dump
     EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
 
     insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
-    mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
+    mTimeStats->incrementJankyFrames(kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
                                      JankType::SurfaceFlingerCpuDeadlineMissed);
-    mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
+    mTimeStats->incrementJankyFrames(kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
                                      JankType::SurfaceFlingerGpuDeadlineMissed);
-    mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), JankType::DisplayHAL);
-    mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
+    mTimeStats->incrementJankyFrames(kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+                                     JankType::DisplayHAL);
+    mTimeStats->incrementJankyFrames(kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
                                      JankType::AppDeadlineMissed);
-    mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), JankType::None);
+    mTimeStats->incrementJankyFrames(kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+                                     JankType::None);
 
     const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
-    std::string expectedResult = "totalTimelineFrames = " + std::to_string(5);
+    std::string expectedResult =
+            "displayRefreshRate = " + std::to_string(REFRESH_RATE_BUCKET_0) + " fps";
+    EXPECT_THAT(result, HasSubstr(expectedResult));
+    expectedResult = "renderRate = " + std::to_string(RENDER_RATE_BUCKET_0) + " fps";
+    EXPECT_THAT(result, HasSubstr(expectedResult));
+    expectedResult = "totalTimelineFrames = " + std::to_string(5);
     EXPECT_THAT(result, HasSubstr(expectedResult));
     expectedResult = "jankyFrames = " + std::to_string(4);
     EXPECT_THAT(result, HasSubstr(expectedResult));
@@ -848,14 +838,16 @@
     mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(
             std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count()));
 
-    mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
+    mTimeStats->incrementJankyFrames(kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
                                      JankType::SurfaceFlingerCpuDeadlineMissed);
-    mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
+    mTimeStats->incrementJankyFrames(kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
                                      JankType::SurfaceFlingerGpuDeadlineMissed);
-    mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), JankType::DisplayHAL);
-    mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
+    mTimeStats->incrementJankyFrames(kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+                                     JankType::DisplayHAL);
+    mTimeStats->incrementJankyFrames(kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
                                      JankType::AppDeadlineMissed);
-    mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), JankType::None);
+    mTimeStats->incrementJankyFrames(kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+                                     JankType::None);
 
     EXPECT_TRUE(inputCommand(InputCommand::CLEAR, FMT_STRING).empty());
 
@@ -865,11 +857,6 @@
     EXPECT_THAT(result, HasSubstr("compositionStrategyChanges = 0"));
     EXPECT_THAT(result, HasSubstr("averageFrameDuration = 0.000 ms"));
     EXPECT_THAT(result, HasSubstr("averageRenderEngineTiming = 0.000 ms"));
-    EXPECT_THAT(result, HasSubstr("jankyFrames = 0"));
-    EXPECT_THAT(result, HasSubstr("sfLongCpuJankyFrames = 0"));
-    EXPECT_THAT(result, HasSubstr("sfLongGpuJankyFrames = 0"));
-    EXPECT_THAT(result, HasSubstr("sfUnattributedJankyFrame = 0"));
-    EXPECT_THAT(result, HasSubstr("appUnattributedJankyFrame = 0"));
 }
 
 TEST_F(TimeStatsTest, canDumpWithMaxLayers) {
@@ -1000,11 +987,16 @@
     mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(3000000));
     mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(5000000));
 
-    mTimeStats->incrementJankyFrames(JankType::SurfaceFlingerCpuDeadlineMissed);
-    mTimeStats->incrementJankyFrames(JankType::SurfaceFlingerGpuDeadlineMissed);
-    mTimeStats->incrementJankyFrames(JankType::DisplayHAL);
-    mTimeStats->incrementJankyFrames(JankType::AppDeadlineMissed);
-    mTimeStats->incrementJankyFrames(JankType::None);
+    mTimeStats->incrementJankyFrames(kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+                                     JankType::SurfaceFlingerCpuDeadlineMissed);
+    mTimeStats->incrementJankyFrames(kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+                                     JankType::SurfaceFlingerGpuDeadlineMissed);
+    mTimeStats->incrementJankyFrames(kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+                                     JankType::DisplayHAL);
+    mTimeStats->incrementJankyFrames(kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+                                     JankType::AppDeadlineMissed);
+    mTimeStats->incrementJankyFrames(kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+                                     JankType::None);
 
     EXPECT_THAT(mDelegate->mAtomTags,
                 UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
@@ -1047,7 +1039,7 @@
         EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 0));
         EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 0));
         EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 0));
-        EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 0));
+        EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, REFRESH_RATE_BUCKET_0));
         EXPECT_CALL(*mDelegate,
                     statsEventWriteByteArray(mDelegate->mEvent,
                                              BytesEq((const uint8_t*)expectedEmptyHistogram.c_str(),
@@ -1058,7 +1050,7 @@
                                              BytesEq((const uint8_t*)expectedEmptyHistogram.c_str(),
                                                      expectedEmptyHistogram.size()),
                                              expectedEmptyHistogram.size()));
-        EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 0));
+        EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, RENDER_RATE_BUCKET_0));
 
         EXPECT_CALL(*mDelegate, statsEventBuild(mDelegate->mEvent));
     }
@@ -1091,14 +1083,16 @@
     }
     insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
 
-    mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
+    mTimeStats->incrementJankyFrames(kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
                                      JankType::SurfaceFlingerCpuDeadlineMissed);
-    mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
+    mTimeStats->incrementJankyFrames(kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
                                      JankType::SurfaceFlingerGpuDeadlineMissed);
-    mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), JankType::DisplayHAL);
-    mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
+    mTimeStats->incrementJankyFrames(kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+                                     JankType::DisplayHAL);
+    mTimeStats->incrementJankyFrames(kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
                                      JankType::AppDeadlineMissed);
-    mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), JankType::None);
+    mTimeStats->incrementJankyFrames(kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+                                     JankType::None);
 
     EXPECT_THAT(mDelegate->mAtomTags,
                 UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
@@ -1170,8 +1164,8 @@
         EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 0));
         EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 0));
         EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 0));
-        EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 0));
-        EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 0));
+        EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, REFRESH_RATE_BUCKET_0));
+        EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, RENDER_RATE_BUCKET_0));
         EXPECT_CALL(*mDelegate,
                     statsEventWriteByteArray(mDelegate->mEvent,
                                              BytesEq((const uint8_t*)
diff --git a/services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.h b/services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.h
index 0a6a9f4..44b9b73 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.h
@@ -31,7 +31,7 @@
 
     MOCK_METHOD0(onBootFinished, void());
     MOCK_METHOD1(addSurfaceFrame, void(std::shared_ptr<frametimeline::SurfaceFrame>));
-    MOCK_METHOD3(setSfWakeUp, void(int64_t, nsecs_t, nsecs_t));
+    MOCK_METHOD3(setSfWakeUp, void(int64_t, nsecs_t, Fps));
     MOCK_METHOD2(setSfPresent, void(nsecs_t, const std::shared_ptr<FenceTime>&));
 };
 
diff --git a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
index 99ec353..ebea5a0 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
@@ -48,10 +48,12 @@
     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_METHOD3(setPresentTime, void(int32_t, uint64_t, nsecs_t));
-    MOCK_METHOD3(setPresentFence, void(int32_t, uint64_t, const std::shared_ptr<FenceTime>&));
-    MOCK_METHOD1(incrementJankyFrames, void(int32_t));
-    MOCK_METHOD3(incrementJankyFrames, void(uid_t, const std::string&, int32_t));
+    MOCK_METHOD5(setPresentTime, void(int32_t, uint64_t, nsecs_t, Fps, std::optional<Fps>));
+    MOCK_METHOD5(setPresentFence,
+                 void(int32_t, uint64_t, const std::shared_ptr<FenceTime>&, Fps,
+                      std::optional<Fps>));
+    MOCK_METHOD5(incrementJankyFrames,
+                 void(Fps, std::optional<Fps>, uid_t, const std::string&, int32_t));
     MOCK_METHOD1(onDestroy, void(int32_t));
     MOCK_METHOD2(removeTimeRecord, void(int32_t, uint64_t));
     MOCK_METHOD1(setPowerMode,