Expand jank classification

This change expands the jank classification to include new cases like
BufferStuffing and SurfaceFlingerScheduling while also updating the jank
classification logic to be more accurate.

This change also refactors SurfaceFrame by removing the abstraction
class for SurfaceFrame since its now being polled by the layers as well.

Bug: 169890654
Test: libsurfaceflinger_unittest

Change-Id: Ica8ab1d1e4bf2052fffc6247fc5820d96ae8445d
diff --git a/libs/gui/ITransactionCompletedListener.cpp b/libs/gui/ITransactionCompletedListener.cpp
index 2dacae1..1808571 100644
--- a/libs/gui/ITransactionCompletedListener.cpp
+++ b/libs/gui/ITransactionCompletedListener.cpp
@@ -99,15 +99,13 @@
 
 status_t JankData::writeToParcel(Parcel* output) const {
     SAFE_PARCEL(output->writeInt64, frameVsyncId);
-    SAFE_PARCEL(output->writeInt32, static_cast<int32_t>(jankType));
+    SAFE_PARCEL(output->writeInt32, jankType);
     return NO_ERROR;
 }
 
 status_t JankData::readFromParcel(const Parcel* input) {
     SAFE_PARCEL(input->readInt64, &frameVsyncId);
-    int32_t jankTypeInt;
-    SAFE_PARCEL(input->readInt32, &jankTypeInt);
-    jankType = static_cast<JankType>(jankTypeInt);
+    SAFE_PARCEL(input->readInt32, &jankType);
     return NO_ERROR;
 }
 
diff --git a/libs/gui/include/gui/ITransactionCompletedListener.h b/libs/gui/include/gui/ITransactionCompletedListener.h
index 26b3840..cb17cee 100644
--- a/libs/gui/include/gui/ITransactionCompletedListener.h
+++ b/libs/gui/include/gui/ITransactionCompletedListener.h
@@ -69,15 +69,14 @@
     status_t readFromParcel(const Parcel* input) override;
 
     JankData();
-    JankData(int64_t frameVsyncId, JankType jankType)
-          : frameVsyncId(frameVsyncId),
-            jankType(jankType) {}
+    JankData(int64_t frameVsyncId, int32_t jankType)
+          : frameVsyncId(frameVsyncId), jankType(jankType) {}
 
     // Identifier for the frame submitted with Transaction.setFrameTimelineVsyncId
     int64_t frameVsyncId;
 
-    // The type of jank occurred
-    JankType jankType;
+    // Bitmask of janks that occurred
+    int32_t jankType;
 };
 
 class SurfaceStats : public Parcelable {
diff --git a/libs/gui/include/gui/JankInfo.h b/libs/gui/include/gui/JankInfo.h
index 47daf95..fc91714 100644
--- a/libs/gui/include/gui/JankInfo.h
+++ b/libs/gui/include/gui/JankInfo.h
@@ -18,24 +18,31 @@
 
 namespace android {
 
-// Jank information tracked by SurfaceFlinger for the purpose of funneling to telemetry.
+// Jank information tracked by SurfaceFlinger(SF) for perfetto tracing and telemetry.
+// TODO(b/175843808): Change JankType from enum to enum class
 enum JankType {
     // No Jank
     None = 0x0,
-    // Jank not related to SurfaceFlinger or the App
-    Display = 0x1,
+    // Jank that occurs in the layers below SurfaceFlinger
+    DisplayHAL = 0x1,
     // SF took too long on the CPU
-    SurfaceFlingerDeadlineMissed = 0x2,
+    SurfaceFlingerCpuDeadlineMissed = 0x2,
     // SF took too long on the GPU
     SurfaceFlingerGpuDeadlineMissed = 0x4,
     // Either App or GPU took too long on the frame
     AppDeadlineMissed = 0x8,
-    // Predictions live for 120ms, if prediction is expired for a frame, there is definitely a
-    // jank
-    // associated with the App if this is for a SurfaceFrame, and SF for a DisplayFrame.
-    PredictionExpired = 0x10,
-    // Latching a buffer early might cause an early present of the frame
-    SurfaceFlingerEarlyLatch = 0x20,
+    // Vsync predictions have drifted beyond the threshold from the actual HWVsync
+    PredictionError = 0x10,
+    // Janks caused due to the time SF was scheduled to work on the frame
+    // Example: SF woke up too early and latched a buffer resulting in an early present
+    SurfaceFlingerScheduling = 0x20,
+    // A buffer is said to be stuffed if it was expected to be presented on a vsync but was
+    // presented later because the previous buffer was presented in its expected vsync. This
+    // usually happens if there is an unexpectedly long frame causing the rest of the buffers
+    // to enter a stuffed state.
+    BufferStuffing = 0x40,
+    // Jank due to unknown reasons.
+    Unknown = 0x80,
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 325ecfe..56d8742 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -274,8 +274,8 @@
             mConsumer->mergeSurfaceDamage(mQueueItems[0].item.mSurfaceDamage);
             mFlinger->mTimeStats->removeTimeRecord(layerId, mQueueItems[0].item.mFrameNumber);
             if (mQueueItems[0].surfaceFrame) {
-                mFlinger->mFrameTimeline->addSurfaceFrame(std::move(mQueueItems[0].surfaceFrame),
-                                                          PresentState::Dropped);
+                mQueueItems[0].surfaceFrame->setPresentState(PresentState::Dropped);
+                mFlinger->mFrameTimeline->addSurfaceFrame(mQueueItems[0].surfaceFrame);
             }
             mQueueItems.erase(mQueueItems.begin());
             mQueuedFrames--;
@@ -290,8 +290,8 @@
             Mutex::Autolock lock(mQueueItemLock);
             for (auto& [item, surfaceFrame] : mQueueItems) {
                 if (surfaceFrame) {
-                    mFlinger->mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame),
-                                                              PresentState::Dropped);
+                    surfaceFrame->setPresentState(PresentState::Dropped);
+                    mFlinger->mFrameTimeline->addSurfaceFrame(surfaceFrame);
                 }
             }
             mQueueItems.clear();
@@ -321,8 +321,8 @@
             mConsumer->mergeSurfaceDamage(mQueueItems[0].item.mSurfaceDamage);
             mFlinger->mTimeStats->removeTimeRecord(layerId, mQueueItems[0].item.mFrameNumber);
             if (mQueueItems[0].surfaceFrame) {
-                mFlinger->mFrameTimeline->addSurfaceFrame(std::move(mQueueItems[0].surfaceFrame),
-                                                          PresentState::Dropped);
+                mQueueItems[0].surfaceFrame->setPresentState(PresentState::Dropped);
+                mFlinger->mFrameTimeline->addSurfaceFrame(mQueueItems[0].surfaceFrame);
             }
             mQueueItems.erase(mQueueItems.begin());
             mQueuedFrames--;
@@ -336,8 +336,9 @@
         if (mQueueItems[0].surfaceFrame) {
             mQueueItems[0].surfaceFrame->setAcquireFenceTime(
                     mQueueItems[0].item.mFenceTime->getSignalTime());
-            mFlinger->mFrameTimeline->addSurfaceFrame(std::move(mQueueItems[0].surfaceFrame),
-                                                      PresentState::Presented);
+            mQueueItems[0].surfaceFrame->setPresentState(PresentState::Presented, mLastLatchTime);
+            mFlinger->mFrameTimeline->addSurfaceFrame(mQueueItems[0].surfaceFrame);
+            mLastLatchTime = latchTime;
         }
         mQueueItems.erase(mQueueItems.begin());
     }
@@ -436,8 +437,9 @@
         }
 
         auto surfaceFrame =
-                mFlinger->mFrameTimeline->createSurfaceFrameForToken(mOwnerPid, mOwnerUid, mName,
-                                                                     mName, mFrameTimelineVsyncId);
+                mFlinger->mFrameTimeline->createSurfaceFrameForToken(mFrameTimelineVsyncId,
+                                                                     mOwnerPid, mOwnerUid, mName,
+                                                                     mName);
         surfaceFrame->setActualQueueTime(systemTime());
 
         mQueueItems.push_back({item, surfaceFrame});
@@ -475,8 +477,9 @@
         }
 
         auto surfaceFrame =
-                mFlinger->mFrameTimeline->createSurfaceFrameForToken(mOwnerPid, mOwnerUid, mName,
-                                                                     mName, mFrameTimelineVsyncId);
+                mFlinger->mFrameTimeline->createSurfaceFrameForToken(mFrameTimelineVsyncId,
+                                                                     mOwnerPid, mOwnerUid, mName,
+                                                                     mName);
         surfaceFrame->setActualQueueTime(systemTime());
         mQueueItems[mQueueItems.size() - 1].item = item;
         mQueueItems[mQueueItems.size() - 1].surfaceFrame = std::move(surfaceFrame);
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index 5a6b9bc..3551026 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -146,6 +146,11 @@
     // a buffer to correlate the buffer with the vsync id. Can only be accessed
     // with the SF state lock held.
     std::optional<int64_t> mFrameTimelineVsyncId;
+
+    // Keeps track of the time SF latched the last buffer from this layer.
+    // Used in buffer stuffing analysis in FrameTimeline.
+    // TODO(b/176106798): Find a way to do this for BLASTBufferQueue as well.
+    nsecs_t mLastLatchTime = 0;
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
index b09f07a..a8fef04 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
@@ -26,7 +26,7 @@
 #include <cinttypes>
 #include <numeric>
 
-namespace android::frametimeline::impl {
+namespace android::frametimeline {
 
 using base::StringAppendF;
 using FrameTimelineEvent = perfetto::protos::pbzero::FrameTimelineEvent;
@@ -60,7 +60,8 @@
         StringAppendF(&result, "\t%10.2f\t|",
                       std::chrono::duration<double, std::milli>(startTime).count());
     }
-    if (actuals.endTime == 0) {
+    if (actuals.endTime <= 0) {
+        // Animation leashes can send the endTime as -1
         StringAppendF(&result, "\t\tN/A\t|");
     } else {
         std::chrono::nanoseconds endTime(actuals.endTime - baseTime);
@@ -89,124 +90,160 @@
         case PredictionState::Expired:
             return "Expired";
         case PredictionState::None:
-        default:
             return "None";
     }
 }
 
-std::string toString(JankType jankType) {
-    switch (jankType) {
-        case JankType::None:
-            return "None";
-        case JankType::Display:
-            return "Composer/Display - outside SF and App";
-        case JankType::SurfaceFlingerDeadlineMissed:
-            return "SurfaceFlinger Deadline Missed";
-        case JankType::AppDeadlineMissed:
-            return "App Deadline Missed";
-        case JankType::PredictionExpired:
-            return "Prediction Expired";
-        case JankType::SurfaceFlingerEarlyLatch:
-            return "SurfaceFlinger Early Latch";
-        default:
-            return "Unclassified";
-    }
-}
-
-std::string jankMetadataBitmaskToString(int32_t jankMetadata) {
-    std::vector<std::string> jankInfo;
-
-    if (jankMetadata & EarlyStart) {
-        jankInfo.emplace_back("Early Start");
-    } else if (jankMetadata & LateStart) {
-        jankInfo.emplace_back("Late Start");
-    }
-
-    if (jankMetadata & EarlyFinish) {
-        jankInfo.emplace_back("Early Finish");
-    } else if (jankMetadata & LateFinish) {
-        jankInfo.emplace_back("Late Finish");
-    }
-
-    if (jankMetadata & EarlyPresent) {
-        jankInfo.emplace_back("Early Present");
-    } else if (jankMetadata & LatePresent) {
-        jankInfo.emplace_back("Late Present");
-    }
-    // TODO(b/169876734): add GPU composition metadata here
-
-    if (jankInfo.empty()) {
+std::string jankTypeBitmaskToString(int32_t jankType) {
+    // TODO(b/175843808): Make this a switch case if jankType becomes an enum class
+    std::vector<std::string> janks;
+    if (jankType == JankType::None) {
         return "None";
     }
-    return std::accumulate(jankInfo.begin(), jankInfo.end(), std::string(),
+    if (jankType & JankType::DisplayHAL) {
+        janks.emplace_back("Display HAL");
+    }
+    if (jankType & JankType::SurfaceFlingerCpuDeadlineMissed) {
+        janks.emplace_back("SurfaceFlinger CPU Deadline Missed");
+    }
+    if (jankType & JankType::SurfaceFlingerGpuDeadlineMissed) {
+        janks.emplace_back("SurfaceFlinger GPU Deadline Missed");
+    }
+    if (jankType & JankType::AppDeadlineMissed) {
+        janks.emplace_back("App Deadline Missed");
+    }
+    if (jankType & JankType::PredictionError) {
+        janks.emplace_back("Prediction Error");
+    }
+    if (jankType & JankType::SurfaceFlingerScheduling) {
+        janks.emplace_back("SurfaceFlinger Scheduling");
+    }
+    if (jankType & JankType::BufferStuffing) {
+        janks.emplace_back("Buffer Stuffing");
+    }
+    if (jankType & JankType::Unknown) {
+        janks.emplace_back("Unknown jank");
+    }
+    return std::accumulate(janks.begin(), janks.end(), std::string(),
                            [](const std::string& l, const std::string& r) {
                                return l.empty() ? r : l + ", " + r;
                            });
 }
 
-FrameTimelineEvent::PresentType presentTypeToProto(int32_t jankMetadata) {
-    if (jankMetadata & EarlyPresent) {
-        return FrameTimelineEvent::PRESENT_EARLY;
+std::string toString(FramePresentMetadata presentMetadata) {
+    switch (presentMetadata) {
+        case FramePresentMetadata::OnTimePresent:
+            return "On Time Present";
+        case FramePresentMetadata::LatePresent:
+            return "Late Present";
+        case FramePresentMetadata::EarlyPresent:
+            return "Early Present";
+        case FramePresentMetadata::UnknownPresent:
+            return "Unknown Present";
     }
-    if (jankMetadata & LatePresent) {
-        return FrameTimelineEvent::PRESENT_LATE;
-    }
-    return FrameTimelineEvent::PRESENT_ON_TIME;
 }
 
-FrameTimelineEvent::JankType JankTypeToProto(JankType jankType) {
+std::string toString(FrameReadyMetadata finishMetadata) {
+    switch (finishMetadata) {
+        case FrameReadyMetadata::OnTimeFinish:
+            return "On Time Finish";
+        case FrameReadyMetadata::LateFinish:
+            return "Late Finish";
+        case FrameReadyMetadata::UnknownFinish:
+            return "Unknown Finish";
+    }
+}
+
+std::string toString(FrameStartMetadata startMetadata) {
+    switch (startMetadata) {
+        case FrameStartMetadata::OnTimeStart:
+            return "On Time Start";
+        case FrameStartMetadata::LateStart:
+            return "Late Start";
+        case FrameStartMetadata::EarlyStart:
+            return "Early Start";
+        case FrameStartMetadata::UnknownStart:
+            return "Unknown Start";
+    }
+}
+
+std::string toString(SurfaceFrame::PresentState presentState) {
+    using PresentState = SurfaceFrame::PresentState;
+    switch (presentState) {
+        case PresentState::Presented:
+            return "Presented";
+        case PresentState::Dropped:
+            return "Dropped";
+        case PresentState::Unknown:
+            return "Unknown";
+    }
+}
+
+FrameTimelineEvent::PresentType toProto(FramePresentMetadata presentMetadata) {
+    switch (presentMetadata) {
+        case FramePresentMetadata::EarlyPresent:
+            return FrameTimelineEvent::PRESENT_EARLY;
+        case FramePresentMetadata::LatePresent:
+            return FrameTimelineEvent::PRESENT_LATE;
+        case FramePresentMetadata::OnTimePresent:
+            return FrameTimelineEvent::PRESENT_ON_TIME;
+        case FramePresentMetadata::UnknownPresent:
+            return FrameTimelineEvent::PRESENT_UNSPECIFIED;
+    }
+}
+
+FrameTimelineEvent::JankType jankTypeBitmaskToProto(int32_t jankType) {
+    // TODO(b/175843808): Either make the proto a bitmask or jankType an enum class
     switch (jankType) {
         case JankType::None:
             return FrameTimelineEvent::JANK_NONE;
-        case JankType::Display:
+        case JankType::DisplayHAL:
             return FrameTimelineEvent::JANK_DISPLAY_HAL;
-        case JankType::SurfaceFlingerDeadlineMissed:
+        case JankType::SurfaceFlingerCpuDeadlineMissed:
+        case JankType::SurfaceFlingerGpuDeadlineMissed:
             return FrameTimelineEvent::JANK_SF_DEADLINE_MISSED;
         case JankType::AppDeadlineMissed:
-        case JankType::PredictionExpired:
+        case JankType::PredictionError:
             return FrameTimelineEvent::JANK_APP_DEADLINE_MISSED;
+        case JankType::SurfaceFlingerScheduling:
+            return FrameTimelineEvent::JANK_SF_SCHEDULING;
+        case JankType::BufferStuffing:
+            return FrameTimelineEvent::JANK_BUFFER_STUFFING;
         default:
+            // TODO(b/175843808): Remove default if JankType becomes an enum class
             return FrameTimelineEvent::JANK_UNKNOWN;
     }
 }
 
-int64_t TokenManager::generateTokenForPredictions(TimelineItem&& predictions) {
-    ATRACE_CALL();
-    std::lock_guard<std::mutex> lock(mMutex);
-    const int64_t assignedToken = mCurrentToken++;
-    mPredictions[assignedToken] = predictions;
-    mTokens.emplace_back(std::make_pair(assignedToken, systemTime()));
-    flushTokens(systemTime());
-    return assignedToken;
-}
-
-std::optional<TimelineItem> TokenManager::getPredictionsForToken(int64_t token) {
-    std::lock_guard<std::mutex> lock(mMutex);
-    flushTokens(systemTime());
-    auto predictionsIterator = mPredictions.find(token);
-    if (predictionsIterator != mPredictions.end()) {
-        return predictionsIterator->second;
+// Returns the smallest timestamp from the set of predictions and actuals.
+nsecs_t getMinTime(PredictionState predictionState, TimelineItem predictions,
+                   TimelineItem actuals) {
+    nsecs_t minTime = std::numeric_limits<nsecs_t>::max();
+    if (predictionState == PredictionState::Valid) {
+        // Checking start time for predictions is enough because start time is always lesser than
+        // endTime and presentTime.
+        minTime = std::min(minTime, predictions.startTime);
     }
-    return {};
-}
 
-void TokenManager::flushTokens(nsecs_t flushTime) {
-    for (size_t i = 0; i < mTokens.size(); i++) {
-        if (flushTime - mTokens[i].second >= kMaxRetentionTime) {
-            mPredictions.erase(mTokens[i].first);
-            mTokens.erase(mTokens.begin() + static_cast<int>(i));
-            --i;
-        } else {
-            // Tokens are ordered by time. If i'th token is within the retention time, then the
-            // i+1'th token will also be within retention time.
-            break;
-        }
+    // Need to check startTime, endTime and presentTime for actuals because some frames might not
+    // have them set.
+    if (actuals.startTime != 0) {
+        minTime = std::min(minTime, actuals.startTime);
     }
+    if (actuals.endTime != 0) {
+        minTime = std::min(minTime, actuals.endTime);
+    }
+    if (actuals.presentTime != 0) {
+        minTime = std::min(minTime, actuals.endTime);
+    }
+    return minTime;
 }
 
 SurfaceFrame::SurfaceFrame(int64_t token, pid_t ownerPid, uid_t ownerUid, std::string layerName,
                            std::string debugName, PredictionState predictionState,
-                           frametimeline::TimelineItem&& predictions)
+                           frametimeline::TimelineItem&& predictions,
+                           std::shared_ptr<TimeStats> timeStats,
+                           JankClassificationThresholds thresholds)
       : mToken(token),
         mOwnerPid(ownerPid),
         mOwnerUid(ownerUid),
@@ -216,29 +253,8 @@
         mPredictionState(predictionState),
         mPredictions(predictions),
         mActuals({0, 0, 0}),
-        mActualQueueTime(0),
-        mJankType(JankType::None),
-        mJankMetadata(0) {}
-
-void SurfaceFrame::setPresentState(PresentState state) {
-    std::lock_guard<std::mutex> lock(mMutex);
-    mPresentState = state;
-}
-
-SurfaceFrame::PresentState SurfaceFrame::getPresentState() const {
-    std::lock_guard<std::mutex> lock(mMutex);
-    return mPresentState;
-}
-
-TimelineItem SurfaceFrame::getActuals() const {
-    std::lock_guard<std::mutex> lock(mMutex);
-    return mActuals;
-}
-
-nsecs_t SurfaceFrame::getActualQueueTime() const {
-    std::lock_guard<std::mutex> lock(mMutex);
-    return mActualQueueTime;
-}
+        mTimeStats(timeStats),
+        mJankClassificationThresholds(thresholds) {}
 
 void SurfaceFrame::setActualStartTime(nsecs_t actualStartTime) {
     std::lock_guard<std::mutex> lock(mMutex);
@@ -254,18 +270,13 @@
     mActuals.endTime = std::max(acquireFenceTime, mActualQueueTime);
 }
 
-void SurfaceFrame::setActualPresentTime(nsecs_t presentTime) {
+void SurfaceFrame::setPresentState(PresentState presentState, nsecs_t lastLatchTime) {
     std::lock_guard<std::mutex> lock(mMutex);
-    mActuals.presentTime = presentTime;
+    mPresentState = presentState;
+    mLastLatchTime = lastLatchTime;
 }
 
-void SurfaceFrame::setJankInfo(JankType jankType, int32_t jankMetadata) {
-    std::lock_guard<std::mutex> lock(mMutex);
-    mJankType = jankType;
-    mJankMetadata = jankMetadata;
-}
-
-std::optional<JankType> SurfaceFrame::getJankType() const {
+std::optional<int32_t> SurfaceFrame::getJankType() const {
     std::lock_guard<std::mutex> lock(mMutex);
     if (mActuals.presentTime == 0) {
         return std::nullopt;
@@ -275,31 +286,30 @@
 
 nsecs_t SurfaceFrame::getBaseTime() const {
     std::lock_guard<std::mutex> lock(mMutex);
-    nsecs_t baseTime = std::numeric_limits<nsecs_t>::max();
-    if (mPredictionState == PredictionState::Valid) {
-        baseTime = std::min(baseTime, mPredictions.startTime);
-    }
-    if (mActuals.startTime != 0) {
-        baseTime = std::min(baseTime, mActuals.startTime);
-    }
-    baseTime = std::min(baseTime, mActuals.endTime);
-    return baseTime;
+    return getMinTime(mPredictionState, mPredictions, mActuals);
 }
 
-std::string presentStateToString(SurfaceFrame::PresentState presentState) {
-    using PresentState = SurfaceFrame::PresentState;
-    switch (presentState) {
-        case PresentState::Presented:
-            return "Presented";
-        case PresentState::Dropped:
-            return "Dropped";
-        case PresentState::Unknown:
-        default:
-            return "Unknown";
-    }
+TimelineItem SurfaceFrame::getActuals() const {
+    std::lock_guard<std::mutex> lock(mMutex);
+    return mActuals;
 }
 
-void SurfaceFrame::dump(std::string& result, const std::string& indent, nsecs_t baseTime) {
+SurfaceFrame::PresentState SurfaceFrame::getPresentState() const {
+    std::lock_guard<std::mutex> lock(mMutex);
+    return mPresentState;
+}
+
+FramePresentMetadata SurfaceFrame::getFramePresentMetadata() const {
+    std::lock_guard<std::mutex> lock(mMutex);
+    return mFramePresentMetadata;
+}
+
+FrameReadyMetadata SurfaceFrame::getFrameReadyMetadata() const {
+    std::lock_guard<std::mutex> lock(mMutex);
+    return mFrameReadyMetadata;
+}
+
+void SurfaceFrame::dump(std::string& result, const std::string& indent, nsecs_t baseTime) const {
     std::lock_guard<std::mutex> lock(mMutex);
     StringAppendF(&result, "%s", indent.c_str());
     StringAppendF(&result, "Layer - %s", mDebugName.c_str());
@@ -309,21 +319,130 @@
     }
     StringAppendF(&result, "\n");
     StringAppendF(&result, "%s", indent.c_str());
+    StringAppendF(&result, "Token: %" PRId64 "\n", mToken);
+    StringAppendF(&result, "%s", indent.c_str());
     StringAppendF(&result, "Owner Pid : %d\n", mOwnerPid);
     StringAppendF(&result, "%s", indent.c_str());
-    StringAppendF(&result, "Present State : %s\n", presentStateToString(mPresentState).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());
     StringAppendF(&result, "%s", indent.c_str());
-    StringAppendF(&result, "Jank Type : %s\n", toString(mJankType).c_str());
+    StringAppendF(&result, "Jank Type : %s\n", jankTypeBitmaskToString(mJankType).c_str());
     StringAppendF(&result, "%s", indent.c_str());
-    StringAppendF(&result, "Jank Metadata: %s\n",
-                  jankMetadataBitmaskToString(mJankMetadata).c_str());
+    StringAppendF(&result, "Present Metadata : %s\n", toString(mFramePresentMetadata).c_str());
+    StringAppendF(&result, "%s", indent.c_str());
+    StringAppendF(&result, "Finish Metadata: %s\n", toString(mFrameReadyMetadata).c_str());
+    std::chrono::nanoseconds latchTime(
+            std::max(static_cast<int64_t>(0), mLastLatchTime - baseTime));
+    StringAppendF(&result, "%s", indent.c_str());
+    StringAppendF(&result, "Last latch time: %10f\n",
+                  std::chrono::duration<double, std::milli>(latchTime).count());
+    if (mPredictionState == PredictionState::Valid) {
+        nsecs_t presentDelta = mActuals.presentTime - mPredictions.presentTime;
+        std::chrono::nanoseconds presentDeltaNs(std::abs(presentDelta));
+        StringAppendF(&result, "%s", indent.c_str());
+        StringAppendF(&result, "Present delta: %10f\n",
+                      std::chrono::duration<double, std::milli>(presentDeltaNs).count());
+    }
     dumpTable(result, mPredictions, mActuals, indent, mPredictionState, baseTime);
 }
 
-void SurfaceFrame::traceSurfaceFrame(int64_t displayFrameToken) {
-    using FrameTimelineDataSource = FrameTimeline::FrameTimelineDataSource;
+void SurfaceFrame::onPresent(nsecs_t presentTime, int32_t displayFrameJankType,
+                             nsecs_t vsyncPeriod) {
+    std::lock_guard<std::mutex> lock(mMutex);
+    if (mPresentState != PresentState::Presented) {
+        // No need to update dropped buffers
+        return;
+    }
+
+    mActuals.presentTime = presentTime;
+    // Jank Analysis for SurfaceFrame
+    if (mPredictionState == PredictionState::None) {
+        // Cannot do jank classification on frames that don't have a token.
+        return;
+    }
+    if (mPredictionState == PredictionState::Expired) {
+        // We do not know what happened here to classify this correctly. This could
+        // potentially be AppDeadlineMissed but that's assuming no app will request frames
+        // 120ms apart.
+        mJankType = JankType::Unknown;
+        mFramePresentMetadata = FramePresentMetadata::UnknownPresent;
+        mFrameReadyMetadata = FrameReadyMetadata::UnknownFinish;
+        mTimeStats->incrementJankyFrames(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;
+
+    if (deadlineDelta > mJankClassificationThresholds.deadlineThreshold) {
+        mFrameReadyMetadata = FrameReadyMetadata::LateFinish;
+    } else {
+        mFrameReadyMetadata = FrameReadyMetadata::OnTimeFinish;
+    }
+
+    if (std::abs(presentDelta) > mJankClassificationThresholds.presentThreshold) {
+        mFramePresentMetadata = presentDelta > 0 ? FramePresentMetadata::LatePresent
+                                                 : FramePresentMetadata::EarlyPresent;
+    } else {
+        mFramePresentMetadata = FramePresentMetadata::OnTimePresent;
+    }
+
+    if (mFramePresentMetadata == FramePresentMetadata::OnTimePresent) {
+        // Frames presented on time are not janky.
+        mJankType = JankType::None;
+    } else if (mFramePresentMetadata == FramePresentMetadata::EarlyPresent) {
+        if (mFrameReadyMetadata == FrameReadyMetadata::OnTimeFinish) {
+            // Finish on time, Present early
+            if (deltaToVsync < mJankClassificationThresholds.presentThreshold ||
+                deltaToVsync >= vsyncPeriod - mJankClassificationThresholds.presentThreshold) {
+                // Delta factor of vsync
+                mJankType = JankType::SurfaceFlingerScheduling;
+            } else {
+                // Delta not a factor of vsync
+                mJankType = JankType::PredictionError;
+            }
+        } else if (mFrameReadyMetadata == FrameReadyMetadata::LateFinish) {
+            // Finish late, Present early
+            mJankType = JankType::Unknown;
+        }
+    } else {
+        if (mLastLatchTime != 0 && mPredictions.endTime <= mLastLatchTime) {
+            // Buffer Stuffing.
+            mJankType |= JankType::BufferStuffing;
+        }
+        if (mFrameReadyMetadata == FrameReadyMetadata::OnTimeFinish) {
+            // Finish on time, Present late
+            if (displayFrameJankType != JankType::None) {
+                // Propagate displayFrame's jank if it exists
+                mJankType |= displayFrameJankType;
+            } else {
+                if (deltaToVsync < mJankClassificationThresholds.presentThreshold ||
+                    deltaToVsync >= vsyncPeriod - mJankClassificationThresholds.presentThreshold) {
+                    // Delta factor of vsync
+                    mJankType |= JankType::SurfaceFlingerScheduling;
+                } else {
+                    // Delta not a factor of vsync
+                    mJankType |= JankType::PredictionError;
+                }
+            }
+        } else if (mFrameReadyMetadata == FrameReadyMetadata::LateFinish) {
+            // Finish late, Present late
+            if (displayFrameJankType == JankType::None) {
+                // Display frame is not janky, so purely app's fault
+                mJankType |= JankType::AppDeadlineMissed;
+            } else {
+                // Propagate DisplayFrame's jankType if it is janky
+                mJankType |= displayFrameJankType;
+            }
+        }
+    }
+    mTimeStats->incrementJankyFrames(mOwnerUid, mLayerName, mJankType);
+}
+
+void SurfaceFrame::trace(int64_t displayFrameToken) {
+    using FrameTimelineDataSource = impl::FrameTimeline::FrameTimelineDataSource;
     FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
         std::lock_guard<std::mutex> lock(mMutex);
         if (mToken == ISurfaceComposer::INVALID_VSYNC_ID) {
@@ -349,11 +468,12 @@
         } else if (mPresentState == PresentState::Unknown) {
             surfaceFrameEvent->set_present_type(FrameTimelineEvent::PRESENT_UNSPECIFIED);
         } else {
-            surfaceFrameEvent->set_present_type(presentTypeToProto(mJankMetadata));
+            surfaceFrameEvent->set_present_type(toProto(mFramePresentMetadata));
         }
-        surfaceFrameEvent->set_on_time_finish(!(mJankMetadata & LateFinish));
-        surfaceFrameEvent->set_gpu_composition(mJankMetadata & GpuComposition);
-        surfaceFrameEvent->set_jank_type(JankTypeToProto(mJankType));
+        surfaceFrameEvent->set_on_time_finish(mFrameReadyMetadata ==
+                                              FrameReadyMetadata::OnTimeFinish);
+        surfaceFrameEvent->set_gpu_composition(mGpuComposition);
+        surfaceFrameEvent->set_jank_type(jankTypeBitmaskToProto(mJankType));
 
         surfaceFrameEvent->set_expected_start_ns(mPredictions.startTime);
         surfaceFrameEvent->set_expected_end_ns(mPredictions.endTime);
@@ -366,10 +486,45 @@
     });
 }
 
-FrameTimeline::FrameTimeline(std::shared_ptr<TimeStats> timeStats)
-      : mCurrentDisplayFrame(std::make_shared<DisplayFrame>()),
+namespace impl {
+
+int64_t TokenManager::generateTokenForPredictions(TimelineItem&& predictions) {
+    ATRACE_CALL();
+    std::lock_guard<std::mutex> lock(mMutex);
+    const int64_t assignedToken = mCurrentToken++;
+    mPredictions[assignedToken] = {systemTime(), predictions};
+    flushTokens(systemTime());
+    return assignedToken;
+}
+
+std::optional<TimelineItem> TokenManager::getPredictionsForToken(int64_t token) const {
+    std::lock_guard<std::mutex> lock(mMutex);
+    auto predictionsIterator = mPredictions.find(token);
+    if (predictionsIterator != mPredictions.end()) {
+        return predictionsIterator->second.predictions;
+    }
+    return {};
+}
+
+void TokenManager::flushTokens(nsecs_t flushTime) {
+    for (auto it = mPredictions.begin(); it != mPredictions.end();) {
+        if (flushTime - it->second.timestamp >= kMaxRetentionTime) {
+            it = mPredictions.erase(it);
+        } else {
+            // Tokens are ordered by time. If i'th token is within the retention time, then the
+            // i+1'th token will also be within retention time.
+            break;
+        }
+    }
+}
+
+FrameTimeline::FrameTimeline(std::shared_ptr<TimeStats> timeStats, pid_t surfaceFlingerPid,
+                             JankClassificationThresholds thresholds)
+      : mCurrentDisplayFrame(std::make_shared<DisplayFrame>(timeStats, thresholds)),
         mMaxDisplayFrames(kDefaultMaxDisplayFrames),
-        mTimeStats(std::move(timeStats)) {}
+        mTimeStats(std::move(timeStats)),
+        mSurfaceFlingerPid(surfaceFlingerPid),
+        mJankClassificationThresholds(thresholds) {}
 
 void FrameTimeline::onBootFinished() {
     perfetto::TracingInitArgs args;
@@ -384,67 +539,225 @@
     FrameTimelineDataSource::Register(dsd);
 }
 
-FrameTimeline::DisplayFrame::DisplayFrame()
-      : surfaceFlingerPredictions(TimelineItem()), surfaceFlingerActuals(TimelineItem()) {
-    this->surfaceFrames.reserve(kNumSurfaceFramesInitial);
-}
-
-std::shared_ptr<android::frametimeline::SurfaceFrame> FrameTimeline::createSurfaceFrameForToken(
-        pid_t ownerPid, uid_t ownerUid, std::string layerName, std::string debugName,
-        std::optional<int64_t> token) {
+std::shared_ptr<SurfaceFrame> FrameTimeline::createSurfaceFrameForToken(
+        std::optional<int64_t> token, pid_t ownerPid, uid_t ownerUid, std::string layerName,
+        std::string debugName) {
     ATRACE_CALL();
     if (!token) {
-        return std::make_shared<impl::SurfaceFrame>(ISurfaceComposer::INVALID_VSYNC_ID,ownerPid,
-                                                    ownerUid, std::move(layerName),
-                                                    std::move(debugName), PredictionState::None,
-                                                    TimelineItem());
+        return std::make_shared<SurfaceFrame>(ISurfaceComposer::INVALID_VSYNC_ID, ownerPid,
+                                              ownerUid, std::move(layerName), std::move(debugName),
+                                              PredictionState::None, TimelineItem(), mTimeStats,
+                                              mJankClassificationThresholds);
     }
     std::optional<TimelineItem> predictions = mTokenManager.getPredictionsForToken(*token);
     if (predictions) {
-        return std::make_shared<impl::SurfaceFrame>(*token, ownerPid, ownerUid,
-                                                    std::move(layerName), std::move(debugName),
-                                                    PredictionState::Valid,
-                                                    std::move(*predictions));
+        return std::make_shared<SurfaceFrame>(*token, ownerPid, ownerUid, std::move(layerName),
+                                              std::move(debugName), PredictionState::Valid,
+                                              std::move(*predictions), mTimeStats,
+                                              mJankClassificationThresholds);
     }
-    return std::make_shared<impl::SurfaceFrame>(*token, ownerPid, ownerUid, std::move(layerName),
-                                                std::move(debugName), PredictionState::Expired,
-                                                TimelineItem());
+    return std::make_shared<SurfaceFrame>(*token, ownerPid, ownerUid, std::move(layerName),
+                                          std::move(debugName), PredictionState::Expired,
+                                          TimelineItem(), mTimeStats,
+                                          mJankClassificationThresholds);
 }
 
-void FrameTimeline::addSurfaceFrame(
-        std::shared_ptr<android::frametimeline::SurfaceFrame> surfaceFrame,
-        SurfaceFrame::PresentState state) {
-    ATRACE_CALL();
-    surfaceFrame->setPresentState(state);
-    std::lock_guard<std::mutex> lock(mMutex);
-    mCurrentDisplayFrame->surfaceFrames.push_back(
-            std::static_pointer_cast<impl::SurfaceFrame>(surfaceFrame));
+FrameTimeline::DisplayFrame::DisplayFrame(std::shared_ptr<TimeStats> timeStats,
+                                          JankClassificationThresholds thresholds)
+      : mSurfaceFlingerPredictions(TimelineItem()),
+        mSurfaceFlingerActuals(TimelineItem()),
+        mTimeStats(timeStats),
+        mJankClassificationThresholds(thresholds) {
+    mSurfaceFrames.reserve(kNumSurfaceFramesInitial);
 }
 
-void FrameTimeline::setSfWakeUp(int64_t token, nsecs_t wakeUpTime) {
+void FrameTimeline::addSurfaceFrame(std::shared_ptr<SurfaceFrame> surfaceFrame) {
     ATRACE_CALL();
-    const std::optional<TimelineItem> prediction = mTokenManager.getPredictionsForToken(token);
     std::lock_guard<std::mutex> lock(mMutex);
-    mCurrentDisplayFrame->token = token;
-    if (!prediction) {
-        mCurrentDisplayFrame->predictionState = PredictionState::Expired;
-    } else {
-        mCurrentDisplayFrame->surfaceFlingerPredictions = *prediction;
-        mCurrentDisplayFrame->predictionState = PredictionState::Valid;
-    }
-    mCurrentDisplayFrame->surfaceFlingerActuals.startTime = wakeUpTime;
+    mCurrentDisplayFrame->addSurfaceFrame(surfaceFrame);
+}
+
+void FrameTimeline::setSfWakeUp(int64_t token, nsecs_t wakeUpTime, nsecs_t vsyncPeriod) {
+    ATRACE_CALL();
+    std::lock_guard<std::mutex> lock(mMutex);
+    mCurrentDisplayFrame->onSfWakeUp(token, vsyncPeriod,
+                                     mTokenManager.getPredictionsForToken(token), wakeUpTime);
 }
 
 void FrameTimeline::setSfPresent(nsecs_t sfPresentTime,
                                  const std::shared_ptr<FenceTime>& presentFence) {
     ATRACE_CALL();
     std::lock_guard<std::mutex> lock(mMutex);
-    mCurrentDisplayFrame->surfaceFlingerActuals.endTime = sfPresentTime;
+    mCurrentDisplayFrame->setActualEndTime(sfPresentTime);
     mPendingPresentFences.emplace_back(std::make_pair(presentFence, mCurrentDisplayFrame));
     flushPendingPresentFences();
     finalizeCurrentDisplayFrame();
 }
 
+void FrameTimeline::DisplayFrame::addSurfaceFrame(std::shared_ptr<SurfaceFrame> surfaceFrame) {
+    mSurfaceFrames.push_back(surfaceFrame);
+}
+
+void FrameTimeline::DisplayFrame::onSfWakeUp(int64_t token, nsecs_t vsyncPeriod,
+                                             std::optional<TimelineItem> predictions,
+                                             nsecs_t wakeUpTime) {
+    mToken = token;
+    mVsyncPeriod = vsyncPeriod;
+    if (!predictions) {
+        mPredictionState = PredictionState::Expired;
+    } else {
+        mPredictionState = PredictionState::Valid;
+        mSurfaceFlingerPredictions = *predictions;
+    }
+    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;
+    mSurfaceFlingerPredictions = predictions;
+}
+
+void FrameTimeline::DisplayFrame::setActualStartTime(nsecs_t actualStartTime) {
+    mSurfaceFlingerActuals.startTime = actualStartTime;
+}
+
+void FrameTimeline::DisplayFrame::setActualEndTime(nsecs_t actualEndTime) {
+    mSurfaceFlingerActuals.endTime = actualEndTime;
+}
+
+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;
+    if (std::abs(presentDelta) > mJankClassificationThresholds.presentThreshold) {
+        mFramePresentMetadata = presentDelta > 0 ? FramePresentMetadata::LatePresent
+                                                 : FramePresentMetadata::EarlyPresent;
+    } else {
+        mFramePresentMetadata = FramePresentMetadata::OnTimePresent;
+    }
+
+    if (mSurfaceFlingerActuals.endTime - mSurfaceFlingerPredictions.endTime >
+        mJankClassificationThresholds.deadlineThreshold) {
+        mFrameReadyMetadata = FrameReadyMetadata::LateFinish;
+    } else {
+        mFrameReadyMetadata = FrameReadyMetadata::OnTimeFinish;
+    }
+
+    if (std::abs(mSurfaceFlingerActuals.startTime - mSurfaceFlingerPredictions.startTime) >
+        mJankClassificationThresholds.startThreshold) {
+        mFrameStartMetadata =
+                mSurfaceFlingerActuals.startTime > mSurfaceFlingerPredictions.startTime
+                ? FrameStartMetadata::LateStart
+                : FrameStartMetadata::EarlyStart;
+    }
+
+    if (mFramePresentMetadata != FramePresentMetadata::OnTimePresent) {
+        // Do jank classification only if present is not on time
+        if (mFramePresentMetadata == FramePresentMetadata::EarlyPresent) {
+            if (mFrameReadyMetadata == FrameReadyMetadata::OnTimeFinish) {
+                // Finish on time, Present early
+                if (deltaToVsync < mJankClassificationThresholds.presentThreshold ||
+                    deltaToVsync >=
+                            (mVsyncPeriod - 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.
+                    mJankType = JankType::SurfaceFlingerScheduling;
+                } else {
+                    // Delta is not a factor of vsync,
+                    mJankType = JankType::PredictionError;
+                }
+            } else if (mFrameReadyMetadata == FrameReadyMetadata::LateFinish) {
+                // Finish late, Present early
+                mJankType = JankType::SurfaceFlingerScheduling;
+            } else {
+                // Finish time unknown
+                mJankType = JankType::Unknown;
+            }
+        } else if (mFramePresentMetadata == FramePresentMetadata::LatePresent) {
+            if (mFrameReadyMetadata == FrameReadyMetadata::OnTimeFinish) {
+                // Finish on time, Present late
+                if (deltaToVsync < mJankClassificationThresholds.presentThreshold ||
+                    deltaToVsync >=
+                            (mVsyncPeriod - 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.
+                    mJankType = JankType::DisplayHAL;
+                } else {
+                    // Delta is not a factor of vsync
+                    mJankType = JankType::PredictionError;
+                }
+            } else if (mFrameReadyMetadata == FrameReadyMetadata::LateFinish) {
+                // Finish late, Present late
+                mJankType = JankType::SurfaceFlingerCpuDeadlineMissed;
+            } else {
+                // Finish time unknown
+                mJankType = JankType::Unknown;
+            }
+        } else {
+            // Present unknown
+            mJankType = JankType::Unknown;
+        }
+    }
+    totalJankReasons |= mJankType;
+
+    for (auto& surfaceFrame : mSurfaceFrames) {
+        surfaceFrame->onPresent(signalTime, mJankType, mVsyncPeriod);
+        auto surfaceFrameJankType = surfaceFrame->getJankType();
+        if (surfaceFrameJankType != std::nullopt) {
+            totalJankReasons |= *surfaceFrameJankType;
+        }
+    }
+    mTimeStats->incrementJankyFrames(totalJankReasons);
+}
+
+void FrameTimeline::DisplayFrame::trace(pid_t surfaceFlingerPid) const {
+    FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
+        if (mToken == ISurfaceComposer::INVALID_VSYNC_ID) {
+            ALOGD("Cannot trace DisplayFrame with invalid token");
+            return;
+        }
+        auto packet = ctx.NewTracePacket();
+        packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC);
+        packet->set_timestamp(static_cast<uint64_t>(systemTime()));
+
+        auto* event = packet->set_frame_timeline_event();
+        auto* displayFrameEvent = event->set_display_frame();
+
+        displayFrameEvent->set_token(mToken);
+        displayFrameEvent->set_present_type(toProto(mFramePresentMetadata));
+        displayFrameEvent->set_on_time_finish(mFrameReadyMetadata ==
+                                              FrameReadyMetadata::OnTimeFinish);
+        displayFrameEvent->set_gpu_composition(mGpuComposition);
+        displayFrameEvent->set_jank_type(jankTypeBitmaskToProto(mJankType));
+
+        displayFrameEvent->set_expected_start_ns(mSurfaceFlingerPredictions.startTime);
+        displayFrameEvent->set_expected_end_ns(mSurfaceFlingerPredictions.endTime);
+
+        displayFrameEvent->set_actual_start_ns(mSurfaceFlingerActuals.startTime);
+        displayFrameEvent->set_actual_end_ns(mSurfaceFlingerActuals.endTime);
+
+        displayFrameEvent->set_pid(surfaceFlingerPid);
+    });
+
+    for (auto& surfaceFrame : mSurfaceFrames) {
+        surfaceFrame->trace(mToken);
+    }
+}
+
 void FrameTimeline::flushPendingPresentFences() {
     for (size_t i = 0; i < mPendingPresentFences.size(); i++) {
         const auto& pendingPresentFence = mPendingPresentFences[i];
@@ -456,93 +769,9 @@
             }
         }
         if (signalTime != Fence::SIGNAL_TIME_INVALID) {
-            int32_t totalJankReasons = JankType::None;
             auto& displayFrame = pendingPresentFence.second;
-            displayFrame->surfaceFlingerActuals.presentTime = signalTime;
-
-            // Jank Analysis for DisplayFrame
-            const auto& sfActuals = displayFrame->surfaceFlingerActuals;
-            const auto& sfPredictions = displayFrame->surfaceFlingerPredictions;
-            if (std::abs(sfActuals.presentTime - sfPredictions.presentTime) > kPresentThreshold) {
-                displayFrame->jankMetadata |= sfActuals.presentTime > sfPredictions.presentTime
-                        ? LatePresent
-                        : EarlyPresent;
-            }
-            if (std::abs(sfActuals.endTime - sfPredictions.endTime) > kDeadlineThreshold) {
-                if (sfActuals.endTime > sfPredictions.endTime) {
-                    displayFrame->jankMetadata |= LateFinish;
-                } else {
-                    displayFrame->jankMetadata |= EarlyFinish;
-                }
-
-                if ((displayFrame->jankMetadata & EarlyFinish) &&
-                    (displayFrame->jankMetadata & EarlyPresent)) {
-                    displayFrame->jankType = JankType::SurfaceFlingerEarlyLatch;
-                } else if ((displayFrame->jankMetadata & LateFinish) &&
-                           (displayFrame->jankMetadata & LatePresent)) {
-                    displayFrame->jankType = JankType::SurfaceFlingerDeadlineMissed;
-                } else if (displayFrame->jankMetadata & EarlyPresent ||
-                           displayFrame->jankMetadata & LatePresent) {
-                    // Cases where SF finished early but frame was presented late and vice versa
-                    displayFrame->jankType = JankType::Display;
-                }
-            }
-
-            if (std::abs(sfActuals.startTime - sfPredictions.startTime) > kSFStartThreshold) {
-                displayFrame->jankMetadata |=
-                        sfActuals.startTime > sfPredictions.startTime ? LateStart : EarlyStart;
-            }
-
-            totalJankReasons |= displayFrame->jankType;
-            traceDisplayFrame(*displayFrame);
-
-            for (auto& surfaceFrame : displayFrame->surfaceFrames) {
-                if (surfaceFrame->getPresentState() == SurfaceFrame::PresentState::Presented) {
-                    // Only presented SurfaceFrames need to be updated
-                    surfaceFrame->setActualPresentTime(signalTime);
-
-                    // Jank Analysis for SurfaceFrame
-                    const auto& predictionState = surfaceFrame->getPredictionState();
-                    if (predictionState == PredictionState::Expired) {
-                        // Jank analysis cannot be done on apps that don't use predictions
-                        surfaceFrame->setJankInfo(JankType::PredictionExpired, 0);
-                    } else if (predictionState == PredictionState::Valid) {
-                        const auto& actuals = surfaceFrame->getActuals();
-                        const auto& predictions = surfaceFrame->getPredictions();
-                        int32_t jankMetadata = 0;
-                        JankType jankType = JankType::None;
-                        if (std::abs(actuals.endTime - predictions.endTime) > kDeadlineThreshold) {
-                            jankMetadata |= actuals.endTime > predictions.endTime ? LateFinish
-                                                                                  : EarlyFinish;
-                        }
-                        if (std::abs(actuals.presentTime - predictions.presentTime) >
-                            kPresentThreshold) {
-                            jankMetadata |= actuals.presentTime > predictions.presentTime
-                                    ? LatePresent
-                                    : EarlyPresent;
-                        }
-                        if (jankMetadata & EarlyPresent) {
-                            jankType = JankType::SurfaceFlingerEarlyLatch;
-                        } else if (jankMetadata & LatePresent) {
-                            if (jankMetadata & EarlyFinish) {
-                                // TODO(b/169890654): Classify this properly
-                                jankType = JankType::Display;
-                            } else {
-                                jankType = JankType::AppDeadlineMissed;
-                            }
-                        }
-
-                        totalJankReasons |= jankType;
-                        mTimeStats->incrementJankyFrames(surfaceFrame->getOwnerUid(),
-                                                         surfaceFrame->getName(),
-                                                         jankType | displayFrame->jankType);
-                        surfaceFrame->setJankInfo(jankType, jankMetadata);
-                    }
-                }
-                surfaceFrame->traceSurfaceFrame(displayFrame->token);
-            }
-
-            mTimeStats->incrementJankyFrames(totalJankReasons);
+            displayFrame->onPresent(signalTime);
+            displayFrame->trace(mSurfaceFlingerPid);
         }
 
         mPendingPresentFences.erase(mPendingPresentFences.begin() + static_cast<int>(i));
@@ -557,16 +786,14 @@
     }
     mDisplayFrames.push_back(mCurrentDisplayFrame);
     mCurrentDisplayFrame.reset();
-    mCurrentDisplayFrame = std::make_shared<DisplayFrame>();
+    mCurrentDisplayFrame =
+            std::make_shared<DisplayFrame>(mTimeStats, mJankClassificationThresholds);
 }
 
-nsecs_t FrameTimeline::findBaseTime(const std::shared_ptr<DisplayFrame>& displayFrame) {
-    nsecs_t baseTime = std::numeric_limits<nsecs_t>::max();
-    if (displayFrame->predictionState == PredictionState::Valid) {
-        baseTime = std::min(baseTime, displayFrame->surfaceFlingerPredictions.startTime);
-    }
-    baseTime = std::min(baseTime, displayFrame->surfaceFlingerActuals.startTime);
-    for (const auto& surfaceFrame : displayFrame->surfaceFrames) {
+nsecs_t FrameTimeline::DisplayFrame::getBaseTime() const {
+    nsecs_t baseTime =
+            getMinTime(mPredictionState, mSurfaceFlingerPredictions, mSurfaceFlingerActuals);
+    for (const auto& surfaceFrame : mSurfaceFrames) {
         nsecs_t surfaceFrameBaseTime = surfaceFrame->getBaseTime();
         if (surfaceFrameBaseTime != 0) {
             baseTime = std::min(baseTime, surfaceFrameBaseTime);
@@ -575,60 +802,79 @@
     return baseTime;
 }
 
-void FrameTimeline::dumpDisplayFrame(std::string& result,
-                                     const std::shared_ptr<DisplayFrame>& displayFrame,
-                                     nsecs_t baseTime) {
-    if (displayFrame->jankType != JankType::None) {
+void FrameTimeline::DisplayFrame::dumpJank(std::string& result, nsecs_t baseTime,
+                                           int displayFrameCount) const {
+    if (mJankType == JankType::None) {
+        // Check if any Surface Frame has been janky
+        bool isJanky = false;
+        for (const auto& surfaceFrame : mSurfaceFrames) {
+            if (surfaceFrame->getJankType() != JankType::None) {
+                isJanky = true;
+                break;
+            }
+        }
+        if (!isJanky) {
+            return;
+        }
+    }
+    StringAppendF(&result, "Display Frame %d", displayFrameCount);
+    dump(result, baseTime);
+}
+
+void FrameTimeline::DisplayFrame::dumpAll(std::string& result, nsecs_t baseTime) const {
+    dump(result, baseTime);
+}
+
+void FrameTimeline::DisplayFrame::dump(std::string& result, nsecs_t baseTime) const {
+    if (mJankType != JankType::None) {
         // Easily identify a janky Display Frame in the dump
         StringAppendF(&result, " [*] ");
     }
     StringAppendF(&result, "\n");
-    StringAppendF(&result, "Prediction State : %s\n",
-                  toString(displayFrame->predictionState).c_str());
-    StringAppendF(&result, "Jank Type : %s\n", toString(displayFrame->jankType).c_str());
-    StringAppendF(&result, "Jank Metadata: %s\n",
-                  jankMetadataBitmaskToString(displayFrame->jankMetadata).c_str());
-    dumpTable(result, displayFrame->surfaceFlingerPredictions, displayFrame->surfaceFlingerActuals,
-              "", displayFrame->predictionState, baseTime);
+    StringAppendF(&result, "Prediction State : %s\n", toString(mPredictionState).c_str());
+    StringAppendF(&result, "Jank Type : %s\n", jankTypeBitmaskToString(mJankType).c_str());
+    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);
+    StringAppendF(&result, "Vsync Period: %10f\n",
+                  std::chrono::duration<double, std::milli>(vsyncPeriod).count());
+    nsecs_t presentDelta =
+            mSurfaceFlingerActuals.presentTime - mSurfaceFlingerPredictions.presentTime;
+    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);
+    StringAppendF(&result, "Present delta %% refreshrate: %10f\n",
+                  std::chrono::duration<double, std::milli>(deltaToVsync).count());
+    dumpTable(result, mSurfaceFlingerPredictions, mSurfaceFlingerActuals, "", mPredictionState,
+              baseTime);
     StringAppendF(&result, "\n");
     std::string indent = "    "; // 4 spaces
-    for (const auto& surfaceFrame : displayFrame->surfaceFrames) {
+    for (const auto& surfaceFrame : mSurfaceFrames) {
         surfaceFrame->dump(result, indent, baseTime);
     }
     StringAppendF(&result, "\n");
 }
+
 void FrameTimeline::dumpAll(std::string& result) {
     std::lock_guard<std::mutex> lock(mMutex);
     StringAppendF(&result, "Number of display frames : %d\n", (int)mDisplayFrames.size());
-    nsecs_t baseTime = (mDisplayFrames.empty()) ? 0 : findBaseTime(mDisplayFrames[0]);
+    nsecs_t baseTime = (mDisplayFrames.empty()) ? 0 : mDisplayFrames[0]->getBaseTime();
     for (size_t i = 0; i < mDisplayFrames.size(); i++) {
         StringAppendF(&result, "Display Frame %d", static_cast<int>(i));
-        dumpDisplayFrame(result, mDisplayFrames[i], baseTime);
+        mDisplayFrames[i]->dumpAll(result, baseTime);
     }
 }
 
 void FrameTimeline::dumpJank(std::string& result) {
     std::lock_guard<std::mutex> lock(mMutex);
-    nsecs_t baseTime = (mDisplayFrames.empty()) ? 0 : findBaseTime(mDisplayFrames[0]);
+    nsecs_t baseTime = (mDisplayFrames.empty()) ? 0 : mDisplayFrames[0]->getBaseTime();
     for (size_t i = 0; i < mDisplayFrames.size(); i++) {
-        const auto& displayFrame = mDisplayFrames[i];
-        if (displayFrame->jankType == JankType::None) {
-            // Check if any Surface Frame has been janky
-            bool isJanky = false;
-            for (const auto& surfaceFrame : displayFrame->surfaceFrames) {
-                if (surfaceFrame->getJankType() != JankType::None) {
-                    isJanky = true;
-                    break;
-                }
-            }
-            if (!isJanky) {
-                continue;
-            }
-        }
-        StringAppendF(&result, "Display Frame %d", static_cast<int>(i));
-        dumpDisplayFrame(result, displayFrame, baseTime);
+        mDisplayFrames[i]->dumpJank(result, baseTime, static_cast<int>(i));
     }
 }
+
 void FrameTimeline::parseArgs(const Vector<String16>& args, std::string& result) {
     ATRACE_CALL();
     std::unordered_map<std::string, bool> argsMap;
@@ -656,31 +902,5 @@
     setMaxDisplayFrames(kDefaultMaxDisplayFrames);
 }
 
-void FrameTimeline::traceDisplayFrame(const DisplayFrame& displayFrame) {
-    FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
-        if (displayFrame.token == ISurfaceComposer::INVALID_VSYNC_ID) {
-            ALOGD("Cannot trace DisplayFrame with invalid token");
-            return;
-        }
-        auto packet = ctx.NewTracePacket();
-        packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC);
-        packet->set_timestamp(static_cast<uint64_t>(systemTime()));
-
-        auto* event = packet->set_frame_timeline_event();
-        auto* displayFrameEvent = event->set_display_frame();
-
-        displayFrameEvent->set_token(displayFrame.token);
-        displayFrameEvent->set_present_type(presentTypeToProto(displayFrame.jankMetadata));
-        displayFrameEvent->set_on_time_finish(!(displayFrame.jankMetadata & LateFinish));
-        displayFrameEvent->set_gpu_composition(displayFrame.jankMetadata & GpuComposition);
-        displayFrameEvent->set_jank_type(JankTypeToProto(displayFrame.jankType));
-
-        displayFrameEvent->set_expected_start_ns(displayFrame.surfaceFlingerPredictions.startTime);
-        displayFrameEvent->set_expected_end_ns(displayFrame.surfaceFlingerPredictions.endTime);
-
-        displayFrameEvent->set_actual_start_ns(displayFrame.surfaceFlingerActuals.startTime);
-        displayFrameEvent->set_actual_end_ns(displayFrame.surfaceFlingerActuals.endTime);
-    });
-}
-
-} // namespace android::frametimeline::impl
+} // namespace impl
+} // namespace android::frametimeline
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.h b/services/surfaceflinger/FrameTimeline/FrameTimeline.h
index 084935b..f5239aa 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.h
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.h
@@ -32,24 +32,44 @@
 
 namespace android::frametimeline {
 
-enum JankMetadata {
-    // Frame was presented earlier than expected
-    EarlyPresent = 0x1,
-    // Frame was presented later than expected
-    LatePresent = 0x2,
-    // App/SF started earlier than expected
-    EarlyStart = 0x4,
-    // App/SF started later than expected
-    LateStart = 0x8,
-    // App/SF finished work earlier than the deadline
-    EarlyFinish = 0x10,
-    // App/SF finished work later than the deadline
-    LateFinish = 0x20,
-    // SF was in GPU composition
-    GpuComposition = 0x40,
+class FrameTimelineTest;
+
+using namespace std::chrono_literals;
+
+// Metadata indicating how the frame was presented w.r.t expected present time.
+enum class FramePresentMetadata : int8_t {
+    // Frame was presented on time
+    OnTimePresent,
+    // Frame was presented late
+    LatePresent,
+    // Frame was presented early
+    EarlyPresent,
+    // Unknown/initial state
+    UnknownPresent,
 };
 
-class FrameTimelineTest;
+// Metadata comparing the frame's actual finish time to the expected deadline.
+enum class FrameReadyMetadata : int8_t {
+    // App/SF finished on time. Early finish is treated as on time since the goal of any component
+    // is to finish before the deadline.
+    OnTimeFinish,
+    // App/SF finished work later than expected
+    LateFinish,
+    // Unknown/initial state
+    UnknownFinish,
+};
+
+// Metadata comparing the frame's actual start time to the expected start time.
+enum class FrameStartMetadata : int8_t {
+    // App/SF started on time
+    OnTimeStart,
+    // App/SF started later than expected
+    LateStart,
+    // App/SF started earlier than expected
+    EarlyStart,
+    // Unknown/initial state
+    UnknownStart,
+};
 
 /*
  * Collection of timestamps that can be used for both predictions and actual times.
@@ -71,6 +91,19 @@
     bool operator!=(const TimelineItem& other) const { return !(*this == other); }
 };
 
+struct TokenManagerPrediction {
+    nsecs_t timestamp = 0;
+    TimelineItem predictions;
+};
+
+struct JankClassificationThresholds {
+    // The various thresholds for App and SF. If the actual timestamp falls within the threshold
+    // compared to prediction, we treat it as on time.
+    nsecs_t presentThreshold = std::chrono::duration_cast<std::chrono::nanoseconds>(2ms).count();
+    nsecs_t deadlineThreshold = std::chrono::duration_cast<std::chrono::nanoseconds>(2ms).count();
+    nsecs_t startThreshold = std::chrono::duration_cast<std::chrono::nanoseconds>(2ms).count();
+};
+
 /*
  * TokenManager generates a running number token for a set of predictions made by VsyncPredictor. It
  * saves these predictions for a short period of time and returns the predictions for a given token,
@@ -83,6 +116,9 @@
     // Generates a token for the given set of predictions. Stores the predictions for 120ms and
     // destroys it later.
     virtual int64_t generateTokenForPredictions(TimelineItem&& prediction) = 0;
+
+    // Returns the stored predictions for a given token, if the predictions haven't expired.
+    virtual std::optional<TimelineItem> getPredictionsForToken(int64_t token) const = 0;
 };
 
 enum class PredictionState {
@@ -91,10 +127,6 @@
     None,    // Predictions are either not present or didn't come from TokenManager
 };
 
-/*
- * Stores a set of predictions and the corresponding actual timestamps pertaining to a single frame
- * from the app
- */
 class SurfaceFrame {
 public:
     enum class PresentState {
@@ -103,29 +135,76 @@
         Unknown,   // Initial state, SurfaceFlinger hasn't seen this buffer yet
     };
 
-    virtual ~SurfaceFrame() = default;
+    // Only FrameTimeline can construct a SurfaceFrame as it provides Predictions(through
+    // TokenManager), Thresholds and TimeStats pointer.
+    SurfaceFrame(int64_t token, pid_t ownerPid, uid_t ownerUid, std::string layerName,
+                 std::string debugName, PredictionState predictionState, TimelineItem&& predictions,
+                 std::shared_ptr<TimeStats> timeStats, JankClassificationThresholds thresholds);
+    ~SurfaceFrame() = default;
 
-    virtual TimelineItem getPredictions() const = 0;
-    virtual TimelineItem getActuals() const = 0;
-    virtual nsecs_t getActualQueueTime() const = 0;
-    virtual PresentState getPresentState() const = 0;
-    virtual PredictionState getPredictionState() const = 0;
-    virtual pid_t getOwnerPid() const = 0;
+    // Returns std::nullopt if the frame hasn't been classified yet.
+    // Used by both SF and FrameTimeline.
+    std::optional<int32_t> getJankType() const;
 
-    virtual void setPresentState(PresentState state) = 0;
-
+    // Functions called by SF
+    int64_t getToken() const { return mToken; };
+    TimelineItem getPredictions() const { return mPredictions; };
     // Actual timestamps of the app are set individually at different functions.
     // Start time (if the app provides) and Queue time are accessible after queueing the frame,
     // whereas Acquire Fence time is available only during latch.
-    virtual void setActualStartTime(nsecs_t actualStartTime) = 0;
-    virtual void setActualQueueTime(nsecs_t actualQueueTime) = 0;
-    virtual void setAcquireFenceTime(nsecs_t acquireFenceTime) = 0;
+    void setActualStartTime(nsecs_t actualStartTime);
+    void setActualQueueTime(nsecs_t actualQueueTime);
+    void setAcquireFenceTime(nsecs_t acquireFenceTime);
+    void setPresentState(PresentState presentState, nsecs_t lastLatchTime = 0);
 
-    // Retrieves jank classification, if it's already been classified.
-    virtual std::optional<JankType> getJankType() const = 0;
+    // 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);
+    // 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
+    // enabled. The displayFrameToken is needed to link the SurfaceFrame to the corresponding
+    // DisplayFrame at the trace processor side.
+    void trace(int64_t displayFrameToken);
 
-    // Token identifying the frame.
-    virtual int64_t getToken() const = 0;
+    // Getter functions used only by FrameTimelineTests
+    TimelineItem getActuals() const;
+    pid_t getOwnerPid() const { return mOwnerPid; };
+    PredictionState getPredictionState() const { return mPredictionState; };
+    PresentState getPresentState() const;
+    FrameReadyMetadata getFrameReadyMetadata() const;
+    FramePresentMetadata getFramePresentMetadata() const;
+
+private:
+    const int64_t mToken;
+    const pid_t mOwnerPid;
+    const uid_t mOwnerUid;
+    const std::string mLayerName;
+    const std::string mDebugName;
+    PresentState mPresentState GUARDED_BY(mMutex);
+    const PredictionState mPredictionState;
+    const TimelineItem mPredictions;
+    TimelineItem mActuals GUARDED_BY(mMutex);
+    std::shared_ptr<TimeStats> mTimeStats;
+    const JankClassificationThresholds mJankClassificationThresholds;
+    nsecs_t mActualQueueTime GUARDED_BY(mMutex) = 0;
+    mutable std::mutex mMutex;
+    // Bitmask for the type of jank
+    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;
+    // Enum for the type of present
+    FramePresentMetadata mFramePresentMetadata GUARDED_BY(mMutex) =
+            FramePresentMetadata::UnknownPresent;
+    // Enum for the type of finish
+    FrameReadyMetadata mFrameReadyMetadata GUARDED_BY(mMutex) = FrameReadyMetadata::UnknownFinish;
+    // Time when the previous buffer from the same layer was latched by SF. This is used in checking
+    // for BufferStuffing where the current buffer is expected to be ready but the previous buffer
+    // was latched instead.
+    nsecs_t mLastLatchTime GUARDED_BY(mMutex) = 0;
 };
 
 /*
@@ -142,20 +221,19 @@
     virtual void onBootFinished() = 0;
 
     // Create a new surface frame, set the predictions based on a token and return it to the caller.
-    // Sets the PredictionState of SurfaceFrame.
     // Debug name is the human-readable debugging string for dumpsys.
-    virtual std::shared_ptr<SurfaceFrame> createSurfaceFrameForToken(
-            pid_t ownerPid, uid_t ownerUid, std::string layerName, std::string debugName,
-            std::optional<int64_t> token) = 0;
+    virtual std::shared_ptr<SurfaceFrame> createSurfaceFrameForToken(std::optional<int64_t> token,
+                                                                     pid_t ownerPid, uid_t ownerUid,
+                                                                     std::string layerName,
+                                                                     std::string debugName) = 0;
 
     // Adds a new SurfaceFrame to the current DisplayFrame. Frames from multiple layers can be
     // composited into one display frame.
-    virtual void addSurfaceFrame(std::shared_ptr<SurfaceFrame> surfaceFrame,
-                                 SurfaceFrame::PresentState state) = 0;
+    virtual void addSurfaceFrame(std::shared_ptr<SurfaceFrame> surfaceFrame) = 0;
 
     // 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) = 0;
+    virtual void setSfWakeUp(int64_t token, nsecs_t wakeupTime, nsecs_t vsyncPeriod) = 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
@@ -178,15 +256,13 @@
 
 namespace impl {
 
-using namespace std::chrono_literals;
-
 class TokenManager : public android::frametimeline::TokenManager {
 public:
     TokenManager() : mCurrentToken(ISurfaceComposer::INVALID_VSYNC_ID + 1) {}
     ~TokenManager() = default;
 
     int64_t generateTokenForPredictions(TimelineItem&& predictions) override;
-    std::optional<TimelineItem> getPredictionsForToken(int64_t token);
+    std::optional<TimelineItem> getPredictionsForToken(int64_t token) const override;
 
 private:
     // Friend class for testing
@@ -194,64 +270,13 @@
 
     void flushTokens(nsecs_t flushTime) REQUIRES(mMutex);
 
-    std::unordered_map<int64_t, TimelineItem> mPredictions GUARDED_BY(mMutex);
-    std::vector<std::pair<int64_t, nsecs_t>> mTokens GUARDED_BY(mMutex);
+    std::map<int64_t, TokenManagerPrediction> mPredictions GUARDED_BY(mMutex);
     int64_t mCurrentToken GUARDED_BY(mMutex);
-    std::mutex mMutex;
+    mutable std::mutex mMutex;
     static constexpr nsecs_t kMaxRetentionTime =
             std::chrono::duration_cast<std::chrono::nanoseconds>(120ms).count();
 };
 
-class SurfaceFrame : public android::frametimeline::SurfaceFrame {
-public:
-    SurfaceFrame(int64_t token, pid_t ownerPid, uid_t ownerUid, std::string layerName,
-                 std::string debugName, PredictionState predictionState,
-                 TimelineItem&& predictions);
-    ~SurfaceFrame() = default;
-
-    TimelineItem getPredictions() const override { return mPredictions; };
-    TimelineItem getActuals() const override;
-    nsecs_t getActualQueueTime() const override;
-    PresentState getPresentState() const override;
-    PredictionState getPredictionState() const override { return mPredictionState; };
-    pid_t getOwnerPid() const override { return mOwnerPid; };
-    std::optional<JankType> getJankType() const override;
-    int64_t getToken() const override { return mToken; };
-    nsecs_t getBaseTime() const;
-    uid_t getOwnerUid() const { return mOwnerUid; };
-    const std::string& getName() const { return mLayerName; };
-
-    void setActualStartTime(nsecs_t actualStartTime) override;
-    void setActualQueueTime(nsecs_t actualQueueTime) override;
-    void setAcquireFenceTime(nsecs_t acquireFenceTime) override;
-    void setPresentState(PresentState state) override;
-    void setActualPresentTime(nsecs_t presentTime);
-    void setJankInfo(JankType jankType, int32_t jankMetadata);
-
-    // All the timestamps are dumped relative to the baseTime
-    void dump(std::string& result, const std::string& indent, nsecs_t baseTime);
-
-    // Emits a packet for perfetto tracing. The function body will be executed only if tracing is
-    // enabled. The displayFrameToken is needed to link the SurfaceFrame to the corresponding
-    // DisplayFrame at the trace processor side.
-    void traceSurfaceFrame(int64_t displayFrameToken);
-
-private:
-    const int64_t mToken;
-    const pid_t mOwnerPid;
-    const uid_t mOwnerUid;
-    const std::string mLayerName;
-    const std::string mDebugName;
-    PresentState mPresentState GUARDED_BY(mMutex);
-    const PredictionState mPredictionState;
-    const TimelineItem mPredictions;
-    TimelineItem mActuals GUARDED_BY(mMutex);
-    nsecs_t mActualQueueTime GUARDED_BY(mMutex);
-    mutable std::mutex mMutex;
-    JankType mJankType GUARDED_BY(mMutex); // Enum for the type of jank
-    int32_t mJankMetadata GUARDED_BY(mMutex); // Additional details about the jank
-};
-
 class FrameTimeline : public android::frametimeline::FrameTimeline {
 public:
     class FrameTimelineDataSource : public perfetto::DataSource<FrameTimelineDataSource> {
@@ -260,16 +285,94 @@
         void OnStop(const StopArgs&) override{};
     };
 
-    FrameTimeline(std::shared_ptr<TimeStats> timeStats);
+    /*
+     * DisplayFrame should be used only internally within FrameTimeline. All members and methods are
+     * guarded by FrameTimeline's mMutex.
+     */
+    class DisplayFrame {
+    public:
+        DisplayFrame(std::shared_ptr<TimeStats> timeStats, JankClassificationThresholds thresholds);
+        virtual ~DisplayFrame() = default;
+        // Dumpsys interface - dumps only if the DisplayFrame itself is janky or is at least one
+        // SurfaceFrame is janky.
+        void dumpJank(std::string& result, nsecs_t baseTime, int displayFrameCount) const;
+        // Dumpsys interface - dumps all data irrespective of jank
+        void dumpAll(std::string& result, nsecs_t baseTime) const;
+        // Emits a packet for perfetto tracing. The function body will be executed only if tracing
+        // 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,
+                        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);
+
+        // BaseTime is the smallest timestamp in a DisplayFrame.
+        // Used for dumping all timestamps relative to the oldest, making it easy to read.
+        nsecs_t getBaseTime() const;
+
+        // Functions to be used only in testing.
+        TimelineItem getActuals() const { return mSurfaceFlingerActuals; };
+        TimelineItem getPredictions() const { return mSurfaceFlingerPredictions; };
+        FramePresentMetadata getFramePresentMetadata() const { return mFramePresentMetadata; };
+        FrameReadyMetadata getFrameReadyMetadata() const { return mFrameReadyMetadata; };
+        int32_t getJankType() const { return mJankType; }
+        const std::vector<std::shared_ptr<SurfaceFrame>>& getSurfaceFrames() const {
+            return mSurfaceFrames;
+        }
+
+    private:
+        void dump(std::string& result, nsecs_t baseTime) const;
+
+        int64_t mToken = ISurfaceComposer::INVALID_VSYNC_ID;
+
+        /* Usage of TimelineItem w.r.t SurfaceFlinger
+         * startTime    Time when SurfaceFlinger wakes up to handle transactions and buffer updates
+         * endTime      Time when SurfaceFlinger sends a composited frame to Display
+         * presentTime  Time when the composited frame was presented on screen
+         */
+        TimelineItem mSurfaceFlingerPredictions;
+        TimelineItem mSurfaceFlingerActuals;
+        std::shared_ptr<TimeStats> mTimeStats;
+        const JankClassificationThresholds mJankClassificationThresholds;
+
+        // Collection of predictions and actual values sent over by Layers
+        std::vector<std::shared_ptr<SurfaceFrame>> mSurfaceFrames;
+
+        PredictionState mPredictionState = PredictionState::None;
+        // Bitmask for the type of jank
+        int32_t mJankType = JankType::None;
+        // Indicates if this frame was composited by the GPU or not
+        bool mGpuComposition = false;
+        // Enum for the type of present
+        FramePresentMetadata mFramePresentMetadata = FramePresentMetadata::UnknownPresent;
+        // Enum for the type of finish
+        FrameReadyMetadata mFrameReadyMetadata = FrameReadyMetadata::UnknownFinish;
+        // Enum for the type of start
+        FrameStartMetadata mFrameStartMetadata = FrameStartMetadata::UnknownStart;
+        // The refresh rate (vsync period) in nanoseconds as seen by SF during this DisplayFrame's
+        // timeline
+        nsecs_t mVsyncPeriod = 0;
+    };
+
+    FrameTimeline(std::shared_ptr<TimeStats> timeStats, pid_t surfaceFlingerPid,
+                  JankClassificationThresholds thresholds = {});
     ~FrameTimeline() = default;
 
     frametimeline::TokenManager* getTokenManager() override { return &mTokenManager; }
-    std::shared_ptr<frametimeline::SurfaceFrame> createSurfaceFrameForToken(
-            pid_t ownerPid, uid_t ownerUid, std::string layerName, std::string debugName,
-            std::optional<int64_t> token) override;
-    void addSurfaceFrame(std::shared_ptr<frametimeline::SurfaceFrame> surfaceFrame,
-                         SurfaceFrame::PresentState state) override;
-    void setSfWakeUp(int64_t token, nsecs_t wakeupTime) override;
+    std::shared_ptr<SurfaceFrame> createSurfaceFrameForToken(std::optional<int64_t> token,
+                                                             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 setSfPresent(nsecs_t sfPresentTime,
                       const std::shared_ptr<FenceTime>& presentFence) override;
     void parseArgs(const Vector<String16>& args, std::string& result) override;
@@ -288,67 +391,28 @@
     // Friend class for testing
     friend class android::frametimeline::FrameTimelineTest;
 
-    /*
-     * DisplayFrame should be used only internally within FrameTimeline.
-     */
-    struct DisplayFrame {
-        DisplayFrame();
-
-        int64_t token = ISurfaceComposer::INVALID_VSYNC_ID;
-
-        /* Usage of TimelineItem w.r.t SurfaceFlinger
-         * startTime    Time when SurfaceFlinger wakes up to handle transactions and buffer updates
-         * endTime      Time when SurfaceFlinger sends a composited frame to Display
-         * presentTime  Time when the composited frame was presented on screen
-         */
-        TimelineItem surfaceFlingerPredictions;
-        TimelineItem surfaceFlingerActuals;
-
-        // Collection of predictions and actual values sent over by Layers
-        std::vector<std::shared_ptr<SurfaceFrame>> surfaceFrames;
-
-        PredictionState predictionState = PredictionState::None;
-        JankType jankType = JankType::None; // Enum for the type of jank
-        int32_t jankMetadata = 0x0; // Additional details about the jank
-    };
-
     void flushPendingPresentFences() REQUIRES(mMutex);
     void finalizeCurrentDisplayFrame() REQUIRES(mMutex);
-    // BaseTime is the smallest timestamp in a DisplayFrame.
-    // Used for dumping all timestamps relative to the oldest, making it easy to read.
-    nsecs_t findBaseTime(const std::shared_ptr<DisplayFrame>&) REQUIRES(mMutex);
-    void dumpDisplayFrame(std::string& result, const std::shared_ptr<DisplayFrame>&,
-                          nsecs_t baseTime) REQUIRES(mMutex);
     void dumpAll(std::string& result);
     void dumpJank(std::string& result);
 
-    // Emits a packet for perfetto tracing. The function body will be executed only if tracing is
-    // enabled.
-    void traceDisplayFrame(const DisplayFrame& displayFrame) REQUIRES(mMutex);
-
     // Sliding window of display frames. TODO(b/168072834): compare perf with fixed size array
     std::deque<std::shared_ptr<DisplayFrame>> mDisplayFrames GUARDED_BY(mMutex);
     std::vector<std::pair<std::shared_ptr<FenceTime>, std::shared_ptr<DisplayFrame>>>
             mPendingPresentFences GUARDED_BY(mMutex);
     std::shared_ptr<DisplayFrame> mCurrentDisplayFrame GUARDED_BY(mMutex);
     TokenManager mTokenManager;
-    std::mutex mMutex;
+    mutable std::mutex mMutex;
     uint32_t mMaxDisplayFrames;
     std::shared_ptr<TimeStats> mTimeStats;
+    const pid_t mSurfaceFlingerPid;
+    const JankClassificationThresholds mJankClassificationThresholds;
     static constexpr uint32_t kDefaultMaxDisplayFrames = 64;
     // The initial container size for the vector<SurfaceFrames> inside display frame. Although
     // this number doesn't represent any bounds on the number of surface frames that can go in a
     // display frame, this is a good starting size for the vector so that we can avoid the
     // internal vector resizing that happens with push_back.
     static constexpr uint32_t kNumSurfaceFramesInitial = 10;
-    // The various thresholds for App and SF. If the actual timestamp falls within the threshold
-    // compared to prediction, we don't treat it as a jank.
-    static constexpr nsecs_t kPresentThreshold =
-            std::chrono::duration_cast<std::chrono::nanoseconds>(2ms).count();
-    static constexpr nsecs_t kDeadlineThreshold =
-            std::chrono::duration_cast<std::chrono::nanoseconds>(2ms).count();
-    static constexpr nsecs_t kSFStartThreshold =
-            std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count();
 };
 
 } // namespace impl
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index f53c4cc..4731f50 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -911,9 +911,8 @@
                 : std::make_optional(stateToCommit->frameTimelineVsyncId);
 
         mSurfaceFrame =
-                mFlinger->mFrameTimeline->createSurfaceFrameForToken(getOwnerPid(), getOwnerUid(),
-                                                                     mName, mTransactionName,
-                                                                     vsyncId);
+                mFlinger->mFrameTimeline->createSurfaceFrameForToken(vsyncId, mOwnerPid, mOwnerUid,
+                                                                     mName, mTransactionName);
         mSurfaceFrame->setActualQueueTime(stateToCommit->postTime);
         // For transactions we set the acquire fence time to the post time as we
         // don't have a buffer. For BufferStateLayer it is overridden in
@@ -1066,7 +1065,8 @@
 
 void Layer::commitTransaction(const State& stateToCommit) {
     mDrawingState = stateToCommit;
-    mFlinger->mFrameTimeline->addSurfaceFrame(mSurfaceFrame, PresentState::Presented);
+    mSurfaceFrame->setPresentState(PresentState::Presented);
+    mFlinger->mFrameTimeline->addSurfaceFrame(mSurfaceFrame);
 }
 
 uint32_t Layer::getTransactionFlags(uint32_t flags) {
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 6f86e76..2c16411 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -339,7 +339,7 @@
         mInterceptor(mFactory.createSurfaceInterceptor()),
         mTimeStats(std::make_shared<impl::TimeStats>()),
         mFrameTracer(mFactory.createFrameTracer()),
-        mFrameTimeline(mFactory.createFrameTimeline(mTimeStats)),
+        mFrameTimeline(mFactory.createFrameTimeline(mTimeStats, getpid())),
         mEventQueue(mFactory.createMessageQueue()),
         mCompositionEngine(mFactory.createCompositionEngine()),
         mInternalDisplayDensity(getDensityFromProperty("ro.sf.lcd_density", true)),
@@ -1872,7 +1872,7 @@
         const bool tracePreComposition = mTracingEnabled && !mTracePostComposition;
         ConditionalLockGuard<std::mutex> lock(mTracingLock, tracePreComposition);
 
-        mFrameTimeline->setSfWakeUp(vsyncId, frameStart);
+        mFrameTimeline->setSfWakeUp(vsyncId, frameStart, stats.vsyncPeriod);
 
         refreshNeeded = handleMessageTransaction();
         refreshNeeded |= handleMessageInvalidate();
@@ -5360,8 +5360,8 @@
                 const auto refreshRate = data.readFloat();
                 mScheduler->setPreferredRefreshRateForUid(FrameRateOverride{inUid, refreshRate});
                 mScheduler->onFrameRateOverridesChanged(mAppConnectionHandle, displayId);
-            }
                 return NO_ERROR;
+            }
         }
     }
     return err;
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
index bc487ac..0d3d9e1 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
@@ -136,8 +136,8 @@
 }
 
 std::unique_ptr<frametimeline::FrameTimeline> DefaultFactory::createFrameTimeline(
-        std::shared_ptr<TimeStats> timeStats) {
-    return std::make_unique<frametimeline::impl::FrameTimeline>(timeStats);
+        std::shared_ptr<TimeStats> timeStats, pid_t surfaceFlingerPid) {
+    return std::make_unique<frametimeline::impl::FrameTimeline>(timeStats, surfaceFlingerPid);
 }
 
 } // namespace android::surfaceflinger
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
index fc45fa9..da160fd 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
@@ -56,7 +56,7 @@
     sp<ContainerLayer> createContainerLayer(const LayerCreationArgs& args) override;
     std::unique_ptr<FrameTracer> createFrameTracer() override;
     std::unique_ptr<frametimeline::FrameTimeline> createFrameTimeline(
-            std::shared_ptr<TimeStats> timeStats) override;
+            std::shared_ptr<TimeStats> timeStats, pid_t surfaceFlingerPid) override;
 };
 
 } // namespace android::surfaceflinger
diff --git a/services/surfaceflinger/SurfaceFlingerFactory.h b/services/surfaceflinger/SurfaceFlingerFactory.h
index deb1b52..6638490 100644
--- a/services/surfaceflinger/SurfaceFlingerFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerFactory.h
@@ -108,7 +108,7 @@
     virtual sp<ContainerLayer> createContainerLayer(const LayerCreationArgs& args) = 0;
     virtual std::unique_ptr<FrameTracer> createFrameTracer() = 0;
     virtual std::unique_ptr<frametimeline::FrameTimeline> createFrameTimeline(
-            std::shared_ptr<TimeStats> timeStats) = 0;
+            std::shared_ptr<TimeStats> timeStats, pid_t surfaceFlingerPid) = 0;
 
 protected:
     ~Factory() = default;
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index 2405884..f4a0319 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -680,19 +680,18 @@
 static void updateJankPayload(T& t, int32_t reasons) {
     t.jankPayload.totalFrames++;
 
-    static const constexpr int32_t kValidJankyReason =
-            JankType::SurfaceFlingerDeadlineMissed |
-            JankType::SurfaceFlingerGpuDeadlineMissed |
-            JankType::AppDeadlineMissed | JankType::Display;
+    static const constexpr int32_t kValidJankyReason = JankType::SurfaceFlingerCpuDeadlineMissed |
+            JankType::SurfaceFlingerGpuDeadlineMissed | JankType::AppDeadlineMissed |
+            JankType::DisplayHAL;
     if (reasons & kValidJankyReason) {
         t.jankPayload.totalJankyFrames++;
-        if ((reasons & JankType::SurfaceFlingerDeadlineMissed) != 0) {
+        if ((reasons & JankType::SurfaceFlingerCpuDeadlineMissed) != 0) {
             t.jankPayload.totalSFLongCpu++;
         }
         if ((reasons & JankType::SurfaceFlingerGpuDeadlineMissed) != 0) {
             t.jankPayload.totalSFLongGpu++;
         }
-        if ((reasons & JankType::Display) != 0) {
+        if ((reasons & JankType::DisplayHAL) != 0) {
             t.jankPayload.totalSFUnattributed++;
         }
         if ((reasons & JankType::AppDeadlineMissed) != 0) {
diff --git a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
index 43b5afe..4b897fa 100644
--- a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
@@ -26,6 +26,7 @@
 #include <cinttypes>
 
 using namespace std::chrono_literals;
+using testing::AtLeast;
 using testing::Contains;
 using FrameTimelineEvent = perfetto::protos::FrameTimelineEvent;
 using ProtoDisplayFrame = perfetto::protos::FrameTimelineEvent_DisplayFrame;
@@ -62,7 +63,8 @@
 
     void SetUp() override {
         mTimeStats = std::make_shared<mock::TimeStats>();
-        mFrameTimeline = std::make_unique<impl::FrameTimeline>(mTimeStats);
+        mFrameTimeline = std::make_unique<impl::FrameTimeline>(mTimeStats, mSurfaceFlingerPid,
+                                                               kTestThresholds);
         mFrameTimeline->registerDataSource();
         mTokenManager = &mFrameTimeline->mTokenManager;
         maxDisplayFrames = &mFrameTimeline->mMaxDisplayFrames;
@@ -110,7 +112,8 @@
 
     SurfaceFrame& getSurfaceFrame(size_t displayFrameIdx, size_t surfaceFrameIdx) {
         std::lock_guard<std::mutex> lock(mFrameTimeline->mMutex);
-        return *(mFrameTimeline->mDisplayFrames[displayFrameIdx]->surfaceFrames[surfaceFrameIdx]);
+        return *(mFrameTimeline->mDisplayFrames[displayFrameIdx]
+                         ->getSurfaceFrames()[surfaceFrameIdx]);
     }
 
     std::shared_ptr<impl::FrameTimeline::DisplayFrame> getDisplayFrame(size_t idx) {
@@ -123,7 +126,7 @@
                 a.presentTime == b.presentTime;
     }
 
-    const std::unordered_map<int64_t, TimelineItem>& getPredictions() {
+    const std::map<int64_t, TokenManagerPrediction>& getPredictions() {
         return mTokenManager->mPredictions;
     }
 
@@ -138,6 +141,16 @@
     FenceToFenceTimeMap fenceFactory;
     uint32_t* maxDisplayFrames;
     nsecs_t maxTokenRetentionTime;
+    pid_t mSurfaceFlingerPid = 666;
+    static constexpr nsecs_t kPresentThreshold =
+            std::chrono::duration_cast<std::chrono::nanoseconds>(2ns).count();
+    static constexpr nsecs_t kDeadlineThreshold =
+            std::chrono::duration_cast<std::chrono::nanoseconds>(2ns).count();
+    static constexpr nsecs_t kStartThreshold =
+            std::chrono::duration_cast<std::chrono::nanoseconds>(2ns).count();
+    static constexpr JankClassificationThresholds kTestThresholds{kPresentThreshold,
+                                                                  kDeadlineThreshold,
+                                                                  kStartThreshold};
 };
 
 static const std::string sLayerNameOne = "layer1";
@@ -162,55 +175,58 @@
 }
 
 TEST_F(FrameTimelineTest, createSurfaceFrameForToken_getOwnerPidReturnsCorrectPid) {
-    auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken(sPidOne, sUidOne, sLayerNameOne,
-                                                                    sLayerNameOne, std::nullopt);
-    auto surfaceFrame2 = mFrameTimeline->createSurfaceFrameForToken(sPidTwo, sUidOne, sLayerNameOne,
-                                                                    sLayerNameOne, std::nullopt);
+    auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken(std::nullopt, sPidOne, sUidOne,
+                                                                    sLayerNameOne, sLayerNameOne);
+    auto surfaceFrame2 = mFrameTimeline->createSurfaceFrameForToken(std::nullopt, sPidTwo, sUidOne,
+                                                                    sLayerNameOne, sLayerNameOne);
     EXPECT_EQ(surfaceFrame1->getOwnerPid(), sPidOne);
     EXPECT_EQ(surfaceFrame2->getOwnerPid(), sPidTwo);
 }
 
 TEST_F(FrameTimelineTest, createSurfaceFrameForToken_noToken) {
-    auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken(sPidOne, sUidOne, sLayerNameOne,
-                                                                   sLayerNameOne, std::nullopt);
+    auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken(std::nullopt, sPidOne, sUidOne,
+                                                                   sLayerNameOne, sLayerNameOne);
     EXPECT_EQ(surfaceFrame->getPredictionState(), PredictionState::None);
 }
 
 TEST_F(FrameTimelineTest, createSurfaceFrameForToken_expiredToken) {
     int64_t token1 = mTokenManager->generateTokenForPredictions({0, 0, 0});
     flushTokens(systemTime() + maxTokenRetentionTime);
-    auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken(sPidOne, sUidOne, sLayerNameOne,
-                                                                   sLayerNameOne, token1);
+    auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken(token1, sPidOne, sUidOne,
+                                                                   sLayerNameOne, sLayerNameOne);
 
     EXPECT_EQ(surfaceFrame->getPredictionState(), PredictionState::Expired);
 }
 
 TEST_F(FrameTimelineTest, createSurfaceFrameForToken_validToken) {
     int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30});
-    auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken(sPidOne, sUidOne, sLayerNameOne,
-                                                                   sLayerNameOne, token1);
+    auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken(token1, sPidOne, sUidOne,
+                                                                   sLayerNameOne, sLayerNameOne);
 
     EXPECT_EQ(surfaceFrame->getPredictionState(), PredictionState::Valid);
     EXPECT_EQ(compareTimelineItems(surfaceFrame->getPredictions(), TimelineItem(10, 20, 30)), true);
 }
 
 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);
 
     int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30});
     int64_t token2 = mTokenManager->generateTokenForPredictions({40, 50, 60});
-    auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken(sPidOne, sUidOne, sLayerNameOne,
-                                                                    sLayerNameOne, token1);
+    auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken(token1, sPidOne, sUidOne,
+                                                                    sLayerNameOne, sLayerNameOne);
 
     // Set up the display frame
-    mFrameTimeline->setSfWakeUp(token1, 20);
-    mFrameTimeline->addSurfaceFrame(surfaceFrame1, SurfaceFrame::PresentState::Dropped);
+    mFrameTimeline->setSfWakeUp(token1, 20, 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);
+    mFrameTimeline->setSfWakeUp(token2, 50, 11);
     mFrameTimeline->setSfPresent(55, presentFence2);
 
     auto& droppedSurfaceFrame = getSurfaceFrame(0, 0);
@@ -219,48 +235,50 @@
 }
 
 TEST_F(FrameTimelineTest, presentFenceSignaled_presentedFramesUpdated) {
+    // Global increment
+    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_));
+    // Layer specific increment
+    EXPECT_CALL(*mTimeStats, incrementJankyFrames(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});
     int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 30});
     int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 56, 60});
     auto surfaceFrame1 =
-            mFrameTimeline->createSurfaceFrameForToken(sPidOne, sUidOne, sLayerNameOne,
-                                                       sLayerNameOne, surfaceFrameToken1);
+            mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken1, sPidOne, sUidOne,
+                                                       sLayerNameOne, sLayerNameOne);
     auto surfaceFrame2 =
-            mFrameTimeline->createSurfaceFrameForToken(sPidOne, sUidOne, sLayerNameTwo,
-                                                       sLayerNameTwo, surfaceFrameToken2);
-    mFrameTimeline->setSfWakeUp(sfToken1, 22);
-    mFrameTimeline->addSurfaceFrame(surfaceFrame1,
-                                    SurfaceFrame::PresentState::Presented);
-    mFrameTimeline->addSurfaceFrame(surfaceFrame2,
-                                    SurfaceFrame::PresentState::Presented);
+            mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken1, sPidOne, sUidOne,
+                                                       sLayerNameTwo, sLayerNameTwo);
+    mFrameTimeline->setSfWakeUp(sfToken1, 22, 11);
+    surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
+    mFrameTimeline->addSurfaceFrame(surfaceFrame1);
+    surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented);
+    mFrameTimeline->addSurfaceFrame(surfaceFrame2);
     mFrameTimeline->setSfPresent(26, presentFence1);
     auto displayFrame = getDisplayFrame(0);
-    SurfaceFrame& presentedSurfaceFrame1 = getSurfaceFrame(0, 0);
-    SurfaceFrame& presentedSurfaceFrame2 = getSurfaceFrame(0, 1);
+    auto& presentedSurfaceFrame1 = getSurfaceFrame(0, 0);
+    auto& presentedSurfaceFrame2 = getSurfaceFrame(0, 1);
     presentFence1->signalForTest(42);
 
     // Fences haven't been flushed yet, so it should be 0
-    EXPECT_EQ(displayFrame->surfaceFlingerActuals.presentTime, 0);
+    EXPECT_EQ(displayFrame->getActuals().presentTime, 0);
     EXPECT_EQ(presentedSurfaceFrame1.getActuals().presentTime, 0);
     EXPECT_EQ(presentedSurfaceFrame2.getActuals().presentTime, 0);
 
-    EXPECT_EQ(surfaceFrame1->getToken(), surfaceFrameToken1);
-    EXPECT_EQ(surfaceFrame2->getToken(), surfaceFrameToken2);
-
     // Trigger a flush by finalizing the next DisplayFrame
     auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     auto surfaceFrame3 =
-            mFrameTimeline->createSurfaceFrameForToken(sPidOne, sUidOne, sLayerNameOne,
-                                                       sLayerNameOne, surfaceFrameToken2);
-    mFrameTimeline->setSfWakeUp(sfToken2, 52);
-    mFrameTimeline->addSurfaceFrame(surfaceFrame3, SurfaceFrame::PresentState::Dropped);
+            mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken2, sPidOne, sUidOne,
+                                                       sLayerNameOne, sLayerNameOne);
+    mFrameTimeline->setSfWakeUp(sfToken2, 52, 11);
+    surfaceFrame3->setPresentState(SurfaceFrame::PresentState::Dropped);
+    mFrameTimeline->addSurfaceFrame(surfaceFrame3);
     mFrameTimeline->setSfPresent(56, presentFence2);
     displayFrame = getDisplayFrame(0);
 
     // Fences have flushed, so the present timestamps should be updated
-    EXPECT_EQ(displayFrame->surfaceFlingerActuals.presentTime, 42);
+    EXPECT_EQ(displayFrame->getActuals().presentTime, 42);
     EXPECT_EQ(presentedSurfaceFrame1.getActuals().presentTime, 42);
     EXPECT_EQ(presentedSurfaceFrame2.getActuals().presentTime, 42);
     EXPECT_NE(surfaceFrame1->getJankType(), std::nullopt);
@@ -270,6 +288,12 @@
 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::_))
+            .Times(static_cast<int32_t>(*maxDisplayFrames));
     for (size_t i = 0; i < *maxDisplayFrames; i++) {
         auto presentFence = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
         int64_t surfaceFrameToken = mTokenManager->generateTokenForPredictions(
@@ -277,11 +301,11 @@
         int64_t sfToken = mTokenManager->generateTokenForPredictions(
                 {22 + frameTimeFactor, 26 + frameTimeFactor, 30 + frameTimeFactor});
         auto surfaceFrame =
-                mFrameTimeline->createSurfaceFrameForToken(sPidOne, sUidOne, sLayerNameOne,
-                                                           sLayerNameOne, surfaceFrameToken);
-        mFrameTimeline->setSfWakeUp(sfToken, 22 + frameTimeFactor);
-        mFrameTimeline->addSurfaceFrame(surfaceFrame,
-                                        SurfaceFrame::PresentState::Presented);
+                mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken, sPidOne, sUidOne,
+                                                           sLayerNameOne, sLayerNameOne);
+        mFrameTimeline->setSfWakeUp(sfToken, 22 + frameTimeFactor, 11);
+        surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented);
+        mFrameTimeline->addSurfaceFrame(surfaceFrame);
         mFrameTimeline->setSfPresent(27 + frameTimeFactor, presentFence);
         presentFence->signalForTest(32 + frameTimeFactor);
         frameTimeFactor += 30;
@@ -289,8 +313,7 @@
     auto displayFrame0 = getDisplayFrame(0);
 
     // The 0th Display Frame should have actuals 22, 27, 32
-    EXPECT_EQ(compareTimelineItems(displayFrame0->surfaceFlingerActuals, TimelineItem(22, 27, 32)),
-              true);
+    EXPECT_EQ(compareTimelineItems(displayFrame0->getActuals(), TimelineItem(22, 27, 32)), true);
 
     // Add one more display frame
     auto presentFence = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
@@ -299,51 +322,54 @@
     int64_t sfToken = mTokenManager->generateTokenForPredictions(
             {22 + frameTimeFactor, 26 + frameTimeFactor, 30 + frameTimeFactor});
     auto surfaceFrame =
-            mFrameTimeline->createSurfaceFrameForToken(sPidOne, sUidOne, sLayerNameOne,
-                                                       sLayerNameOne, surfaceFrameToken);
-    mFrameTimeline->setSfWakeUp(sfToken, 22 + frameTimeFactor);
-    mFrameTimeline->addSurfaceFrame(surfaceFrame, SurfaceFrame::PresentState::Presented);
+            mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken, sPidOne, sUidOne,
+                                                       sLayerNameOne, sLayerNameOne);
+    mFrameTimeline->setSfWakeUp(sfToken, 22 + frameTimeFactor, 11);
+    surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented);
+    mFrameTimeline->addSurfaceFrame(surfaceFrame);
     mFrameTimeline->setSfPresent(27 + frameTimeFactor, presentFence);
     presentFence->signalForTest(32 + frameTimeFactor);
     displayFrame0 = getDisplayFrame(0);
 
     // The window should have slided by 1 now and the previous 0th display frame
     // should have been removed from the deque
-    EXPECT_EQ(compareTimelineItems(displayFrame0->surfaceFlingerActuals, TimelineItem(52, 57, 62)),
-              true);
+    EXPECT_EQ(compareTimelineItems(displayFrame0->getActuals(), TimelineItem(52, 57, 62)), true);
 }
 
 TEST_F(FrameTimelineTest, surfaceFrameEndTimeAcquireFenceAfterQueue) {
-    auto surfaceFrame =
-            mFrameTimeline->createSurfaceFrameForToken(sPidOne, 0, "acquireFenceAfterQueue",
-                                                       "acquireFenceAfterQueue", std::nullopt);
+    auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken(std::nullopt, sPidOne, 0,
+                                                                   "acquireFenceAfterQueue",
+                                                                   "acquireFenceAfterQueue");
     surfaceFrame->setActualQueueTime(123);
     surfaceFrame->setAcquireFenceTime(456);
     EXPECT_EQ(surfaceFrame->getActuals().endTime, 456);
 }
 
 TEST_F(FrameTimelineTest, surfaceFrameEndTimeAcquireFenceBeforeQueue) {
-    auto surfaceFrame =
-            mFrameTimeline->createSurfaceFrameForToken(sPidOne, 0, "acquireFenceAfterQueue",
-                                                       "acquireFenceAfterQueue", std::nullopt);
+    auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken(std::nullopt, sPidOne, 0,
+                                                                   "acquireFenceAfterQueue",
+                                                                   "acquireFenceAfterQueue");
     surfaceFrame->setActualQueueTime(456);
     surfaceFrame->setAcquireFenceTime(123);
     EXPECT_EQ(surfaceFrame->getActuals().endTime, 456);
 }
 
 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);
 
     // Size shouldn't exceed maxDisplayFrames - 64
     for (size_t i = 0; i < *maxDisplayFrames + 10; i++) {
         auto surfaceFrame =
-                mFrameTimeline->createSurfaceFrameForToken(sPidOne, sUidOne, sLayerNameOne,
-                                                           sLayerNameOne, std::nullopt);
+                mFrameTimeline->createSurfaceFrameForToken(std::nullopt, sPidOne, sUidOne,
+                                                           sLayerNameOne, sLayerNameOne);
         int64_t sfToken = mTokenManager->generateTokenForPredictions({22, 26, 30});
-        mFrameTimeline->setSfWakeUp(sfToken, 22);
-        mFrameTimeline->addSurfaceFrame(surfaceFrame,
-                                        SurfaceFrame::PresentState::Presented);
+        mFrameTimeline->setSfWakeUp(sfToken, 22, 11);
+        surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented);
+        mFrameTimeline->addSurfaceFrame(surfaceFrame);
         mFrameTimeline->setSfPresent(27, presentFence);
     }
     EXPECT_EQ(getNumberOfDisplayFrames(), *maxDisplayFrames);
@@ -351,15 +377,18 @@
     // Increase the size to 256
     mFrameTimeline->setMaxDisplayFrames(256);
     EXPECT_EQ(*maxDisplayFrames, 256);
+    // 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, std::nullopt);
+                mFrameTimeline->createSurfaceFrameForToken(std::nullopt, sPidOne, sUidOne,
+                                                           sLayerNameOne, sLayerNameOne);
         int64_t sfToken = mTokenManager->generateTokenForPredictions({22, 26, 30});
-        mFrameTimeline->setSfWakeUp(sfToken, 22);
-        mFrameTimeline->addSurfaceFrame(surfaceFrame,
-                                        SurfaceFrame::PresentState::Presented);
+        mFrameTimeline->setSfWakeUp(sfToken, 22, 11);
+        surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented);
+        mFrameTimeline->addSurfaceFrame(surfaceFrame);
         mFrameTimeline->setSfPresent(27, presentFence);
     }
     EXPECT_EQ(getNumberOfDisplayFrames(), *maxDisplayFrames);
@@ -367,26 +396,30 @@
     // Shrink the size to 128
     mFrameTimeline->setMaxDisplayFrames(128);
     EXPECT_EQ(*maxDisplayFrames, 128);
+    // 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, std::nullopt);
+                mFrameTimeline->createSurfaceFrameForToken(std::nullopt, sPidOne, sUidOne,
+                                                           sLayerNameOne, sLayerNameOne);
         int64_t sfToken = mTokenManager->generateTokenForPredictions({22, 26, 30});
-        mFrameTimeline->setSfWakeUp(sfToken, 22);
-        mFrameTimeline->addSurfaceFrame(surfaceFrame,
-                                        SurfaceFrame::PresentState::Presented);
+        mFrameTimeline->setSfWakeUp(sfToken, 22, 11);
+        surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented);
+        mFrameTimeline->addSurfaceFrame(surfaceFrame);
         mFrameTimeline->setSfPresent(27, presentFence);
     }
     EXPECT_EQ(getNumberOfDisplayFrames(), *maxDisplayFrames);
 }
 
+// Tests related to TimeStats
 TEST_F(FrameTimelineTest, presentFenceSignaled_reportsLongSfCpu) {
     EXPECT_CALL(*mTimeStats,
                 incrementJankyFrames(sUidOne, sLayerNameOne,
-                                     HasBit(JankType::SurfaceFlingerDeadlineMissed)));
+                                     HasBit(JankType::SurfaceFlingerCpuDeadlineMissed)));
     EXPECT_CALL(*mTimeStats,
-                incrementJankyFrames(HasBit(JankType::SurfaceFlingerDeadlineMissed)));
+                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(),
@@ -397,12 +430,13 @@
              std::chrono::duration_cast<std::chrono::nanoseconds>(56ms).count(),
              std::chrono::duration_cast<std::chrono::nanoseconds>(60ms).count()});
     auto surfaceFrame1 =
-            mFrameTimeline->createSurfaceFrameForToken(sPidOne, sUidOne, sLayerNameOne,
-                                                       sLayerNameOne, surfaceFrameToken1);
+            mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken1, sPidOne, sUidOne,
+                                                       sLayerNameOne, sLayerNameOne);
     mFrameTimeline->setSfWakeUp(sfToken1,
-                                std::chrono::duration_cast<std::chrono::nanoseconds>(52ms).count());
-    mFrameTimeline->addSurfaceFrame(surfaceFrame1,
-                                    SurfaceFrame::PresentState::Presented);
+                                std::chrono::duration_cast<std::chrono::nanoseconds>(52ms).count(),
+                                11);
+    surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
+    mFrameTimeline->addSurfaceFrame(surfaceFrame1);
     presentFence1->signalForTest(
             std::chrono::duration_cast<std::chrono::nanoseconds>(70ms).count());
 
@@ -412,8 +446,9 @@
 
 TEST_F(FrameTimelineTest, presentFenceSignaled_reportsDisplayMiss) {
     EXPECT_CALL(*mTimeStats,
-                incrementJankyFrames(sUidOne, sLayerNameOne, HasBit(JankType::Display)));
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(HasBit(JankType::Display)));
+                incrementJankyFrames(sUidOne, sLayerNameOne, HasBit(JankType::DisplayHAL)));
+    EXPECT_CALL(*mTimeStats, incrementJankyFrames(HasBit(JankType::DisplayHAL)));
+
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions(
             {std::chrono::duration_cast<std::chrono::nanoseconds>(10ms).count(),
@@ -424,18 +459,18 @@
              std::chrono::duration_cast<std::chrono::nanoseconds>(56ms).count(),
              std::chrono::duration_cast<std::chrono::nanoseconds>(60ms).count()});
     auto surfaceFrame1 =
-            mFrameTimeline->createSurfaceFrameForToken(sPidOne, sUidOne, sLayerNameOne,
-                                                       sLayerNameOne, surfaceFrameToken1);
+            mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken1, sPidOne, sUidOne,
+                                                       sLayerNameOne, sLayerNameOne);
     mFrameTimeline->setSfWakeUp(sfToken1,
-                                std::chrono::duration_cast<std::chrono::nanoseconds>(52ms).count());
-    mFrameTimeline->addSurfaceFrame(surfaceFrame1,
-                                    SurfaceFrame::PresentState::Presented);
+                                std::chrono::duration_cast<std::chrono::nanoseconds>(52ms).count(),
+                                30);
+    surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
+    mFrameTimeline->addSurfaceFrame(surfaceFrame1);
     presentFence1->signalForTest(
             std::chrono::duration_cast<std::chrono::nanoseconds>(90ms).count());
-    mFrameTimeline->setSfPresent(std::chrono::duration_cast<std::chrono::nanoseconds>(59ms).count(),
+    mFrameTimeline->setSfPresent(std::chrono::duration_cast<std::chrono::nanoseconds>(56ms).count(),
                                  presentFence1);
-    EXPECT_NE(surfaceFrame1->getJankType(), std::nullopt);
-    EXPECT_TRUE((surfaceFrame1->getJankType().value() & JankType::Display) != 0);
+    EXPECT_EQ(surfaceFrame1->getJankType(), JankType::DisplayHAL);
 }
 
 TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppMiss) {
@@ -449,26 +484,26 @@
              std::chrono::duration_cast<std::chrono::nanoseconds>(20ms).count(),
              std::chrono::duration_cast<std::chrono::nanoseconds>(60ms).count()});
     int64_t sfToken1 = mTokenManager->generateTokenForPredictions(
-            {std::chrono::duration_cast<std::chrono::nanoseconds>(52ms).count(),
-             std::chrono::duration_cast<std::chrono::nanoseconds>(56ms).count(),
-             std::chrono::duration_cast<std::chrono::nanoseconds>(60ms).count()});
+            {std::chrono::duration_cast<std::chrono::nanoseconds>(82ms).count(),
+             std::chrono::duration_cast<std::chrono::nanoseconds>(86ms).count(),
+             std::chrono::duration_cast<std::chrono::nanoseconds>(90ms).count()});
     auto surfaceFrame1 =
-            mFrameTimeline->createSurfaceFrameForToken(sPidOne, sUidOne, sLayerNameOne,
-                                                       sLayerNameOne, surfaceFrameToken1);
+            mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken1, sPidOne, sUidOne,
+                                                       sLayerNameOne, sLayerNameOne);
     surfaceFrame1->setAcquireFenceTime(
             std::chrono::duration_cast<std::chrono::nanoseconds>(45ms).count());
     mFrameTimeline->setSfWakeUp(sfToken1,
-                                std::chrono::duration_cast<std::chrono::nanoseconds>(52ms).count());
+                                std::chrono::duration_cast<std::chrono::nanoseconds>(52ms).count(),
+                                11);
 
-    mFrameTimeline->addSurfaceFrame(surfaceFrame1,
-                                    SurfaceFrame::PresentState::Presented);
+    surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
+    mFrameTimeline->addSurfaceFrame(surfaceFrame1);
     presentFence1->signalForTest(
             std::chrono::duration_cast<std::chrono::nanoseconds>(90ms).count());
-    mFrameTimeline->setSfPresent(std::chrono::duration_cast<std::chrono::nanoseconds>(56ms).count(),
+    mFrameTimeline->setSfPresent(std::chrono::duration_cast<std::chrono::nanoseconds>(86ms).count(),
                                  presentFence1);
 
-    EXPECT_NE(surfaceFrame1->getJankType(), std::nullopt);
-    EXPECT_TRUE((surfaceFrame1->getJankType().value() & JankType::AppDeadlineMissed) != 0);
+    EXPECT_EQ(surfaceFrame1->getJankType(), JankType::AppDeadlineMissed);
 }
 
 /*
@@ -481,23 +516,26 @@
  */
 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);
 
     int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30});
     int64_t token2 = mTokenManager->generateTokenForPredictions({40, 50, 60});
-    auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken(sPidOne, sUidOne, sLayerNameOne,
-                                                                    sLayerNameOne, token1);
+    auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken(token1, sPidOne, sUidOne,
+                                                                    sLayerNameOne, sLayerNameOne);
 
     // Set up the display frame
-    mFrameTimeline->setSfWakeUp(token1, 20);
-    mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame1), SurfaceFrame::PresentState::Dropped);
+    mFrameTimeline->setSfWakeUp(token1, 20, 11);
+    surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Dropped);
+    mFrameTimeline->addSurfaceFrame(surfaceFrame1);
     mFrameTimeline->setSfPresent(25, presentFence1);
     presentFence1->signalForTest(30);
 
     // Trigger a flushPresentFence (which will call trace function) by calling setSfPresent for the
     // next frame
-    mFrameTimeline->setSfWakeUp(token2, 50);
+    mFrameTimeline->setSfWakeUp(token2, 50, 11);
     mFrameTimeline->setSfPresent(55, presentFence2);
 
     auto packets = readFrameTimelinePacketsBlocking(tracingSession.get());
@@ -506,25 +544,29 @@
 
 TEST_F(FrameTimelineTest, tracing_sanityTest) {
     auto tracingSession = getTracingSessionForTest();
+    // Global increment
+    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_)).Times(2);
+    // Layer specific increment
+    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_, testing::_, testing::_));
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
 
     tracingSession->StartBlocking();
     int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30});
     int64_t token2 = mTokenManager->generateTokenForPredictions({40, 50, 60});
-    auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken(sPidOne, sUidOne, sLayerNameOne,
-                                                                    sLayerNameOne, token1);
+    auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken(token1, sPidOne, sUidOne,
+                                                                    sLayerNameOne, sLayerNameOne);
 
     // Set up the display frame
-    mFrameTimeline->setSfWakeUp(token2, 20);
-    mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame1),
-                                    SurfaceFrame::PresentState::Presented);
+    mFrameTimeline->setSfWakeUp(token2, 20, 11);
+    surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
+    mFrameTimeline->addSurfaceFrame(surfaceFrame1);
     mFrameTimeline->setSfPresent(25, presentFence1);
     presentFence1->signalForTest(30);
 
     // Trigger a flushPresentFence (which will call trace function) by calling setSfPresent for the
     // next frame
-    mFrameTimeline->setSfWakeUp(token2, 50);
+    mFrameTimeline->setSfWakeUp(token2, 50, 11);
     mFrameTimeline->setSfPresent(55, presentFence2);
     presentFence2->signalForTest(55);
 
@@ -543,6 +585,8 @@
 
 TEST_F(FrameTimelineTest, traceDisplayFrame_invalidTokenDoesNotEmitTracePacket) {
     auto tracingSession = getTracingSessionForTest();
+    // Global increment
+    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_)).Times(2);
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
 
@@ -550,13 +594,13 @@
     int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30});
 
     // Set up the display frame
-    mFrameTimeline->setSfWakeUp(-1, 20);
+    mFrameTimeline->setSfWakeUp(-1, 20, 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);
+    mFrameTimeline->setSfWakeUp(token1, 50, 11);
     mFrameTimeline->setSfPresent(55, presentFence2);
     presentFence2->signalForTest(60);
 
@@ -572,24 +616,27 @@
 
 TEST_F(FrameTimelineTest, traceSurfaceFrame_invalidTokenDoesNotEmitTracePacket) {
     auto tracingSession = getTracingSessionForTest();
+    // Global increment
+    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_)).Times(2);
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
 
     tracingSession->StartBlocking();
     int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30});
     int64_t token2 = mTokenManager->generateTokenForPredictions({40, 50, 60});
-    auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken(sPidOne, sUidOne, sLayerNameOne,
-                                                                    sLayerNameOne, std::nullopt);
+    auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken(std::nullopt, sPidOne, sUidOne,
+                                                                    sLayerNameOne, sLayerNameOne);
 
     // Set up the display frame
-    mFrameTimeline->setSfWakeUp(token1, 20);
-    mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame1), SurfaceFrame::PresentState::Dropped);
+    mFrameTimeline->setSfWakeUp(token1, 20, 11);
+    surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Dropped);
+    mFrameTimeline->addSurfaceFrame(surfaceFrame1);
     mFrameTimeline->setSfPresent(25, presentFence1);
     presentFence1->signalForTest(30);
 
     // Trigger a flushPresentFence (which will call trace function) by calling setSfPresent for the
     // next frame
-    mFrameTimeline->setSfWakeUp(token2, 50);
+    mFrameTimeline->setSfWakeUp(token2, 50, 11);
     mFrameTimeline->setSfPresent(55, presentFence2);
     presentFence2->signalForTest(60);
 
@@ -662,6 +709,8 @@
 
 TEST_F(FrameTimelineTest, traceDisplayFrame_emitsValidTracePacket) {
     auto tracingSession = getTracingSessionForTest();
+    // Global increment
+    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_)).Times(2);
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
 
@@ -670,7 +719,7 @@
     int64_t displayFrameToken2 = mTokenManager->generateTokenForPredictions({40, 50, 60});
 
     // Set up the display frame
-    mFrameTimeline->setSfWakeUp(displayFrameToken1, 20);
+    mFrameTimeline->setSfWakeUp(displayFrameToken1, 20, 11);
     mFrameTimeline->setSfPresent(26, presentFence1);
     presentFence1->signalForTest(31);
 
@@ -687,7 +736,7 @@
 
     // Trigger a flushPresentFence (which will call trace function) by calling setSfPresent for the
     // next frame
-    mFrameTimeline->setSfWakeUp(displayFrameToken2, 50);
+    mFrameTimeline->setSfWakeUp(displayFrameToken2, 50, 11);
     mFrameTimeline->setSfPresent(55, presentFence2);
     presentFence2->signalForTest(55);
 
@@ -713,6 +762,10 @@
 
 TEST_F(FrameTimelineTest, traceSurfaceFrame_emitsValidTracePacket) {
     auto tracingSession = getTracingSessionForTest();
+    // Global increment
+    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_)).Times(2);
+    // Layer specific increment
+    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_, testing::_, testing::_));
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
 
@@ -722,8 +775,8 @@
     int64_t displayFrameToken2 = mTokenManager->generateTokenForPredictions({40, 50, 60});
 
     auto surfaceFrame1 =
-            mFrameTimeline->createSurfaceFrameForToken(sPidOne, sUidOne, sLayerNameOne,
-                                                       sLayerNameOne, surfaceFrameToken);
+            mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken, sPidOne, sUidOne,
+                                                       sLayerNameOne, sLayerNameOne);
     surfaceFrame1->setActualStartTime(0);
     surfaceFrame1->setActualQueueTime(15);
     surfaceFrame1->setAcquireFenceTime(20);
@@ -743,15 +796,15 @@
     protoSurfaceFrame.set_pid(sPidOne);
 
     // Set up the display frame
-    mFrameTimeline->setSfWakeUp(displayFrameToken1, 20);
-    mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame1),
-                                    SurfaceFrame::PresentState::Presented);
+    mFrameTimeline->setSfWakeUp(displayFrameToken1, 20, 11);
+    surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
+    mFrameTimeline->addSurfaceFrame(surfaceFrame1);
     mFrameTimeline->setSfPresent(26, presentFence1);
-    presentFence1->signalForTest(31);
+    presentFence1->signalForTest(40);
 
     // Trigger a flushPresentFence (which will call trace function) by calling setSfPresent for the
     // next frame
-    mFrameTimeline->setSfWakeUp(displayFrameToken2, 50);
+    mFrameTimeline->setSfWakeUp(displayFrameToken2, 50, 11);
     mFrameTimeline->setSfPresent(55, presentFence2);
     presentFence2->signalForTest(55);
 
@@ -775,4 +828,508 @@
     validateSurfaceFrameEvent(surfaceFrameEvent, protoSurfaceFrame);
 }
 
+// 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::_));
+    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, sPidOne, sUidOne,
+                                                       sLayerNameOne, sLayerNameOne);
+    mFrameTimeline->setSfWakeUp(sfToken1, 22, 11);
+    surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented);
+    mFrameTimeline->addSurfaceFrame(surfaceFrame);
+    mFrameTimeline->setSfPresent(26, presentFence1);
+    auto displayFrame = getDisplayFrame(0);
+    auto& presentedSurfaceFrame = getSurfaceFrame(0, 0);
+    presentFence1->signalForTest(29);
+
+    // Fences haven't been flushed yet, so it should be 0
+    EXPECT_EQ(displayFrame->getActuals().presentTime, 0);
+    EXPECT_EQ(presentedSurfaceFrame.getActuals().presentTime, 0);
+
+    addEmptyDisplayFrame();
+    displayFrame = getDisplayFrame(0);
+
+    // Fences have flushed, so the present timestamps should be updated
+    EXPECT_EQ(displayFrame->getActuals().presentTime, 29);
+    EXPECT_EQ(presentedSurfaceFrame.getActuals().presentTime, 29);
+    EXPECT_EQ(displayFrame->getFramePresentMetadata(), FramePresentMetadata::OnTimePresent);
+    EXPECT_EQ(displayFrame->getFrameReadyMetadata(), FrameReadyMetadata::OnTimeFinish);
+    EXPECT_EQ(displayFrame->getJankType(), JankType::None);
+}
+
+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->setSfPresent(26, presentFence1);
+    auto displayFrame = getDisplayFrame(0);
+    presentFence1->signalForTest(30);
+
+    // Fences for the first frame haven't been flushed yet, so it should be 0
+    EXPECT_EQ(displayFrame->getActuals().presentTime, 0);
+
+    // Trigger a flush by finalizing the next DisplayFrame
+    auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+    mFrameTimeline->setSfWakeUp(sfToken2, 52, 11);
+    mFrameTimeline->setSfPresent(56, presentFence2);
+    displayFrame = getDisplayFrame(0);
+
+    // Fences for the first frame have flushed, so the present timestamps should be updated
+    EXPECT_EQ(displayFrame->getActuals().presentTime, 30);
+    EXPECT_EQ(displayFrame->getFramePresentMetadata(), FramePresentMetadata::EarlyPresent);
+    EXPECT_EQ(displayFrame->getFrameReadyMetadata(), FrameReadyMetadata::OnTimeFinish);
+    EXPECT_EQ(displayFrame->getJankType(), JankType::SurfaceFlingerScheduling);
+
+    // Fences for the second frame haven't been flushed yet, so it should be 0
+    auto displayFrame2 = getDisplayFrame(1);
+    presentFence2->signalForTest(65);
+    EXPECT_EQ(displayFrame2->getActuals().presentTime, 0);
+
+    addEmptyDisplayFrame();
+    displayFrame2 = getDisplayFrame(1);
+
+    // Fences for the second frame have flushed, so the present timestamps should be updated
+    EXPECT_EQ(displayFrame2->getActuals().presentTime, 65);
+    EXPECT_EQ(displayFrame2->getFramePresentMetadata(), FramePresentMetadata::EarlyPresent);
+    EXPECT_EQ(displayFrame2->getFrameReadyMetadata(), FrameReadyMetadata::OnTimeFinish);
+    EXPECT_EQ(displayFrame2->getJankType(), JankType::PredictionError);
+}
+
+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->setSfPresent(26, presentFence1);
+    auto displayFrame = getDisplayFrame(0);
+    presentFence1->signalForTest(50);
+
+    // Fences for the first frame haven't been flushed yet, so it should be 0
+    EXPECT_EQ(displayFrame->getActuals().presentTime, 0);
+
+    // Trigger a flush by finalizing the next DisplayFrame
+    auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+    mFrameTimeline->setSfWakeUp(sfToken2, 52, 11);
+    mFrameTimeline->setSfPresent(56, presentFence2);
+    displayFrame = getDisplayFrame(0);
+
+    // Fences for the first frame have flushed, so the present timestamps should be updated
+    EXPECT_EQ(displayFrame->getActuals().presentTime, 50);
+    EXPECT_EQ(displayFrame->getFramePresentMetadata(), FramePresentMetadata::LatePresent);
+    EXPECT_EQ(displayFrame->getFrameReadyMetadata(), FrameReadyMetadata::OnTimeFinish);
+    EXPECT_EQ(displayFrame->getJankType(), JankType::DisplayHAL);
+
+    // Fences for the second frame haven't been flushed yet, so it should be 0
+    auto displayFrame2 = getDisplayFrame(1);
+    presentFence2->signalForTest(75);
+    EXPECT_EQ(displayFrame2->getActuals().presentTime, 0);
+
+    addEmptyDisplayFrame();
+    displayFrame2 = getDisplayFrame(1);
+
+    // Fences for the second frame have flushed, so the present timestamps should be updated
+    EXPECT_EQ(displayFrame2->getActuals().presentTime, 75);
+    EXPECT_EQ(displayFrame2->getFramePresentMetadata(), FramePresentMetadata::LatePresent);
+    EXPECT_EQ(displayFrame2->getFrameReadyMetadata(), FrameReadyMetadata::OnTimeFinish);
+    EXPECT_EQ(displayFrame2->getJankType(), JankType::PredictionError);
+}
+
+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->setSfPresent(22, presentFence1);
+    auto displayFrame = getDisplayFrame(0);
+    presentFence1->signalForTest(28);
+
+    // Fences haven't been flushed yet, so it should be 0
+    EXPECT_EQ(displayFrame->getActuals().presentTime, 0);
+
+    addEmptyDisplayFrame();
+    displayFrame = getDisplayFrame(0);
+
+    // Fences have flushed, so the present timestamps should be updated
+    EXPECT_EQ(displayFrame->getActuals().presentTime, 28);
+    EXPECT_EQ(displayFrame->getFramePresentMetadata(), FramePresentMetadata::EarlyPresent);
+    EXPECT_EQ(displayFrame->getFrameReadyMetadata(), FrameReadyMetadata::LateFinish);
+    EXPECT_EQ(displayFrame->getJankType(), JankType::SurfaceFlingerScheduling);
+}
+
+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->setSfPresent(36, presentFence1);
+    auto displayFrame = getDisplayFrame(0);
+    presentFence1->signalForTest(52);
+
+    // Fences haven't been flushed yet, so it should be 0
+    EXPECT_EQ(displayFrame->getActuals().presentTime, 0);
+
+    addEmptyDisplayFrame();
+    displayFrame = getDisplayFrame(0);
+
+    // Fences have flushed, so the present timestamps should be updated
+    EXPECT_EQ(displayFrame->getActuals().presentTime, 52);
+    EXPECT_EQ(displayFrame->getFramePresentMetadata(), FramePresentMetadata::LatePresent);
+    EXPECT_EQ(displayFrame->getFrameReadyMetadata(), FrameReadyMetadata::LateFinish);
+    EXPECT_EQ(displayFrame->getJankType(), JankType::SurfaceFlingerCpuDeadlineMissed);
+}
+
+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);
+    auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+    int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 40});
+    int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 56, 70});
+    int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({5, 16, 40});
+    int64_t surfaceFrameToken2 = mTokenManager->generateTokenForPredictions({25, 36, 70});
+    auto surfaceFrame1 =
+            mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken1, sPidOne, sUidOne,
+                                                       sLayerNameOne, sLayerNameOne);
+    surfaceFrame1->setAcquireFenceTime(16);
+    mFrameTimeline->setSfWakeUp(sfToken1, 22, 11);
+    surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
+    mFrameTimeline->addSurfaceFrame(surfaceFrame1);
+    mFrameTimeline->setSfPresent(26, presentFence1);
+    auto displayFrame1 = getDisplayFrame(0);
+    auto& presentedSurfaceFrame1 = getSurfaceFrame(0, 0);
+    presentFence1->signalForTest(30);
+
+    // Fences for the first frame haven't been flushed yet, so it should be 0
+    EXPECT_EQ(displayFrame1->getActuals().presentTime, 0);
+    auto actuals1 = presentedSurfaceFrame1.getActuals();
+    EXPECT_EQ(actuals1.presentTime, 0);
+
+    // Trigger a flush by finalizing the next DisplayFrame
+    auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+    auto surfaceFrame2 =
+            mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken2, sPidOne, sUidOne,
+                                                       sLayerNameOne, sLayerNameOne);
+    surfaceFrame2->setAcquireFenceTime(36);
+    mFrameTimeline->setSfWakeUp(sfToken2, 52, 11);
+    surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented);
+    mFrameTimeline->addSurfaceFrame(surfaceFrame2);
+    mFrameTimeline->setSfPresent(56, presentFence2);
+    auto displayFrame2 = getDisplayFrame(1);
+    auto& presentedSurfaceFrame2 = getSurfaceFrame(1, 0);
+
+    // Fences for the first frame have flushed, so the present timestamps should be updated
+    EXPECT_EQ(displayFrame1->getActuals().presentTime, 30);
+    EXPECT_EQ(displayFrame1->getFramePresentMetadata(), FramePresentMetadata::EarlyPresent);
+    EXPECT_EQ(displayFrame1->getFrameReadyMetadata(), FrameReadyMetadata::OnTimeFinish);
+    EXPECT_EQ(displayFrame1->getJankType(), JankType::SurfaceFlingerScheduling);
+
+    actuals1 = presentedSurfaceFrame1.getActuals();
+    EXPECT_EQ(actuals1.presentTime, 30);
+    EXPECT_EQ(presentedSurfaceFrame1.getFramePresentMetadata(), FramePresentMetadata::EarlyPresent);
+    EXPECT_EQ(presentedSurfaceFrame1.getFrameReadyMetadata(), FrameReadyMetadata::OnTimeFinish);
+    EXPECT_EQ(presentedSurfaceFrame1.getJankType(), JankType::SurfaceFlingerScheduling);
+
+    // Fences for the second frame haven't been flushed yet, so it should be 0
+    presentFence2->signalForTest(65);
+    EXPECT_EQ(displayFrame2->getActuals().presentTime, 0);
+    auto actuals2 = presentedSurfaceFrame2.getActuals();
+    EXPECT_EQ(actuals2.presentTime, 0);
+
+    addEmptyDisplayFrame();
+
+    // Fences for the second frame have flushed, so the present timestamps should be updated
+    EXPECT_EQ(displayFrame2->getActuals().presentTime, 65);
+    EXPECT_EQ(displayFrame2->getFramePresentMetadata(), FramePresentMetadata::EarlyPresent);
+    EXPECT_EQ(displayFrame2->getFrameReadyMetadata(), FrameReadyMetadata::OnTimeFinish);
+    EXPECT_EQ(displayFrame2->getJankType(), JankType::PredictionError);
+
+    actuals2 = presentedSurfaceFrame2.getActuals();
+    EXPECT_EQ(actuals2.presentTime, 65);
+    EXPECT_EQ(presentedSurfaceFrame2.getFramePresentMetadata(), FramePresentMetadata::EarlyPresent);
+    EXPECT_EQ(presentedSurfaceFrame2.getFrameReadyMetadata(), FrameReadyMetadata::OnTimeFinish);
+    EXPECT_EQ(presentedSurfaceFrame2.getJankType(), JankType::PredictionError);
+}
+
+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);
+    auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+    int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 40});
+    int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 56, 70});
+    int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({5, 16, 40});
+    int64_t surfaceFrameToken2 = mTokenManager->generateTokenForPredictions({25, 36, 70});
+    auto surfaceFrame1 =
+            mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken1, sPidOne, sUidOne,
+                                                       sLayerNameOne, sLayerNameOne);
+    surfaceFrame1->setAcquireFenceTime(16);
+    mFrameTimeline->setSfWakeUp(sfToken1, 22, 11);
+    surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
+    mFrameTimeline->addSurfaceFrame(surfaceFrame1);
+    mFrameTimeline->setSfPresent(26, presentFence1);
+    auto displayFrame1 = getDisplayFrame(0);
+    auto& presentedSurfaceFrame1 = getSurfaceFrame(0, 0);
+    presentFence1->signalForTest(50);
+
+    // Fences for the first frame haven't been flushed yet, so it should be 0
+    EXPECT_EQ(displayFrame1->getActuals().presentTime, 0);
+    auto actuals1 = presentedSurfaceFrame1.getActuals();
+    EXPECT_EQ(actuals1.presentTime, 0);
+
+    // Trigger a flush by finalizing the next DisplayFrame
+    auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+    auto surfaceFrame2 =
+            mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken2, sPidOne, sUidOne,
+                                                       sLayerNameOne, sLayerNameOne);
+    surfaceFrame2->setAcquireFenceTime(36);
+    mFrameTimeline->setSfWakeUp(sfToken2, 52, 11);
+    surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented);
+    mFrameTimeline->addSurfaceFrame(surfaceFrame2);
+    mFrameTimeline->setSfPresent(56, presentFence2);
+    auto displayFrame2 = getDisplayFrame(1);
+    auto& presentedSurfaceFrame2 = getSurfaceFrame(1, 0);
+
+    // Fences for the first frame have flushed, so the present timestamps should be updated
+    EXPECT_EQ(displayFrame1->getActuals().presentTime, 50);
+    EXPECT_EQ(displayFrame1->getFramePresentMetadata(), FramePresentMetadata::LatePresent);
+    EXPECT_EQ(displayFrame1->getFrameReadyMetadata(), FrameReadyMetadata::OnTimeFinish);
+    EXPECT_EQ(displayFrame1->getJankType(), JankType::DisplayHAL);
+
+    actuals1 = presentedSurfaceFrame1.getActuals();
+    EXPECT_EQ(actuals1.presentTime, 50);
+    EXPECT_EQ(presentedSurfaceFrame1.getFramePresentMetadata(), FramePresentMetadata::LatePresent);
+    EXPECT_EQ(presentedSurfaceFrame1.getFrameReadyMetadata(), FrameReadyMetadata::OnTimeFinish);
+    EXPECT_EQ(presentedSurfaceFrame1.getJankType(), JankType::DisplayHAL);
+
+    // Fences for the second frame haven't been flushed yet, so it should be 0
+    presentFence2->signalForTest(86);
+    EXPECT_EQ(displayFrame2->getActuals().presentTime, 0);
+    auto actuals2 = presentedSurfaceFrame2.getActuals();
+    EXPECT_EQ(actuals2.presentTime, 0);
+
+    addEmptyDisplayFrame();
+
+    // Fences for the second frame have flushed, so the present timestamps should be updated
+    EXPECT_EQ(displayFrame2->getActuals().presentTime, 86);
+    EXPECT_EQ(displayFrame2->getFramePresentMetadata(), FramePresentMetadata::LatePresent);
+    EXPECT_EQ(displayFrame2->getFrameReadyMetadata(), FrameReadyMetadata::OnTimeFinish);
+    EXPECT_EQ(displayFrame2->getJankType(), JankType::PredictionError);
+
+    actuals2 = presentedSurfaceFrame2.getActuals();
+    EXPECT_EQ(actuals2.presentTime, 86);
+    EXPECT_EQ(presentedSurfaceFrame2.getFramePresentMetadata(), FramePresentMetadata::LatePresent);
+    EXPECT_EQ(presentedSurfaceFrame2.getFrameReadyMetadata(), FrameReadyMetadata::OnTimeFinish);
+    EXPECT_EQ(presentedSurfaceFrame2.getJankType(), JankType::PredictionError);
+}
+
+TEST_F(FrameTimelineTest, jankClassification_surfaceFrameLateFinishEarlyPresent) {
+    // Global increment
+    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_));
+    // Layer specific increment
+    EXPECT_CALL(*mTimeStats, incrementJankyFrames(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});
+    auto surfaceFrame1 =
+            mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken1, sPidOne, sUidOne,
+                                                       sLayerNameOne, sLayerNameOne);
+    surfaceFrame1->setAcquireFenceTime(40);
+    mFrameTimeline->setSfWakeUp(sfToken1, 42, 11);
+    surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
+    mFrameTimeline->addSurfaceFrame(surfaceFrame1);
+    mFrameTimeline->setSfPresent(46, presentFence1);
+    auto displayFrame1 = getDisplayFrame(0);
+    auto& presentedSurfaceFrame1 = getSurfaceFrame(0, 0);
+    presentFence1->signalForTest(50);
+
+    // Fences for the first frame haven't been flushed yet, so it should be 0
+    EXPECT_EQ(displayFrame1->getActuals().presentTime, 0);
+    auto actuals1 = presentedSurfaceFrame1.getActuals();
+    EXPECT_EQ(actuals1.presentTime, 0);
+
+    addEmptyDisplayFrame();
+
+    // Fences for the first frame have flushed, so the present timestamps should be updated
+    EXPECT_EQ(displayFrame1->getActuals().presentTime, 50);
+    EXPECT_EQ(displayFrame1->getFramePresentMetadata(), FramePresentMetadata::OnTimePresent);
+    EXPECT_EQ(displayFrame1->getFrameReadyMetadata(), FrameReadyMetadata::OnTimeFinish);
+    EXPECT_EQ(displayFrame1->getJankType(), JankType::None);
+
+    actuals1 = presentedSurfaceFrame1.getActuals();
+    EXPECT_EQ(actuals1.presentTime, 50);
+    EXPECT_EQ(presentedSurfaceFrame1.getFramePresentMetadata(), FramePresentMetadata::EarlyPresent);
+    EXPECT_EQ(presentedSurfaceFrame1.getFrameReadyMetadata(), FrameReadyMetadata::LateFinish);
+    EXPECT_EQ(presentedSurfaceFrame1.getJankType(), JankType::Unknown);
+}
+
+TEST_F(FrameTimelineTest, jankClassification_surfaceFrameLateFinishLatePresent) {
+    // First frame - DisplayFrame is not janky. This should classify the SurfaceFrame as
+    // 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);
+    auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+    int64_t sfToken1 = mTokenManager->generateTokenForPredictions({32, 36, 40});
+    int64_t sfToken2 = mTokenManager->generateTokenForPredictions({42, 46, 50});
+    int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({5, 16, 30});
+    int64_t surfaceFrameToken2 = mTokenManager->generateTokenForPredictions({25, 36, 50});
+    auto surfaceFrame1 =
+            mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken1, sPidOne, sUidOne,
+                                                       sLayerNameOne, sLayerNameOne);
+    surfaceFrame1->setAcquireFenceTime(26);
+    mFrameTimeline->setSfWakeUp(sfToken1, 32, 11);
+    surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
+    mFrameTimeline->addSurfaceFrame(surfaceFrame1);
+    mFrameTimeline->setSfPresent(36, presentFence1);
+    auto displayFrame1 = getDisplayFrame(0);
+    auto& presentedSurfaceFrame1 = getSurfaceFrame(0, 0);
+    presentFence1->signalForTest(40);
+
+    // Fences for the first frame haven't been flushed yet, so it should be 0
+    EXPECT_EQ(displayFrame1->getActuals().presentTime, 0);
+    auto actuals1 = presentedSurfaceFrame1.getActuals();
+    EXPECT_EQ(actuals1.presentTime, 0);
+
+    // Trigger a flush by finalizing the next DisplayFrame
+    auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+    auto surfaceFrame2 =
+            mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken2, sPidOne, sUidOne,
+                                                       sLayerNameOne, sLayerNameOne);
+    surfaceFrame2->setAcquireFenceTime(40);
+    mFrameTimeline->setSfWakeUp(sfToken2, 43, 11);
+    surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented);
+    mFrameTimeline->addSurfaceFrame(surfaceFrame2);
+    mFrameTimeline->setSfPresent(56, presentFence2);
+    auto displayFrame2 = getDisplayFrame(1);
+    auto& presentedSurfaceFrame2 = getSurfaceFrame(1, 0);
+
+    // Fences for the first frame have flushed, so the present timestamps should be updated
+    EXPECT_EQ(displayFrame1->getActuals().presentTime, 40);
+    EXPECT_EQ(displayFrame1->getFramePresentMetadata(), FramePresentMetadata::OnTimePresent);
+    EXPECT_EQ(displayFrame1->getFrameReadyMetadata(), FrameReadyMetadata::OnTimeFinish);
+    EXPECT_EQ(displayFrame1->getJankType(), JankType::None);
+
+    actuals1 = presentedSurfaceFrame1.getActuals();
+    EXPECT_EQ(actuals1.presentTime, 40);
+    EXPECT_EQ(presentedSurfaceFrame1.getFramePresentMetadata(), FramePresentMetadata::LatePresent);
+    EXPECT_EQ(presentedSurfaceFrame1.getFrameReadyMetadata(), FrameReadyMetadata::LateFinish);
+    EXPECT_EQ(presentedSurfaceFrame1.getJankType(), JankType::AppDeadlineMissed);
+
+    // Fences for the second frame haven't been flushed yet, so it should be 0
+    presentFence2->signalForTest(60);
+    EXPECT_EQ(displayFrame2->getActuals().presentTime, 0);
+    auto actuals2 = presentedSurfaceFrame2.getActuals();
+    EXPECT_EQ(actuals2.presentTime, 0);
+
+    addEmptyDisplayFrame();
+
+    // Fences for the second frame have flushed, so the present timestamps should be updated
+    EXPECT_EQ(displayFrame2->getActuals().presentTime, 60);
+    EXPECT_EQ(displayFrame2->getFramePresentMetadata(), FramePresentMetadata::LatePresent);
+    EXPECT_EQ(displayFrame2->getFrameReadyMetadata(), FrameReadyMetadata::LateFinish);
+    EXPECT_EQ(displayFrame2->getJankType(), JankType::SurfaceFlingerCpuDeadlineMissed);
+
+    actuals2 = presentedSurfaceFrame2.getActuals();
+    EXPECT_EQ(actuals2.presentTime, 60);
+    EXPECT_EQ(presentedSurfaceFrame2.getFramePresentMetadata(), FramePresentMetadata::LatePresent);
+    EXPECT_EQ(presentedSurfaceFrame2.getFrameReadyMetadata(), FrameReadyMetadata::LateFinish);
+    EXPECT_EQ(presentedSurfaceFrame2.getJankType(), JankType::SurfaceFlingerCpuDeadlineMissed);
+}
+
+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);
+    auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+    int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 30});
+    int64_t surfaceFrameToken2 = mTokenManager->generateTokenForPredictions({40, 50, 60});
+
+    int64_t sfToken1 = mTokenManager->generateTokenForPredictions({52, 56, 60});
+    int64_t sfToken2 = mTokenManager->generateTokenForPredictions({112, 116, 120});
+    auto surfaceFrame1 =
+            mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken1, sPidOne, sUidOne,
+                                                       sLayerNameOne, sLayerNameOne);
+    surfaceFrame1->setAcquireFenceTime(50);
+    mFrameTimeline->setSfWakeUp(sfToken1, 52, 30);
+    surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
+    mFrameTimeline->addSurfaceFrame(surfaceFrame1);
+    mFrameTimeline->setSfPresent(56, presentFence1);
+    auto displayFrame1 = getDisplayFrame(0);
+    auto& presentedSurfaceFrame1 = getSurfaceFrame(0, 0);
+    presentFence1->signalForTest(60);
+
+    // Fences for the first frame haven't been flushed yet, so it should be 0
+    EXPECT_EQ(displayFrame1->getActuals().presentTime, 0);
+    auto actuals1 = presentedSurfaceFrame1.getActuals();
+    EXPECT_EQ(actuals1.presentTime, 0);
+
+    // Trigger a flush by finalizing the next DisplayFrame
+    auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+    auto surfaceFrame2 =
+            mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken2, sPidOne, sUidOne,
+                                                       sLayerNameOne, sLayerNameOne);
+    surfaceFrame2->setAcquireFenceTime(84);
+    mFrameTimeline->setSfWakeUp(sfToken2, 112, 30);
+    surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented, 54);
+    mFrameTimeline->addSurfaceFrame(surfaceFrame2);
+    mFrameTimeline->setSfPresent(116, presentFence2);
+    auto displayFrame2 = getDisplayFrame(1);
+    auto& presentedSurfaceFrame2 = getSurfaceFrame(1, 0);
+    presentFence2->signalForTest(120);
+
+    // Fences for the first frame have flushed, so the present timestamps should be updated
+    EXPECT_EQ(displayFrame1->getActuals().presentTime, 60);
+    actuals1 = presentedSurfaceFrame1.getActuals();
+    EXPECT_EQ(actuals1.endTime, 50);
+    EXPECT_EQ(actuals1.presentTime, 60);
+
+    EXPECT_EQ(displayFrame1->getFramePresentMetadata(), FramePresentMetadata::OnTimePresent);
+    EXPECT_EQ(displayFrame1->getFrameReadyMetadata(), FrameReadyMetadata::OnTimeFinish);
+    EXPECT_EQ(displayFrame1->getJankType(), JankType::None);
+
+    EXPECT_EQ(presentedSurfaceFrame1.getFramePresentMetadata(), FramePresentMetadata::LatePresent);
+    EXPECT_EQ(presentedSurfaceFrame1.getFrameReadyMetadata(), FrameReadyMetadata::LateFinish);
+    EXPECT_EQ(presentedSurfaceFrame1.getJankType(), JankType::AppDeadlineMissed);
+
+    // Fences for the second frame haven't been flushed yet, so it should be 0
+    EXPECT_EQ(displayFrame2->getActuals().presentTime, 0);
+    auto actuals2 = presentedSurfaceFrame2.getActuals();
+    EXPECT_EQ(actuals2.presentTime, 0);
+
+    addEmptyDisplayFrame();
+
+    // Fences for the second frame have flushed, so the present timestamps should be updated
+    EXPECT_EQ(displayFrame2->getActuals().presentTime, 120);
+    actuals2 = presentedSurfaceFrame2.getActuals();
+    EXPECT_EQ(actuals2.presentTime, 120);
+
+    EXPECT_EQ(displayFrame2->getFramePresentMetadata(), FramePresentMetadata::OnTimePresent);
+    EXPECT_EQ(displayFrame2->getFrameReadyMetadata(), FrameReadyMetadata::OnTimeFinish);
+    EXPECT_EQ(displayFrame2->getJankType(), JankType::None);
+
+    EXPECT_EQ(presentedSurfaceFrame2.getFramePresentMetadata(), FramePresentMetadata::LatePresent);
+    EXPECT_EQ(presentedSurfaceFrame2.getFrameReadyMetadata(), FrameReadyMetadata::LateFinish);
+    EXPECT_EQ(presentedSurfaceFrame2.getJankType(),
+              JankType::AppDeadlineMissed | JankType::BufferStuffing);
+}
 } // namespace android::frametimeline
diff --git a/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp
index 53dfe3f..8208b3f 100644
--- a/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp
+++ b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp
@@ -69,6 +69,7 @@
     ~MockTokenManager() override = default;
 
     MOCK_METHOD1(generateTokenForPredictions, int64_t(frametimeline::TimelineItem&& prediction));
+    MOCK_CONST_METHOD1(getPredictionsForToken, std::optional<frametimeline::TimelineItem>(int64_t));
 };
 
 class MessageQueueTest : public testing::Test {
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index d617374..48c55d4 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -156,8 +156,8 @@
     }
 
     std::unique_ptr<frametimeline::FrameTimeline> createFrameTimeline(
-            std::shared_ptr<TimeStats> timeStats) override {
-        return std::make_unique<mock::FrameTimeline>(timeStats);
+            std::shared_ptr<TimeStats> timeStats, pid_t surfaceFlingerPid = 0) override {
+        return std::make_unique<mock::FrameTimeline>(timeStats, surfaceFlingerPid);
     }
 
     using CreateBufferQueueFunction =
diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
index bbcc0c9..ace370f 100644
--- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
@@ -356,9 +356,9 @@
     EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
 
     insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
-    mTimeStats->incrementJankyFrames(JankType::SurfaceFlingerDeadlineMissed);
+    mTimeStats->incrementJankyFrames(JankType::SurfaceFlingerCpuDeadlineMissed);
     mTimeStats->incrementJankyFrames(JankType::SurfaceFlingerGpuDeadlineMissed);
-    mTimeStats->incrementJankyFrames(JankType::Display);
+    mTimeStats->incrementJankyFrames(JankType::DisplayHAL);
     mTimeStats->incrementJankyFrames(JankType::AppDeadlineMissed);
     mTimeStats->incrementJankyFrames(JankType::None);
 
@@ -383,10 +383,10 @@
 
     insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
     mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
-                                     JankType::SurfaceFlingerDeadlineMissed);
+                                     JankType::SurfaceFlingerCpuDeadlineMissed);
     mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
                                      JankType::SurfaceFlingerGpuDeadlineMissed);
-    mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), JankType::Display);
+    mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), JankType::DisplayHAL);
     mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
                                      JankType::AppDeadlineMissed);
     mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), JankType::None);
@@ -848,10 +848,10 @@
             std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count()));
 
     mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
-                                     JankType::SurfaceFlingerDeadlineMissed);
+                                     JankType::SurfaceFlingerCpuDeadlineMissed);
     mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
                                      JankType::SurfaceFlingerGpuDeadlineMissed);
-    mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), JankType::Display);
+    mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), JankType::DisplayHAL);
     mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
                                      JankType::AppDeadlineMissed);
     mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), JankType::None);
@@ -987,9 +987,9 @@
     mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(3000000));
     mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(5000000));
 
-    mTimeStats->incrementJankyFrames(JankType::SurfaceFlingerDeadlineMissed);
+    mTimeStats->incrementJankyFrames(JankType::SurfaceFlingerCpuDeadlineMissed);
     mTimeStats->incrementJankyFrames(JankType::SurfaceFlingerGpuDeadlineMissed);
-    mTimeStats->incrementJankyFrames(JankType::Display);
+    mTimeStats->incrementJankyFrames(JankType::DisplayHAL);
     mTimeStats->incrementJankyFrames(JankType::AppDeadlineMissed);
     mTimeStats->incrementJankyFrames(JankType::None);
 
@@ -1062,10 +1062,10 @@
     insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
 
     mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
-                                     JankType::SurfaceFlingerDeadlineMissed);
+                                     JankType::SurfaceFlingerCpuDeadlineMissed);
     mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
                                      JankType::SurfaceFlingerGpuDeadlineMissed);
-    mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), JankType::Display);
+    mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), JankType::DisplayHAL);
     mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
                                      JankType::AppDeadlineMissed);
     mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), JankType::None);
diff --git a/services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.cpp b/services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.cpp
index f784df3..ff005a0 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.cpp
+++ b/services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.cpp
@@ -19,8 +19,8 @@
 namespace android::mock {
 
 // Explicit default instantiation is recommended.
-FrameTimeline::FrameTimeline(std::shared_ptr<TimeStats> timeStats)
-      : android::frametimeline::impl::FrameTimeline(timeStats) {}
+FrameTimeline::FrameTimeline(std::shared_ptr<TimeStats> timeStats, pid_t surfaceFlingerPid)
+      : android::frametimeline::impl::FrameTimeline(timeStats, surfaceFlingerPid) {}
 FrameTimeline::~FrameTimeline() = default;
 
 } // namespace android::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.h b/services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.h
index 6b12536..0a6a9f4 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.h
@@ -26,14 +26,12 @@
     // No need to create mocks for SurfaceFrame and TokenManager yet. They are very small components
     // and do not have external dependencies like perfetto.
 public:
-    FrameTimeline(std::shared_ptr<TimeStats> timeStats);
+    FrameTimeline(std::shared_ptr<TimeStats> timeStats, pid_t surfaceFlingerPid);
     ~FrameTimeline();
 
     MOCK_METHOD0(onBootFinished, void());
-    MOCK_METHOD2(addSurfaceFrame,
-                 void(std::shared_ptr<frametimeline::SurfaceFrame>,
-                      frametimeline::SurfaceFrame::PresentState));
-    MOCK_METHOD2(setSfWakeUp, void(int64_t, nsecs_t));
+    MOCK_METHOD1(addSurfaceFrame, void(std::shared_ptr<frametimeline::SurfaceFrame>));
+    MOCK_METHOD3(setSfWakeUp, void(int64_t, nsecs_t, nsecs_t));
     MOCK_METHOD2(setSfPresent, void(nsecs_t, const std::shared_ptr<FenceTime>&));
 };