Merge "Expand jank classification"
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 17ef7ef..7ecfe53 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();
@@ -5366,8 +5366,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 10846f1..4a75180 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 ea66676..24148dd 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 5a0ea57..885297f 100644
--- a/services/surfaceflinger/SurfaceFlingerFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerFactory.h
@@ -110,7 +110,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 9d16782..c98004a 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>&));
 };