Add Shared timeline jank classification listener (1/2)

Adds the ability to register a listener that gets informed about
SF' jank classifications via the TransactionCompleted interface

Bug: 17475548
Test: FrameTimelineTest
Test: Register listener, ensure data flows back
Change-Id: Ie42c508da605c03569eadab6ab18b7315b35d247
diff --git a/libs/gui/ITransactionCompletedListener.cpp b/libs/gui/ITransactionCompletedListener.cpp
index 69f7894..2dacae1 100644
--- a/libs/gui/ITransactionCompletedListener.cpp
+++ b/libs/gui/ITransactionCompletedListener.cpp
@@ -17,6 +17,8 @@
 #define LOG_TAG "ITransactionCompletedListener"
 //#define LOG_NDEBUG 0
 
+#include <gui/LayerState.h>
+#include <gui/ISurfaceComposer.h>
 #include <gui/ITransactionCompletedListener.h>
 
 namespace android {
@@ -90,61 +92,63 @@
     return err;
 }
 
-status_t SurfaceStats::writeToParcel(Parcel* output) const {
-    status_t err = output->writeStrongBinder(surfaceControl);
-    if (err != NO_ERROR) {
-        return err;
-    }
-    err = output->writeInt64(acquireTime);
-    if (err != NO_ERROR) {
-        return err;
-    }
-    if (previousReleaseFence) {
-        err = output->writeBool(true);
-        if (err != NO_ERROR) {
-            return err;
-        }
-        err = output->write(*previousReleaseFence);
-    } else {
-        err = output->writeBool(false);
-    }
-    err = output->writeUint32(transformHint);
-    if (err != NO_ERROR) {
-        return err;
-    }
+JankData::JankData() :
+        frameVsyncId(ISurfaceComposer::INVALID_VSYNC_ID),
+        jankType(JankType::None) {
+}
 
-    err = output->writeParcelable(eventStats);
-    return err;
+status_t JankData::writeToParcel(Parcel* output) const {
+    SAFE_PARCEL(output->writeInt64, frameVsyncId);
+    SAFE_PARCEL(output->writeInt32, static_cast<int32_t>(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);
+    return NO_ERROR;
+}
+
+status_t SurfaceStats::writeToParcel(Parcel* output) const {
+    SAFE_PARCEL(output->writeStrongBinder, surfaceControl);
+    SAFE_PARCEL(output->writeInt64, acquireTime);
+    if (previousReleaseFence) {
+        SAFE_PARCEL(output->writeBool, true);
+        SAFE_PARCEL(output->write, *previousReleaseFence);
+    } else {
+        SAFE_PARCEL(output->writeBool, false);
+    }
+    SAFE_PARCEL(output->writeUint32, transformHint);
+    SAFE_PARCEL(output->writeParcelable, eventStats);
+    SAFE_PARCEL(output->writeInt32, static_cast<int32_t>(jankData.size()));
+    for (const auto& data : jankData) {
+        SAFE_PARCEL(output->writeParcelable, data);
+    }
+    return NO_ERROR;
 }
 
 status_t SurfaceStats::readFromParcel(const Parcel* input) {
-    status_t err = input->readStrongBinder(&surfaceControl);
-    if (err != NO_ERROR) {
-        return err;
-    }
-    err = input->readInt64(&acquireTime);
-    if (err != NO_ERROR) {
-        return err;
-    }
+    SAFE_PARCEL(input->readStrongBinder, &surfaceControl);
+    SAFE_PARCEL(input->readInt64, &acquireTime);
     bool hasFence = false;
-    err = input->readBool(&hasFence);
-    if (err != NO_ERROR) {
-        return err;
-    }
+    SAFE_PARCEL(input->readBool, &hasFence);
     if (hasFence) {
         previousReleaseFence = new Fence();
-        err = input->read(*previousReleaseFence);
-        if (err != NO_ERROR) {
-            return err;
-        }
+        SAFE_PARCEL(input->read, *previousReleaseFence);
     }
-    err = input->readUint32(&transformHint);
-    if (err != NO_ERROR) {
-        return err;
-    }
+    SAFE_PARCEL(input->readUint32, &transformHint);
+    SAFE_PARCEL(input->readParcelable, &eventStats);
 
-    err = input->readParcelable(&eventStats);
-    return err;
+    int32_t jankData_size = 0;
+    SAFE_PARCEL_READ_SIZE(input->readInt32, &jankData_size, input->dataSize());
+    for (int i = 0; i < jankData_size; i++) {
+        JankData data;
+        SAFE_PARCEL(input->readParcelable, &data);
+        jankData.push_back(data);
+    }
+    return NO_ERROR;
 }
 
 status_t TransactionStats::writeToParcel(Parcel* output) const {
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 47a08ab..9ed7d1c 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -125,6 +125,9 @@
     return DefaultComposerClient::getComposerClient();
 }
 
+JankDataListener::~JankDataListener() {
+}
+
 // ---------------------------------------------------------------------------
 
 // TransactionCompletedListener does not use ANDROID_SINGLETON_STATIC_INSTANCE because it needs
@@ -174,6 +177,23 @@
     return callbackId;
 }
 
+void TransactionCompletedListener::addJankListener(const sp<JankDataListener>& listener,
+                                                   sp<SurfaceControl> surfaceControl) {
+    std::lock_guard<std::mutex> lock(mMutex);
+    mJankListeners.insert({surfaceControl->getHandle(), listener});
+}
+
+void TransactionCompletedListener::removeJankListener(const sp<JankDataListener>& listener) {
+    std::lock_guard<std::mutex> lock(mMutex);
+    for (auto it = mJankListeners.begin(); it != mJankListeners.end();) {
+        if (it->second == listener) {
+            it = mJankListeners.erase(it);
+        } else {
+            it++;
+        }
+    }
+}
+
 void TransactionCompletedListener::addSurfaceControlToCallbacks(
         const sp<SurfaceControl>& surfaceControl,
         const std::unordered_set<CallbackId>& callbackIds) {
@@ -189,6 +209,7 @@
 
 void TransactionCompletedListener::onTransactionCompleted(ListenerStats listenerStats) {
     std::unordered_map<CallbackId, CallbackTranslation> callbacksMap;
+    std::multimap<sp<IBinder>, sp<JankDataListener>> jankListenersMap;
     {
         std::lock_guard<std::mutex> lock(mMutex);
 
@@ -204,6 +225,7 @@
          * sp<SurfaceControl> that could possibly exist for the callbacks.
          */
         callbacksMap = mCallbacks;
+        jankListenersMap = mJankListeners;
         for (const auto& transactionStats : listenerStats.transactionStats) {
             for (auto& callbackId : transactionStats.callbackIds) {
                 mCallbacks.erase(callbackId);
@@ -236,6 +258,13 @@
             callbackFunction(transactionStats.latchTime, transactionStats.presentFence,
                              surfaceControlStats);
         }
+        for (const auto& surfaceStats : transactionStats.surfaceStats) {
+            if (surfaceStats.jankData.empty()) continue;
+            for (auto it = jankListenersMap.find(surfaceStats.surfaceControl);
+                    it != jankListenersMap.end(); it++) {
+                it->second->onJankDataAvailable(surfaceStats.jankData);
+            }
+        }
     }
 }
 
diff --git a/libs/gui/include/gui/ITransactionCompletedListener.h b/libs/gui/include/gui/ITransactionCompletedListener.h
index c58634b..26b3840 100644
--- a/libs/gui/include/gui/ITransactionCompletedListener.h
+++ b/libs/gui/include/gui/ITransactionCompletedListener.h
@@ -16,6 +16,8 @@
 
 #pragma once
 
+#include "JankInfo.h"
+
 #include <binder/IInterface.h>
 #include <binder/Parcel.h>
 #include <binder/Parcelable.h>
@@ -57,6 +59,27 @@
     nsecs_t dequeueReadyTime;
 };
 
+/**
+ * Jank information representing SurfaceFlinger's jank classification about frames for a specific
+ * surface.
+ */
+class JankData : public Parcelable {
+public:
+    status_t writeToParcel(Parcel* output) const override;
+    status_t readFromParcel(const Parcel* input) override;
+
+    JankData();
+    JankData(int64_t frameVsyncId, JankType jankType)
+          : frameVsyncId(frameVsyncId),
+            jankType(jankType) {}
+
+    // Identifier for the frame submitted with Transaction.setFrameTimelineVsyncId
+    int64_t frameVsyncId;
+
+    // The type of jank occurred
+    JankType jankType;
+};
+
 class SurfaceStats : public Parcelable {
 public:
     status_t writeToParcel(Parcel* output) const override;
@@ -64,18 +87,21 @@
 
     SurfaceStats() = default;
     SurfaceStats(const sp<IBinder>& sc, nsecs_t time, const sp<Fence>& prevReleaseFence,
-                 uint32_t hint, FrameEventHistoryStats frameEventStats)
+                 uint32_t hint, FrameEventHistoryStats frameEventStats,
+                 std::vector<JankData> jankData)
           : surfaceControl(sc),
             acquireTime(time),
             previousReleaseFence(prevReleaseFence),
             transformHint(hint),
-            eventStats(frameEventStats) {}
+            eventStats(frameEventStats),
+            jankData(std::move(jankData)) {}
 
     sp<IBinder> surfaceControl;
     nsecs_t acquireTime = -1;
     sp<Fence> previousReleaseFence;
     uint32_t transformHint = 0;
     FrameEventHistoryStats eventStats;
+    std::vector<JankData> jankData;
 };
 
 class TransactionStats : public Parcelable {
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 2eb97f2..f1845ee 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -619,6 +619,12 @@
 
 // ---------------------------------------------------------------------------
 
+class JankDataListener : public VirtualLightRefBase {
+public:
+    virtual ~JankDataListener() = 0;
+    virtual void onJankDataAvailable(const std::vector<JankData>& jankData) = 0;
+};
+
 class TransactionCompletedListener : public BnTransactionCompletedListener {
     TransactionCompletedListener();
 
@@ -637,6 +643,7 @@
     };
 
     std::unordered_map<CallbackId, CallbackTranslation> mCallbacks GUARDED_BY(mMutex);
+    std::multimap<sp<IBinder>, sp<JankDataListener>> mJankListeners GUARDED_BY(mMutex);
 
 public:
     static sp<TransactionCompletedListener> getInstance();
@@ -652,6 +659,18 @@
     void addSurfaceControlToCallbacks(const sp<SurfaceControl>& surfaceControl,
                                       const std::unordered_set<CallbackId>& callbackIds);
 
+    /*
+     * Adds a jank listener to be informed about SurfaceFlinger's jank classification for a specific
+     * surface. Jank classifications arrive as part of the transaction callbacks about previous
+     * frames submitted to this Surface.
+     */
+    void addJankListener(const sp<JankDataListener>& listener, sp<SurfaceControl> surfaceControl);
+
+    /**
+     * Removes a jank listener previously added to addJankCallback.
+     */
+    void removeJankListener(const sp<JankDataListener>& listener);
+
     // Overrides BnTransactionCompletedListener's onTransactionCompleted
     void onTransactionCompleted(ListenerStats stats) override;
 };
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index dc99986..325ecfe 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -440,7 +440,7 @@
                                                                      mName, mFrameTimelineVsyncId);
         surfaceFrame->setActualQueueTime(systemTime());
 
-        mQueueItems.push_back({item, std::move(surfaceFrame)});
+        mQueueItems.push_back({item, surfaceFrame});
         mQueuedFrames++;
 
         // Wake up any pending callbacks
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index b45900e..5a6b9bc 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -129,10 +129,10 @@
     Condition mQueueItemCondition;
 
     struct BufferData {
-        BufferData(BufferItem item, std::unique_ptr<frametimeline::SurfaceFrame> surfaceFrame)
-              : item(item), surfaceFrame(std::move(surfaceFrame)) {}
+        BufferData(BufferItem item, std::shared_ptr<frametimeline::SurfaceFrame> surfaceFrame)
+              : item(item), surfaceFrame(surfaceFrame) {}
         BufferItem item;
-        std::unique_ptr<frametimeline::SurfaceFrame> surfaceFrame;
+        std::shared_ptr<frametimeline::SurfaceFrame> surfaceFrame;
     };
     std::vector<BufferData> mQueueItems;
     std::atomic<uint64_t> mLastFrameNumberReceived{0};
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 963e541..4efff75 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -100,14 +100,30 @@
     }
 }
 
+void BufferStateLayer::onSurfaceFrameCreated(
+        const std::shared_ptr<frametimeline::SurfaceFrame>& surfaceFrame) {
+    mPendingJankClassifications.emplace_back(surfaceFrame);
+}
+
 void BufferStateLayer::releasePendingBuffer(nsecs_t dequeueReadyTime) {
     for (const auto& handle : mDrawingState.callbackHandles) {
         handle->transformHint = mTransformHint;
         handle->dequeueReadyTime = dequeueReadyTime;
     }
 
+    std::vector<JankData> jankData;
+    jankData.reserve(mPendingJankClassifications.size());
+    while (!mPendingJankClassifications.empty()
+            && mPendingJankClassifications.front()->getJankType()) {
+        std::shared_ptr<frametimeline::SurfaceFrame> surfaceFrame =
+                mPendingJankClassifications.front();
+        mPendingJankClassifications.pop_front();
+        jankData.emplace_back(
+                JankData(surfaceFrame->getToken(), surfaceFrame->getJankType().value()));
+    }
+
     mFlinger->getTransactionCompletedThread().finalizePendingCallbackHandles(
-            mDrawingState.callbackHandles);
+            mDrawingState.callbackHandles, jankData);
 
     mDrawingState.callbackHandles = {};
 
@@ -382,7 +398,7 @@
 
 void BufferStateLayer::forceSendCallbacks() {
     mFlinger->getTransactionCompletedThread().finalizePendingCallbackHandles(
-            mCurrentState.callbackHandles);
+            mCurrentState.callbackHandles, std::vector<JankData>());
 }
 
 bool BufferStateLayer::setTransparentRegionHint(const Region& transparent) {
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 42be62a..0f0b48a 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -115,6 +115,7 @@
 protected:
     void gatherBufferInfo() override;
     uint64_t getHeadFrameNumber(nsecs_t expectedPresentTime) const;
+    void onSurfaceFrameCreated(const std::shared_ptr<frametimeline::SurfaceFrame>& surfaceFrame);
 
 private:
     friend class SlotGenerationTest;
@@ -158,6 +159,8 @@
     bool mReleasePreviousBuffer = false;
     nsecs_t mCallbackHandleAcquireTime = -1;
 
+    std::deque<std::shared_ptr<android::frametimeline::SurfaceFrame>> mPendingJankClassifications;
+
     // TODO(marissaw): support sticky transform for LEGACY camera mode
 
     class HwcSlotGenerator : public ClientCache::ErasedRecipient {
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
index b45c213..b09f07a 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
@@ -265,8 +265,11 @@
     mJankMetadata = jankMetadata;
 }
 
-JankType SurfaceFrame::getJankType() const {
+std::optional<JankType> SurfaceFrame::getJankType() const {
     std::lock_guard<std::mutex> lock(mMutex);
+    if (mActuals.presentTime == 0) {
+        return std::nullopt;
+    }
     return mJankType;
 }
 
@@ -386,37 +389,36 @@
     this->surfaceFrames.reserve(kNumSurfaceFramesInitial);
 }
 
-std::unique_ptr<android::frametimeline::SurfaceFrame> FrameTimeline::createSurfaceFrameForToken(
+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) {
     ATRACE_CALL();
     if (!token) {
-        return std::make_unique<impl::SurfaceFrame>(ISurfaceComposer::INVALID_VSYNC_ID, ownerPid,
+        return std::make_shared<impl::SurfaceFrame>(ISurfaceComposer::INVALID_VSYNC_ID,ownerPid,
                                                     ownerUid, std::move(layerName),
                                                     std::move(debugName), PredictionState::None,
                                                     TimelineItem());
     }
     std::optional<TimelineItem> predictions = mTokenManager.getPredictionsForToken(*token);
     if (predictions) {
-        return std::make_unique<impl::SurfaceFrame>(*token, ownerPid, ownerUid,
+        return std::make_shared<impl::SurfaceFrame>(*token, ownerPid, ownerUid,
                                                     std::move(layerName), std::move(debugName),
                                                     PredictionState::Valid,
                                                     std::move(*predictions));
     }
-    return std::make_unique<impl::SurfaceFrame>(*token, ownerPid, ownerUid, std::move(layerName),
+    return std::make_shared<impl::SurfaceFrame>(*token, ownerPid, ownerUid, std::move(layerName),
                                                 std::move(debugName), PredictionState::Expired,
                                                 TimelineItem());
 }
 
 void FrameTimeline::addSurfaceFrame(
-        std::unique_ptr<android::frametimeline::SurfaceFrame> surfaceFrame,
+        std::shared_ptr<android::frametimeline::SurfaceFrame> surfaceFrame,
         SurfaceFrame::PresentState state) {
     ATRACE_CALL();
     surfaceFrame->setPresentState(state);
-    std::unique_ptr<impl::SurfaceFrame> implSurfaceFrame(
-            static_cast<impl::SurfaceFrame*>(surfaceFrame.release()));
     std::lock_guard<std::mutex> lock(mMutex);
-    mCurrentDisplayFrame->surfaceFrames.push_back(std::move(implSurfaceFrame));
+    mCurrentDisplayFrame->surfaceFrames.push_back(
+            std::static_pointer_cast<impl::SurfaceFrame>(surfaceFrame));
 }
 
 void FrameTimeline::setSfWakeUp(int64_t token, nsecs_t wakeUpTime) {
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.h b/services/surfaceflinger/FrameTimeline/FrameTimeline.h
index fe83ebf..084935b 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.h
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.h
@@ -120,6 +120,12 @@
     virtual void setActualStartTime(nsecs_t actualStartTime) = 0;
     virtual void setActualQueueTime(nsecs_t actualQueueTime) = 0;
     virtual void setAcquireFenceTime(nsecs_t acquireFenceTime) = 0;
+
+    // Retrieves jank classification, if it's already been classified.
+    virtual std::optional<JankType> getJankType() const = 0;
+
+    // Token identifying the frame.
+    virtual int64_t getToken() const = 0;
 };
 
 /*
@@ -138,13 +144,13 @@
     // 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::unique_ptr<SurfaceFrame> createSurfaceFrameForToken(
+    virtual std::shared_ptr<SurfaceFrame> createSurfaceFrameForToken(
             pid_t ownerPid, uid_t ownerUid, std::string layerName, std::string debugName,
             std::optional<int64_t> token) = 0;
 
     // Adds a new SurfaceFrame to the current DisplayFrame. Frames from multiple layers can be
     // composited into one display frame.
-    virtual void addSurfaceFrame(std::unique_ptr<SurfaceFrame> surfaceFrame,
+    virtual void addSurfaceFrame(std::shared_ptr<SurfaceFrame> surfaceFrame,
                                  SurfaceFrame::PresentState state) = 0;
 
     // The first function called by SF for the current DisplayFrame. Fetches SF predictions based on
@@ -209,8 +215,8 @@
     PresentState getPresentState() const override;
     PredictionState getPredictionState() const override { return mPredictionState; };
     pid_t getOwnerPid() const override { return mOwnerPid; };
-    JankType getJankType() const;
-    int64_t getToken() const { return mToken; };
+    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; };
@@ -258,10 +264,10 @@
     ~FrameTimeline() = default;
 
     frametimeline::TokenManager* getTokenManager() override { return &mTokenManager; }
-    std::unique_ptr<frametimeline::SurfaceFrame> createSurfaceFrameForToken(
+    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::unique_ptr<frametimeline::SurfaceFrame> surfaceFrame,
+    void addSurfaceFrame(std::shared_ptr<frametimeline::SurfaceFrame> surfaceFrame,
                          SurfaceFrame::PresentState state) override;
     void setSfWakeUp(int64_t token, nsecs_t wakeupTime) override;
     void setSfPresent(nsecs_t sfPresentTime,
@@ -299,7 +305,7 @@
         TimelineItem surfaceFlingerActuals;
 
         // Collection of predictions and actual values sent over by Layers
-        std::vector<std::unique_ptr<SurfaceFrame>> surfaceFrames;
+        std::vector<std::shared_ptr<SurfaceFrame>> surfaceFrames;
 
         PredictionState predictionState = PredictionState::None;
         JankType jankType = JankType::None; // Enum for the type of jank
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index ab0d3df..cfaa59d 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -901,17 +901,17 @@
                 ? std::nullopt
                 : std::make_optional(stateToCommit->frameTimelineVsyncId);
 
-        auto surfaceFrame =
+        mSurfaceFrame =
                 mFlinger->mFrameTimeline->createSurfaceFrameForToken(getOwnerPid(), getOwnerUid(),
                                                                      mName, mTransactionName,
                                                                      vsyncId);
-        surfaceFrame->setActualQueueTime(stateToCommit->postTime);
+        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
         // BufferStateLayer::applyPendingStates
-        surfaceFrame->setAcquireFenceTime(stateToCommit->postTime);
+        mSurfaceFrame->setAcquireFenceTime(stateToCommit->postTime);
 
-        mSurfaceFrame = std::move(surfaceFrame);
+        onSurfaceFrameCreated(mSurfaceFrame);
     }
 
     mCurrentState.modified = false;
@@ -1057,7 +1057,7 @@
 
 void Layer::commitTransaction(const State& stateToCommit) {
     mDrawingState = stateToCommit;
-    mFlinger->mFrameTimeline->addSurfaceFrame(std::move(mSurfaceFrame), PresentState::Presented);
+    mFlinger->mFrameTimeline->addSurfaceFrame(mSurfaceFrame, PresentState::Presented);
 }
 
 uint32_t Layer::getTransactionFlags(uint32_t flags) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 75d68a1..b30793a 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -942,6 +942,7 @@
     virtual void commitTransaction(const State& stateToCommit);
     virtual bool applyPendingStates(State* stateToCommit);
     virtual uint32_t doTransactionResize(uint32_t flags, Layer::State* stateToCommit);
+    virtual void onSurfaceFrameCreated(const std::shared_ptr<frametimeline::SurfaceFrame>&) {}
 
     // Returns mCurrentScaling mode (originating from the
     // Client) or mOverrideScalingMode mode (originating from
@@ -1066,7 +1067,7 @@
     const InputWindowInfo::Type mWindowType;
 
     // Can only be accessed with the SF state lock held.
-    std::unique_ptr<frametimeline::SurfaceFrame> mSurfaceFrame;
+    std::shared_ptr<frametimeline::SurfaceFrame> mSurfaceFrame;
 
     // The owner of the layer. If created from a non system process, it will be the calling uid.
     // If created from a system process, the value can be passed in.
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 773b3ab..cb56ecc 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1986,12 +1986,14 @@
 
     mScheduler->onDisplayRefreshed(presentTime);
 
-    postFrame();
-    postComposition();
-
+    // Set presentation information before calling postComposition, such that jank information from
+    // this' frame classification is already available when sending jank info to clients.
     mFrameTimeline->setSfPresent(systemTime(),
                                  std::make_shared<FenceTime>(mPreviousPresentFences[0]));
 
+    postFrame();
+    postComposition();
+
     const bool prevFrameHadClientComposition = mHadClientComposition;
 
     mHadClientComposition = std::any_of(displays.cbegin(), displays.cend(), [](const auto& pair) {
diff --git a/services/surfaceflinger/TransactionCompletedThread.cpp b/services/surfaceflinger/TransactionCompletedThread.cpp
index ca24493..1797af4 100644
--- a/services/surfaceflinger/TransactionCompletedThread.cpp
+++ b/services/surfaceflinger/TransactionCompletedThread.cpp
@@ -153,7 +153,7 @@
 }
 
 status_t TransactionCompletedThread::finalizePendingCallbackHandles(
-        const std::deque<sp<CallbackHandle>>& handles) {
+        const std::deque<sp<CallbackHandle>>& handles, const std::vector<JankData>& jankData) {
     if (handles.empty()) {
         return NO_ERROR;
     }
@@ -186,7 +186,7 @@
             ALOGW("cannot find listener in mPendingTransactions");
         }
 
-        status_t err = addCallbackHandle(handle);
+        status_t err = addCallbackHandle(handle, jankData);
         if (err != NO_ERROR) {
             ALOGE("could not add callback handle");
             return err;
@@ -204,7 +204,7 @@
         return BAD_VALUE;
     }
 
-    return addCallbackHandle(handle);
+    return addCallbackHandle(handle, std::vector<JankData>());
 }
 
 status_t TransactionCompletedThread::findTransactionStats(
@@ -225,7 +225,8 @@
     return BAD_VALUE;
 }
 
-status_t TransactionCompletedThread::addCallbackHandle(const sp<CallbackHandle>& handle) {
+status_t TransactionCompletedThread::addCallbackHandle(const sp<CallbackHandle>& handle,
+        const std::vector<JankData>& jankData) {
     // If we can't find the transaction stats something has gone wrong. The client should call
     // startRegistration before trying to add a callback handle.
     TransactionStats* transactionStats;
@@ -246,7 +247,7 @@
                                           handle->dequeueReadyTime);
         transactionStats->surfaceStats.emplace_back(surfaceControl, handle->acquireTime,
                                                     handle->previousReleaseFence,
-                                                    handle->transformHint, eventStats);
+                                                    handle->transformHint, eventStats, jankData);
     }
     return NO_ERROR;
 }
diff --git a/services/surfaceflinger/TransactionCompletedThread.h b/services/surfaceflinger/TransactionCompletedThread.h
index f50147a..c4ba7e4 100644
--- a/services/surfaceflinger/TransactionCompletedThread.h
+++ b/services/surfaceflinger/TransactionCompletedThread.h
@@ -73,7 +73,8 @@
     // presented.
     status_t registerPendingCallbackHandle(const sp<CallbackHandle>& handle);
     // Notifies the TransactionCompletedThread that a pending CallbackHandle has been presented.
-    status_t finalizePendingCallbackHandles(const std::deque<sp<CallbackHandle>>& handles);
+    status_t finalizePendingCallbackHandles(const std::deque<sp<CallbackHandle>>& handles,
+                                            const std::vector<JankData>& jankData);
 
     // Adds the Transaction CallbackHandle from a layer that does not need to be relatched and
     // presented this frame.
@@ -93,7 +94,8 @@
                                   const std::vector<CallbackId>& callbackIds,
                                   TransactionStats** outTransactionStats) REQUIRES(mMutex);
 
-    status_t addCallbackHandle(const sp<CallbackHandle>& handle) REQUIRES(mMutex);
+    status_t addCallbackHandle(const sp<CallbackHandle>& handle,
+                               const std::vector<JankData>& jankData) REQUIRES(mMutex);
 
     class ThreadDeathRecipient : public IBinder::DeathRecipient {
     public:
diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
index 31a5126..538b10d 100644
--- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
+++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
@@ -69,6 +69,7 @@
 
 using Transaction = SurfaceComposerClient::Transaction;
 using Attribute = V2_4::IComposerClient::Attribute;
+using Display = V2_1::Display;
 
 ///////////////////////////////////////////////
 
diff --git a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
index 411e780..43b5afe 100644
--- a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
@@ -205,7 +205,7 @@
 
     // Set up the display frame
     mFrameTimeline->setSfWakeUp(token1, 20);
-    mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame1), SurfaceFrame::PresentState::Dropped);
+    mFrameTimeline->addSurfaceFrame(surfaceFrame1, SurfaceFrame::PresentState::Dropped);
     mFrameTimeline->setSfPresent(25, presentFence1);
     presentFence1->signalForTest(30);
 
@@ -229,11 +229,11 @@
                                                        sLayerNameOne, surfaceFrameToken1);
     auto surfaceFrame2 =
             mFrameTimeline->createSurfaceFrameForToken(sPidOne, sUidOne, sLayerNameTwo,
-                                                       sLayerNameTwo, surfaceFrameToken1);
+                                                       sLayerNameTwo, surfaceFrameToken2);
     mFrameTimeline->setSfWakeUp(sfToken1, 22);
-    mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame1),
+    mFrameTimeline->addSurfaceFrame(surfaceFrame1,
                                     SurfaceFrame::PresentState::Presented);
-    mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame2),
+    mFrameTimeline->addSurfaceFrame(surfaceFrame2,
                                     SurfaceFrame::PresentState::Presented);
     mFrameTimeline->setSfPresent(26, presentFence1);
     auto displayFrame = getDisplayFrame(0);
@@ -246,13 +246,16 @@
     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(std::move(surfaceFrame3), SurfaceFrame::PresentState::Dropped);
+    mFrameTimeline->addSurfaceFrame(surfaceFrame3, SurfaceFrame::PresentState::Dropped);
     mFrameTimeline->setSfPresent(56, presentFence2);
     displayFrame = getDisplayFrame(0);
 
@@ -260,6 +263,8 @@
     EXPECT_EQ(displayFrame->surfaceFlingerActuals.presentTime, 42);
     EXPECT_EQ(presentedSurfaceFrame1.getActuals().presentTime, 42);
     EXPECT_EQ(presentedSurfaceFrame2.getActuals().presentTime, 42);
+    EXPECT_NE(surfaceFrame1->getJankType(), std::nullopt);
+    EXPECT_NE(surfaceFrame2->getJankType(), std::nullopt);
 }
 
 TEST_F(FrameTimelineTest, displayFramesSlidingWindowMovesAfterLimit) {
@@ -275,7 +280,7 @@
                 mFrameTimeline->createSurfaceFrameForToken(sPidOne, sUidOne, sLayerNameOne,
                                                            sLayerNameOne, surfaceFrameToken);
         mFrameTimeline->setSfWakeUp(sfToken, 22 + frameTimeFactor);
-        mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame),
+        mFrameTimeline->addSurfaceFrame(surfaceFrame,
                                         SurfaceFrame::PresentState::Presented);
         mFrameTimeline->setSfPresent(27 + frameTimeFactor, presentFence);
         presentFence->signalForTest(32 + frameTimeFactor);
@@ -297,7 +302,7 @@
             mFrameTimeline->createSurfaceFrameForToken(sPidOne, sUidOne, sLayerNameOne,
                                                        sLayerNameOne, surfaceFrameToken);
     mFrameTimeline->setSfWakeUp(sfToken, 22 + frameTimeFactor);
-    mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame), SurfaceFrame::PresentState::Presented);
+    mFrameTimeline->addSurfaceFrame(surfaceFrame, SurfaceFrame::PresentState::Presented);
     mFrameTimeline->setSfPresent(27 + frameTimeFactor, presentFence);
     presentFence->signalForTest(32 + frameTimeFactor);
     displayFrame0 = getDisplayFrame(0);
@@ -337,7 +342,7 @@
                                                            sLayerNameOne, std::nullopt);
         int64_t sfToken = mTokenManager->generateTokenForPredictions({22, 26, 30});
         mFrameTimeline->setSfWakeUp(sfToken, 22);
-        mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame),
+        mFrameTimeline->addSurfaceFrame(surfaceFrame,
                                         SurfaceFrame::PresentState::Presented);
         mFrameTimeline->setSfPresent(27, presentFence);
     }
@@ -353,7 +358,7 @@
                                                            sLayerNameOne, std::nullopt);
         int64_t sfToken = mTokenManager->generateTokenForPredictions({22, 26, 30});
         mFrameTimeline->setSfWakeUp(sfToken, 22);
-        mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame),
+        mFrameTimeline->addSurfaceFrame(surfaceFrame,
                                         SurfaceFrame::PresentState::Presented);
         mFrameTimeline->setSfPresent(27, presentFence);
     }
@@ -369,7 +374,7 @@
                                                            sLayerNameOne, std::nullopt);
         int64_t sfToken = mTokenManager->generateTokenForPredictions({22, 26, 30});
         mFrameTimeline->setSfWakeUp(sfToken, 22);
-        mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame),
+        mFrameTimeline->addSurfaceFrame(surfaceFrame,
                                         SurfaceFrame::PresentState::Presented);
         mFrameTimeline->setSfPresent(27, presentFence);
     }
@@ -396,10 +401,10 @@
                                                        sLayerNameOne, surfaceFrameToken1);
     mFrameTimeline->setSfWakeUp(sfToken1,
                                 std::chrono::duration_cast<std::chrono::nanoseconds>(52ms).count());
-    mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame1),
+    mFrameTimeline->addSurfaceFrame(surfaceFrame1,
                                     SurfaceFrame::PresentState::Presented);
     presentFence1->signalForTest(
-            std::chrono::duration_cast<std::chrono::nanoseconds>(90ms).count());
+            std::chrono::duration_cast<std::chrono::nanoseconds>(70ms).count());
 
     mFrameTimeline->setSfPresent(std::chrono::duration_cast<std::chrono::nanoseconds>(59ms).count(),
                                  presentFence1);
@@ -423,12 +428,14 @@
                                                        sLayerNameOne, surfaceFrameToken1);
     mFrameTimeline->setSfWakeUp(sfToken1,
                                 std::chrono::duration_cast<std::chrono::nanoseconds>(52ms).count());
-    mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame1),
+    mFrameTimeline->addSurfaceFrame(surfaceFrame1,
                                     SurfaceFrame::PresentState::Presented);
     presentFence1->signalForTest(
             std::chrono::duration_cast<std::chrono::nanoseconds>(90ms).count());
     mFrameTimeline->setSfPresent(std::chrono::duration_cast<std::chrono::nanoseconds>(59ms).count(),
                                  presentFence1);
+    EXPECT_NE(surfaceFrame1->getJankType(), std::nullopt);
+    EXPECT_TRUE((surfaceFrame1->getJankType().value() & JankType::Display) != 0);
 }
 
 TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppMiss) {
@@ -453,12 +460,15 @@
     mFrameTimeline->setSfWakeUp(sfToken1,
                                 std::chrono::duration_cast<std::chrono::nanoseconds>(52ms).count());
 
-    mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame1),
+    mFrameTimeline->addSurfaceFrame(surfaceFrame1,
                                     SurfaceFrame::PresentState::Presented);
     presentFence1->signalForTest(
             std::chrono::duration_cast<std::chrono::nanoseconds>(90ms).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::AppDeadlineMissed) != 0);
 }
 
 /*
diff --git a/services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.h b/services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.h
index 81c32fe..6b12536 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.h
@@ -31,7 +31,7 @@
 
     MOCK_METHOD0(onBootFinished, void());
     MOCK_METHOD2(addSurfaceFrame,
-                 void(std::unique_ptr<frametimeline::SurfaceFrame>,
+                 void(std::shared_ptr<frametimeline::SurfaceFrame>,
                       frametimeline::SurfaceFrame::PresentState));
     MOCK_METHOD2(setSfWakeUp, void(int64_t, nsecs_t));
     MOCK_METHOD2(setSfPresent, void(nsecs_t, const std::shared_ptr<FenceTime>&));