Merge "[CE] Extract transform computation logic to ProjectionSpace"
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 2519ffa..3184843 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -99,7 +99,9 @@
 
 /* Tracing categories */
 static const TracingCategory k_categories[] = {
-    { "gfx",        "Graphics",                 ATRACE_TAG_GRAPHICS, { } },
+    { "gfx",        "Graphics",                 ATRACE_TAG_GRAPHICS, {
+        { OPT,      "events/gpu_mem/gpu_mem_total/enable" },
+    } },
     { "input",      "Input",                    ATRACE_TAG_INPUT, { } },
     { "view",       "View System",              ATRACE_TAG_VIEW, { } },
     { "webview",    "WebView",                  ATRACE_TAG_WEBVIEW, { } },
@@ -241,6 +243,7 @@
         { OPT,      "events/kmem/ion_heap_grow/enable" },
         { OPT,      "events/kmem/ion_heap_shrink/enable" },
         { OPT,      "events/ion/ion_stat/enable" },
+        { OPT,      "events/gpu_mem/gpu_mem_total/enable" },
     } },
     { "thermal",  "Thermal event", 0, {
         { REQ,      "events/thermal/thermal_temperature/enable" },
diff --git a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
index f44ce0c..a4f4441 100644
--- a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
@@ -93,7 +93,7 @@
     //
     // Use 'SharedRefBase::make<T>(...)' to make. SharedRefBase has implicit
     // ownership. Making this operator private to avoid double-ownership.
-#if !defined(__ANDROID_API__) || __ANDROID_API__ >= 30
+#if !defined(__ANDROID_API__) || __ANDROID_API__ >= 30 || defined(__ANDROID_APEX__)
    private:
 #else
     [[deprecated("Prefer SharedRefBase::make<T>(...) if possible.")]]
diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs
index ceb6ade..81a5f02 100644
--- a/libs/binder/rust/src/binder.rs
+++ b/libs/binder/rust/src/binder.rs
@@ -590,6 +590,15 @@
                 f.pad(stringify!($interface))
             }
         }
+
+        // Convert a &dyn $interface to Box<dyn $interface>
+        impl std::borrow::ToOwned for dyn $interface {
+            type Owned = Box<dyn $interface>;
+            fn to_owned(&self) -> Self::Owned {
+                self.as_binder().into_interface()
+                    .expect(concat!("Error cloning interface ", stringify!($interface)))
+            }
+        }
     };
 }
 
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index 7cfe207..70e997d 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -394,6 +394,10 @@
                                       display.clip.bottom));
     canvas->drawColor(0, SkBlendMode::kSrc);
     for (const auto& layer : layers) {
+        SkPaint paint;
+        const auto& bounds = layer->geometry.boundaries;
+        const auto dest = SkRect::MakeLTRB(bounds.left, bounds.top, bounds.right, bounds.bottom);
+
         if (layer->source.buffer.buffer) {
             ATRACE_NAME("DrawImage");
             const auto& item = layer->source.buffer;
@@ -408,15 +412,27 @@
                                                                  : kUnpremul_SkAlphaType);
                 mImageCache.insert({item.buffer->getId(), image});
             }
-            const auto& bounds = layer->geometry.boundaries;
-            SkRect dest = SkRect::MakeLTRB(bounds.left, bounds.top, bounds.right, bounds.bottom);
-            canvas->drawImageRect(image, dest, nullptr);
+
+            SkMatrix matrix;
+            if (layer->geometry.roundedCornersRadius > 0) {
+                const auto roundedRect = getRoundedRect(layer);
+                matrix.setTranslate(roundedRect.getBounds().left() - dest.left(),
+                                    roundedRect.getBounds().top() - dest.top());
+            } else {
+                matrix.setIdentity();
+            }
+            paint.setShader(image->makeShader(matrix));
         } else {
             ATRACE_NAME("DrawColor");
-            SkPaint paint;
             const auto color = layer->source.solidColor;
             paint.setColor(SkColor4f{.fR = color.r, .fG = color.g, .fB = color.b, layer->alpha});
         }
+
+        if (layer->geometry.roundedCornersRadius > 0) {
+            canvas->drawRRect(getRoundedRect(layer), paint);
+        } else {
+            canvas->drawRect(dest, paint);
+        }
     }
     {
         ATRACE_NAME("flush surface");
@@ -448,6 +464,13 @@
     return NO_ERROR;
 }
 
+inline SkRRect SkiaGLRenderEngine::getRoundedRect(const LayerSettings* layer) {
+    const auto& crop = layer->geometry.roundedCornersCrop;
+    const auto rect = SkRect::MakeLTRB(crop.left, crop.top, crop.right, crop.bottom);
+    const auto cornerRadius = layer->geometry.roundedCornersRadius;
+    return SkRRect::MakeRectXY(rect, cornerRadius, cornerRadius);
+}
+
 size_t SkiaGLRenderEngine::getMaxTextureSize() const {
     return mGrContext->maxTextureSize();
 }
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h
index b8387b2..b5c4a1e 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.h
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.h
@@ -60,6 +60,7 @@
                                        Protection protection);
     static EGLSurface createPlaceholderEglPbufferSurface(EGLDisplay display, EGLConfig config,
                                                          int hwcFormat, Protection protection);
+    inline SkRRect getRoundedRect(const LayerSettings* layer);
 
     base::unique_fd flush();
     bool waitFence(base::unique_fd fenceFd);
diff --git a/services/gpuservice/Android.bp b/services/gpuservice/Android.bp
index 1bcaab4..9a9bca1 100644
--- a/services/gpuservice/Android.bp
+++ b/services/gpuservice/Android.bp
@@ -44,11 +44,11 @@
     defaults: ["libgpuservice_defaults"],
     cflags: [
         "-fvisibility=hidden",
-        "-fwhole-program-vtables", // requires ThinLTO
     ],
     lto: {
         thin: true,
     },
+    whole_program_vtables: true, // Requires ThinLTO
 }
 
 filegroup {
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 04e9a2d..7c08e11 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -102,11 +102,11 @@
     defaults: ["libsurfaceflinger_defaults"],
     cflags: [
         "-fvisibility=hidden",
-        "-fwhole-program-vtables", // requires ThinLTO
     ],
     lto: {
         thin: true,
     },
+    whole_program_vtables: true, // Requires ThinLTO
     // TODO(b/131771163): Fix broken fuzzer support with LTO.
     sanitize: {
         fuzzer: false,
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index d460d3d..4cbfdff 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -37,6 +37,7 @@
 #include "BufferLayerConsumer.h"
 #include "Client.h"
 #include "DisplayHardware/HWComposer.h"
+#include "FrameTimeline.h"
 #include "FrameTracker.h"
 #include "Layer.h"
 #include "LayerVector.h"
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 97ad212..33126ab 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -35,6 +35,7 @@
 #include "TimeStats/TimeStats.h"
 
 namespace android {
+using PresentState = frametimeline::SurfaceFrame::PresentState;
 
 BufferQueueLayer::BufferQueueLayer(const LayerCreationArgs& args) : BufferLayer(args) {}
 
@@ -109,7 +110,7 @@
 
     Mutex::Autolock lock(mQueueItemLock);
 
-    const int64_t addedTime = mQueueItems[0].mTimestamp;
+    const int64_t addedTime = mQueueItems[0].item.mTimestamp;
 
     // Ignore timestamps more than a second in the future
     const bool isPlausible = addedTime < (expectedPresentTime + s2ns(1));
@@ -136,7 +137,7 @@
     }
 
     Mutex::Autolock lock(mQueueItemLock);
-    if (mQueueItems[0].mIsDroppable) {
+    if (mQueueItems[0].item.mIsDroppable) {
         // Even though this buffer's fence may not have signaled yet, it could
         // be replaced by another buffer before it has a chance to, which means
         // that it's possible to get into a situation where a buffer is never
@@ -144,7 +145,7 @@
         return true;
     }
     const bool fenceSignaled =
-            mQueueItems[0].mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING;
+            mQueueItems[0].item.mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING;
     if (!fenceSignaled) {
         mFlinger->mTimeStats->incrementLatchSkipped(getSequence(),
                                                     TimeStats::LatchSkipReason::LateAcquire);
@@ -159,12 +160,12 @@
     }
 
     Mutex::Autolock lock(mQueueItemLock);
-    return mQueueItems[0].mTimestamp <= expectedPresentTime;
+    return mQueueItems[0].item.mTimestamp <= expectedPresentTime;
 }
 
 uint64_t BufferQueueLayer::getFrameNumber(nsecs_t expectedPresentTime) const {
     Mutex::Autolock lock(mQueueItemLock);
-    uint64_t frameNumber = mQueueItems[0].mFrameNumber;
+    uint64_t frameNumber = mQueueItems[0].item.mFrameNumber;
 
     // The head of the queue will be dropped if there are signaled and timely frames behind it
     if (isRemovedFromCurrentState()) {
@@ -173,23 +174,23 @@
 
     for (int i = 1; i < mQueueItems.size(); i++) {
         const bool fenceSignaled =
-                mQueueItems[i].mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING;
+                mQueueItems[i].item.mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING;
         if (!fenceSignaled) {
             break;
         }
 
         // We don't drop frames without explicit timestamps
-        if (mQueueItems[i].mIsAutoTimestamp) {
+        if (mQueueItems[i].item.mIsAutoTimestamp) {
             break;
         }
 
-        const nsecs_t desiredPresent = mQueueItems[i].mTimestamp;
+        const nsecs_t desiredPresent = mQueueItems[i].item.mTimestamp;
         if (desiredPresent < expectedPresentTime - BufferQueueConsumer::MAX_REASONABLE_NSEC ||
             desiredPresent > expectedPresentTime) {
             break;
         }
 
-        frameNumber = mQueueItems[i].mFrameNumber;
+        frameNumber = mQueueItems[i].item.mFrameNumber;
     }
 
     return frameNumber;
@@ -254,11 +255,11 @@
         Mutex::Autolock lock(mQueueItemLock);
         for (int i = 0; i < mQueueItems.size(); i++) {
             bool fenceSignaled =
-                    mQueueItems[i].mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING;
+                    mQueueItems[i].item.mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING;
             if (!fenceSignaled) {
                 break;
             }
-            lastSignaledFrameNumber = mQueueItems[i].mFrameNumber;
+            lastSignaledFrameNumber = mQueueItems[i].item.mFrameNumber;
         }
     }
     const uint64_t maxFrameNumberToAcquire =
@@ -276,9 +277,13 @@
         // and return early
         if (queuedBuffer) {
             Mutex::Autolock lock(mQueueItemLock);
-            mConsumer->mergeSurfaceDamage(mQueueItems[0].mSurfaceDamage);
-            mFlinger->mTimeStats->removeTimeRecord(layerId, mQueueItems[0].mFrameNumber);
-            mQueueItems.removeAt(0);
+            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.erase(mQueueItems.begin());
             mQueuedFrames--;
         }
         return BAD_VALUE;
@@ -289,6 +294,12 @@
         // early.
         if (queuedBuffer) {
             Mutex::Autolock lock(mQueueItemLock);
+            for (auto& [item, surfaceFrame] : mQueueItems) {
+                if (surfaceFrame) {
+                    mFlinger->mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame),
+                                                              PresentState::Dropped);
+                }
+            }
             mQueueItems.clear();
             mQueuedFrames = 0;
             mFlinger->mTimeStats->onDestroy(layerId);
@@ -312,19 +323,29 @@
 
         // Remove any stale buffers that have been dropped during
         // updateTexImage
-        while (mQueueItems[0].mFrameNumber != currentFrameNumber) {
-            mConsumer->mergeSurfaceDamage(mQueueItems[0].mSurfaceDamage);
-            mFlinger->mTimeStats->removeTimeRecord(layerId, mQueueItems[0].mFrameNumber);
-            mQueueItems.removeAt(0);
+        while (mQueueItems[0].item.mFrameNumber != currentFrameNumber) {
+            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.erase(mQueueItems.begin());
             mQueuedFrames--;
         }
 
-        uint64_t bufferID = mQueueItems[0].mGraphicBuffer->getId();
+        uint64_t bufferID = mQueueItems[0].item.mGraphicBuffer->getId();
         mFlinger->mTimeStats->setLatchTime(layerId, currentFrameNumber, latchTime);
         mFlinger->mFrameTracer->traceTimestamp(layerId, bufferID, currentFrameNumber, latchTime,
                                                FrameTracer::FrameEvent::LATCH);
 
-        mQueueItems.removeAt(0);
+        if (mQueueItems[0].surfaceFrame) {
+            mQueueItems[0].surfaceFrame->setActualEndTime(
+                    mQueueItems[0].item.mFenceTime->getSignalTime());
+            mFlinger->mFrameTimeline->addSurfaceFrame(std::move(mQueueItems[0].surfaceFrame),
+                                                      PresentState::Presented);
+        }
+        mQueueItems.erase(mQueueItems.begin());
     }
 
     // Decrement the queued-frames count.  Signal another event if we
@@ -416,7 +437,11 @@
             }
         }
 
-        mQueueItems.push_back(item);
+        auto surfaceFrame =
+                mFlinger->mFrameTimeline->createSurfaceFrameForToken(mName, mFrameTimelineVsyncId);
+        surfaceFrame->setActualQueueTime(systemTime());
+
+        mQueueItems.push_back({item, std::move(surfaceFrame)});
         mQueuedFrames++;
 
         // Wake up any pending callbacks
@@ -449,7 +474,12 @@
             ALOGE("Can't replace a frame on an empty queue");
             return;
         }
-        mQueueItems.editItemAt(mQueueItems.size() - 1) = item;
+
+        auto surfaceFrame =
+                mFlinger->mFrameTimeline->createSurfaceFrameForToken(mName, mFrameTimelineVsyncId);
+        surfaceFrame->setActualQueueTime(systemTime());
+        mQueueItems[mQueueItems.size() - 1].item = item;
+        mQueueItems[mQueueItems.size() - 1].surfaceFrame = std::move(surfaceFrame);
 
         // Wake up any pending callbacks
         mLastFrameNumberReceived = item.mFrameNumber;
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index 7d06128..fc992f7 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -22,6 +22,10 @@
 
 namespace android {
 
+namespace frametimeline {
+class SurfaceFrame;
+}
+
 /*
  * A new BufferQueue and a new BufferLayerConsumer are created when the
  * BufferLayer is first referenced.
@@ -125,7 +129,14 @@
     // Local copy of the queued contents of the incoming BufferQueue
     mutable Mutex mQueueItemLock;
     Condition mQueueItemCondition;
-    Vector<BufferItem> mQueueItems;
+
+    struct BufferData {
+        BufferData(BufferItem item, std::unique_ptr<frametimeline::SurfaceFrame> surfaceFrame)
+              : item(item), surfaceFrame(std::move(surfaceFrame)) {}
+        BufferItem item;
+        std::unique_ptr<frametimeline::SurfaceFrame> surfaceFrame;
+    };
+    std::vector<BufferData> mQueueItems;
     std::atomic<uint64_t> mLastFrameNumberReceived{0};
 
     bool mAutoRefresh{false};
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
index c95440a..a12f4c7 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
@@ -20,6 +20,7 @@
 
 #include "FrameTimeline.h"
 #include <android-base/stringprintf.h>
+#include <utils/Trace.h>
 #include <cinttypes>
 
 namespace android::frametimeline::impl {
@@ -27,6 +28,7 @@
 using base::StringAppendF;
 
 int64_t TokenManager::generateTokenForPredictions(TimelineItem&& predictions) {
+    ATRACE_CALL();
     std::lock_guard<std::mutex> lock(mMutex);
     const int64_t assignedToken = mCurrentToken++;
     mPredictions[assignedToken] = predictions;
@@ -88,18 +90,34 @@
     return mActuals;
 }
 
-void SurfaceFrame::setActuals(frametimeline::TimelineItem&& actuals) {
+nsecs_t SurfaceFrame::getActualQueueTime() {
     std::lock_guard<std::mutex> lock(mMutex);
-    mActuals = actuals;
+    return mActualQueueTime;
 }
 
-void SurfaceFrame::setPresentTime(nsecs_t presentTime) {
+void SurfaceFrame::setActualStartTime(nsecs_t actualStartTime) {
+    std::lock_guard<std::mutex> lock(mMutex);
+    mActuals.startTime = actualStartTime;
+}
+
+void SurfaceFrame::setActualQueueTime(nsecs_t actualQueueTime) {
+    std::lock_guard<std::mutex> lock(mMutex);
+    mActualQueueTime = actualQueueTime;
+}
+void SurfaceFrame::setActualEndTime(nsecs_t actualEndTime) {
+    std::lock_guard<std::mutex> lock(mMutex);
+    mActuals.endTime = actualEndTime;
+}
+
+void SurfaceFrame::setActualPresentTime(nsecs_t presentTime) {
     std::lock_guard<std::mutex> lock(mMutex);
     mActuals.presentTime = presentTime;
 }
 
 void SurfaceFrame::dump(std::string& result) {
     std::lock_guard<std::mutex> lock(mMutex);
+    StringAppendF(&result, "Present State : %d\n", static_cast<int>(mPresentState));
+    StringAppendF(&result, "Prediction State : %d\n", static_cast<int>(mPredictionState));
     StringAppendF(&result, "Predicted Start Time : %" PRId64 "\n", mPredictions.startTime);
     StringAppendF(&result, "Actual Start Time : %" PRId64 "\n", mActuals.startTime);
     StringAppendF(&result, "Actual Queue Time : %" PRId64 "\n", mActualQueueTime);
@@ -120,6 +138,7 @@
 
 std::unique_ptr<android::frametimeline::SurfaceFrame> FrameTimeline::createSurfaceFrameForToken(
         const std::string& layerName, std::optional<int64_t> token) {
+    ATRACE_CALL();
     if (!token) {
         return std::make_unique<impl::SurfaceFrame>(layerName, PredictionState::None,
                                                     TimelineItem());
@@ -136,6 +155,7 @@
 void FrameTimeline::addSurfaceFrame(
         std::unique_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()));
@@ -144,18 +164,21 @@
 }
 
 void FrameTimeline::setSfWakeUp(int64_t token, nsecs_t wakeUpTime) {
+    ATRACE_CALL();
     const std::optional<TimelineItem> prediction = mTokenManager.getPredictionsForToken(token);
     std::lock_guard<std::mutex> lock(mMutex);
     if (!prediction) {
         mCurrentDisplayFrame->predictionState = PredictionState::Expired;
     } else {
         mCurrentDisplayFrame->surfaceFlingerPredictions = *prediction;
+        mCurrentDisplayFrame->predictionState = PredictionState::Valid;
     }
     mCurrentDisplayFrame->surfaceFlingerActuals.startTime = 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;
     mPendingPresentFences.emplace_back(std::make_pair(presentFence, mCurrentDisplayFrame));
@@ -179,7 +202,7 @@
             for (auto& surfaceFrame : displayFrame->surfaceFrames) {
                 if (surfaceFrame->getPresentState() == SurfaceFrame::PresentState::Presented) {
                     // Only presented SurfaceFrames need to be updated
-                    surfaceFrame->setPresentTime(signalTime);
+                    surfaceFrame->setActualPresentTime(signalTime);
                 }
             }
         }
@@ -204,6 +227,8 @@
     StringAppendF(&result, "Number of display frames : %d\n", (int)mDisplayFrames.size());
     for (const auto& displayFrame : mDisplayFrames) {
         StringAppendF(&result, "---Display Frame---\n");
+        StringAppendF(&result, "Prediction State : %d\n",
+                      static_cast<int>(displayFrame->predictionState));
         StringAppendF(&result, "Predicted SF wake time : %" PRId64 "\n",
                       displayFrame->surfaceFlingerPredictions.startTime);
         StringAppendF(&result, "Actual SF wake time : %" PRId64 "\n",
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.h b/services/surfaceflinger/FrameTimeline/FrameTimeline.h
index 291e30e..a42c32c 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.h
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.h
@@ -51,7 +51,7 @@
 
     // Generates a token for the given set of predictions. Stores the predictions for 120ms and
     // destroys it later.
-    virtual int64_t generateTokenForPredictions(TimelineItem&& prediction);
+    virtual int64_t generateTokenForPredictions(TimelineItem&& prediction) = 0;
 };
 
 enum class PredictionState {
@@ -76,15 +76,18 @@
 
     virtual TimelineItem getPredictions() = 0;
     virtual TimelineItem getActuals() = 0;
+    virtual nsecs_t getActualQueueTime() = 0;
     virtual PresentState getPresentState() = 0;
     virtual PredictionState getPredictionState() = 0;
 
     virtual void setPresentState(PresentState state) = 0;
-    virtual void setActuals(TimelineItem&& actuals) = 0;
 
-    // There is no prediction for Queue time and it is not a part of TimelineItem. Set it
-    // separately.
+    // 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 End time is available only during latch.
+    virtual void setActualStartTime(nsecs_t actualStartTime) = 0;
     virtual void setActualQueueTime(nsecs_t actualQueueTime) = 0;
+    virtual void setActualEndTime(nsecs_t actualEndTime) = 0;
 };
 
 /*
@@ -94,7 +97,7 @@
 class FrameTimeline {
 public:
     virtual ~FrameTimeline() = default;
-    virtual TokenManager& getTokenManager() = 0;
+    virtual TokenManager* getTokenManager() = 0;
 
     // Create a new surface frame, set the predictions based on a token and return it to the caller.
     // Sets the PredictionState of SurfaceFrame.
@@ -115,6 +118,8 @@
     // that vsync.
     virtual void setSfPresent(nsecs_t sfPresentTime,
                               const std::shared_ptr<FenceTime>& presentFence) = 0;
+
+    virtual void dump(std::string& result) = 0;
 };
 
 namespace impl {
@@ -151,14 +156,15 @@
 
     TimelineItem getPredictions() override { return mPredictions; };
     TimelineItem getActuals() override;
+    nsecs_t getActualQueueTime() override;
     PresentState getPresentState() override;
     PredictionState getPredictionState() override;
-    void setActuals(TimelineItem&& actuals) override;
-    void setActualQueueTime(nsecs_t actualQueueTime) override {
-        mActualQueueTime = actualQueueTime;
-    };
+
+    void setActualStartTime(nsecs_t actualStartTime) override;
+    void setActualQueueTime(nsecs_t actualQueueTime) override;
+    void setActualEndTime(nsecs_t actualEndTime) override;
     void setPresentState(PresentState state) override;
-    void setPresentTime(nsecs_t presentTime);
+    void setActualPresentTime(nsecs_t presentTime);
     void dump(std::string& result);
 
 private:
@@ -176,7 +182,7 @@
     FrameTimeline();
     ~FrameTimeline() = default;
 
-    frametimeline::TokenManager& getTokenManager() override { return mTokenManager; }
+    frametimeline::TokenManager* getTokenManager() override { return &mTokenManager; }
     std::unique_ptr<frametimeline::SurfaceFrame> createSurfaceFrameForToken(
             const std::string& layerName, std::optional<int64_t> token) override;
     void addSurfaceFrame(std::unique_ptr<frametimeline::SurfaceFrame> surfaceFrame,
@@ -184,7 +190,7 @@
     void setSfWakeUp(int64_t token, nsecs_t wakeupTime) override;
     void setSfPresent(nsecs_t sfPresentTime,
                       const std::shared_ptr<FenceTime>& presentFence) override;
-    void dump(std::string& result);
+    void dump(std::string& result) override;
 
 private:
     // Friend class for testing
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index f77a828..5dad4a9 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -1024,6 +1024,7 @@
     // Can only be accessed with the SF state lock held.
     bool mChildrenChanged{false};
 
+    // Can only be accessed with the SF state lock held.
     std::optional<int64_t> mFrameTimelineVsyncId;
 
     // Window types from WindowManager.LayoutParams
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index 77b2f42..3307388 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -40,6 +40,7 @@
 #include <utils/Trace.h>
 
 #include "EventThread.h"
+#include "FrameTimeline.h"
 #include "HwcStrongTypes.h"
 
 using namespace std::chrono_literals;
@@ -166,8 +167,10 @@
 namespace impl {
 
 EventThread::EventThread(std::unique_ptr<VSyncSource> vsyncSource,
+                         android::frametimeline::TokenManager* tokenManager,
                          InterceptVSyncsCallback interceptVSyncsCallback)
       : mVSyncSource(std::move(vsyncSource)),
+        mTokenManager(tokenManager),
         mInterceptVSyncsCallback(std::move(interceptVSyncsCallback)),
         mThreadName(mVSyncSource->getName()) {
     mVSyncSource->setCallback(this);
@@ -292,9 +295,16 @@
     std::lock_guard<std::mutex> lock(mMutex);
 
     LOG_FATAL_IF(!mVSyncState);
-    // TODO(b/162890590): use TokenManager to populate vsyncId
+    const int64_t vsyncId = [&] {
+        if (mTokenManager != nullptr) {
+            return mTokenManager->generateTokenForPredictions(
+                    {timestamp, deadlineTimestamp, expectedVSyncTimestamp});
+        }
+        return static_cast<int64_t>(0);
+    }();
+
     mPendingEvents.push_back(makeVSync(mVSyncState->displayId, timestamp, ++mVSyncState->count,
-                                       expectedVSyncTimestamp, deadlineTimestamp, /*vsyncId=*/0));
+                                       expectedVSyncTimestamp, deadlineTimestamp, vsyncId));
     mCondition.notify_all();
 }
 
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index fa1ca64..80bd606 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -41,6 +41,10 @@
 class EventThreadTest;
 class SurfaceFlinger;
 
+namespace frametimeline {
+class TokenManager;
+} // namespace frametimeline
+
 // ---------------------------------------------------------------------------
 
 using ResyncCallback = std::function<void()>;
@@ -137,7 +141,8 @@
 public:
     using InterceptVSyncsCallback = std::function<void(nsecs_t)>;
 
-    EventThread(std::unique_ptr<VSyncSource>, InterceptVSyncsCallback);
+    EventThread(std::unique_ptr<VSyncSource>, frametimeline::TokenManager*,
+                InterceptVSyncsCallback);
     ~EventThread();
 
     sp<EventThreadConnection> createEventConnection(
@@ -185,6 +190,7 @@
                       nsecs_t deadlineTimestamp) override;
 
     const std::unique_ptr<VSyncSource> mVSyncSource GUARDED_BY(mMutex);
+    frametimeline::TokenManager* const mTokenManager;
 
     const InterceptVSyncsCallback mInterceptVSyncsCallback;
     const char* const mThreadName;
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.cpp b/services/surfaceflinger/Scheduler/MessageQueue.cpp
index 6067e69..641a0a3 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.cpp
+++ b/services/surfaceflinger/Scheduler/MessageQueue.cpp
@@ -39,8 +39,9 @@
     }
 }
 
-void MessageQueue::Handler::dispatchInvalidate(nsecs_t expectedVSyncTimestamp) {
+void MessageQueue::Handler::dispatchInvalidate(int64_t vsyncId, nsecs_t expectedVSyncTimestamp) {
     if ((android_atomic_or(eventMaskInvalidate, &mEventMask) & eventMaskInvalidate) == 0) {
+        mVsyncId = vsyncId;
         mExpectedVSyncTime = expectedVSyncTimestamp;
         mQueue.mLooper->sendMessage(this, Message(MessageQueue::INVALIDATE));
     }
@@ -50,11 +51,11 @@
     switch (message.what) {
         case INVALIDATE:
             android_atomic_and(~eventMaskInvalidate, &mEventMask);
-            mQueue.mFlinger->onMessageReceived(message.what, mExpectedVSyncTime);
+            mQueue.mFlinger->onMessageReceived(message.what, mVsyncId, mExpectedVSyncTime);
             break;
         case REFRESH:
             android_atomic_and(~eventMaskRefresh, &mEventMask);
-            mQueue.mFlinger->onMessageReceived(message.what, mExpectedVSyncTime);
+            mQueue.mFlinger->onMessageReceived(message.what, mVsyncId, mExpectedVSyncTime);
             break;
     }
 }
@@ -123,7 +124,8 @@
     while ((n = DisplayEventReceiver::getEvents(&mEventTube, buffer, 8)) > 0) {
         for (int i = 0; i < n; i++) {
             if (buffer[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
-                mHandler->dispatchInvalidate(buffer[i].vsync.expectedVSyncTimestamp);
+                mHandler->dispatchInvalidate(buffer[i].vsync.vsyncId,
+                                             buffer[i].vsync.expectedVSyncTimestamp);
                 break;
             }
         }
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.h b/services/surfaceflinger/Scheduler/MessageQueue.h
index 132b416..e263b2f 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.h
+++ b/services/surfaceflinger/Scheduler/MessageQueue.h
@@ -79,13 +79,14 @@
         enum { eventMaskInvalidate = 0x1, eventMaskRefresh = 0x2, eventMaskTransaction = 0x4 };
         MessageQueue& mQueue;
         int32_t mEventMask;
+        std::atomic<int64_t> mVsyncId;
         std::atomic<nsecs_t> mExpectedVSyncTime;
 
     public:
         explicit Handler(MessageQueue& queue) : mQueue(queue), mEventMask(0) {}
         virtual void handleMessage(const Message& message);
         void dispatchRefresh();
-        void dispatchInvalidate(nsecs_t expectedVSyncTimestamp);
+        void dispatchInvalidate(int64_t vsyncId, nsecs_t expectedVSyncTimestamp);
     };
 
     friend class Handler;
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 5271ccc..9c145cc 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -31,6 +31,7 @@
 #include <utils/Timers.h>
 #include <utils/Trace.h>
 
+#include <FrameTimeline/FrameTimeline.h>
 #include <algorithm>
 #include <cinttypes>
 #include <cstdint>
@@ -212,11 +213,11 @@
 }
 
 Scheduler::ConnectionHandle Scheduler::createConnection(
-        const char* connectionName, std::chrono::nanoseconds workDuration,
-        std::chrono::nanoseconds readyDuration,
+        const char* connectionName, frametimeline::TokenManager* tokenManager,
+        std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration,
         impl::EventThread::InterceptVSyncsCallback interceptCallback) {
     auto vsyncSource = makePrimaryDispSyncSource(connectionName, workDuration, readyDuration);
-    auto eventThread = std::make_unique<impl::EventThread>(std::move(vsyncSource),
+    auto eventThread = std::make_unique<impl::EventThread>(std::move(vsyncSource), tokenManager,
                                                            std::move(interceptCallback));
     return createConnection(std::move(eventThread));
 }
@@ -332,6 +333,7 @@
 
         auto eventThread =
                 std::make_unique<impl::EventThread>(std::move(vsyncSource),
+                                                    /*tokenManager=*/nullptr,
                                                     impl::EventThread::InterceptVSyncsCallback());
 
         mInjectorConnectionHandle = createConnection(std::move(eventThread));
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 0b5c9d2..da25f5c 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -50,6 +50,10 @@
 class VSyncTracker;
 } // namespace scheduler
 
+namespace frametimeline {
+class TokenManager;
+} // namespace frametimeline
+
 struct ISchedulerCallback {
     virtual void setVsyncEnabled(bool) = 0;
     virtual void changeRefreshRate(const scheduler::RefreshRateConfigs::RefreshRate&,
@@ -70,7 +74,7 @@
     ~Scheduler();
 
     using ConnectionHandle = scheduler::ConnectionHandle;
-    ConnectionHandle createConnection(const char* connectionName,
+    ConnectionHandle createConnection(const char* connectionName, frametimeline::TokenManager*,
                                       std::chrono::nanoseconds workDuration,
                                       std::chrono::nanoseconds readyDuration,
                                       impl::EventThread::InterceptVSyncsCallback);
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index e860dff..f1f67cc 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -331,7 +331,7 @@
         mInterceptor(mFactory.createSurfaceInterceptor(this)),
         mTimeStats(std::make_shared<impl::TimeStats>()),
         mFrameTracer(std::make_unique<FrameTracer>()),
-        mFrameTimeline(std::make_shared<frametimeline::impl::FrameTimeline>()),
+        mFrameTimeline(std::make_unique<frametimeline::impl::FrameTimeline>()),
         mEventQueue(mFactory.createMessageQueue()),
         mCompositionEngine(mFactory.createCompositionEngine()),
         mInternalDisplayDensity(getDensityFromProperty("ro.sf.lcd_density", true)),
@@ -1710,11 +1710,11 @@
                                                           : stats.vsyncTime + stats.vsyncPeriod;
 }
 
-void SurfaceFlinger::onMessageReceived(int32_t what, nsecs_t expectedVSyncTime) {
+void SurfaceFlinger::onMessageReceived(int32_t what, int64_t vsyncId, nsecs_t expectedVSyncTime) {
     ATRACE_CALL();
     switch (what) {
         case MessageQueue::INVALIDATE: {
-            onMessageInvalidate(expectedVSyncTime);
+            onMessageInvalidate(vsyncId, expectedVSyncTime);
             break;
         }
         case MessageQueue::REFRESH: {
@@ -1724,7 +1724,7 @@
     }
 }
 
-void SurfaceFlinger::onMessageInvalidate(nsecs_t expectedVSyncTime) {
+void SurfaceFlinger::onMessageInvalidate(int64_t vsyncId, nsecs_t expectedVSyncTime) {
     ATRACE_CALL();
 
     const nsecs_t frameStart = systemTime();
@@ -1850,6 +1850,8 @@
     {
         ConditionalLockGuard<std::mutex> lock(mTracingLock, mTracingEnabled);
 
+        mFrameTimeline->setSfWakeUp(vsyncId, frameStart);
+
         refreshNeeded = handleMessageTransaction();
         refreshNeeded |= handleMessageInvalidate();
         if (mTracingEnabled) {
@@ -1977,6 +1979,9 @@
     postFrame();
     postComposition();
 
+    mFrameTimeline->setSfPresent(systemTime(),
+                                 std::make_shared<FenceTime>(mPreviousPresentFences[0]));
+
     const bool prevFrameHadDeviceComposition = mHadDeviceComposition;
 
     mHadClientComposition = std::any_of(displays.cbegin(), displays.cend(), [](const auto& pair) {
@@ -2864,12 +2869,12 @@
     mScheduler = getFactory().createScheduler(*mRefreshRateConfigs, *this);
     const auto configs = mVsyncConfiguration->getCurrentConfigs();
     mAppConnectionHandle =
-            mScheduler->createConnection("app",
+            mScheduler->createConnection("app", mFrameTimeline->getTokenManager(),
                                          /*workDuration=*/configs.late.appWorkDuration,
                                          /*readyDuration=*/configs.late.sfWorkDuration,
                                          impl::EventThread::InterceptVSyncsCallback());
     mSfConnectionHandle =
-            mScheduler->createConnection("sf",
+            mScheduler->createConnection("sf", mFrameTimeline->getTokenManager(),
                                          /*workDuration=*/configs.late.sfWorkDuration,
                                          /*readyDuration=*/0ns, [this](nsecs_t timestamp) {
                                              mInterceptor->saveVSyncEvent(timestamp);
@@ -4240,6 +4245,7 @@
                 {"--timestats"s, protoDumper(&SurfaceFlinger::dumpTimeStats)},
                 {"--vsync"s, dumper(&SurfaceFlinger::dumpVSync)},
                 {"--wide-color"s, dumper(&SurfaceFlinger::dumpWideColorInfo)},
+                {"--frametimeline"s, dumper([this](std::string& s) { mFrameTimeline->dump(s); })},
         };
 
         const auto flag = args.empty() ? ""s : std::string(String8(args[0]));
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 361377d..305dbf8 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -303,7 +303,7 @@
     // called on the main thread by MessageQueue when an internal message
     // is received
     // TODO: this should be made accessible only to MessageQueue
-    void onMessageReceived(int32_t what, nsecs_t expectedVSyncTime);
+    void onMessageReceived(int32_t what, int64_t vsyncId, nsecs_t expectedVSyncTime);
 
     renderengine::RenderEngine& getRenderEngine() const;
 
@@ -671,7 +671,7 @@
 
     // Handle the INVALIDATE message queue event, latching new buffers and applying
     // incoming transactions
-    void onMessageInvalidate(nsecs_t expectedVSyncTime);
+    void onMessageInvalidate(int64_t vsyncId, nsecs_t expectedVSyncTime);
 
     // Returns whether the transaction actually modified any state
     bool handleMessageTransaction();
@@ -1112,7 +1112,7 @@
     volatile nsecs_t mDebugInTransaction = 0;
     bool mForceFullDamage = false;
     bool mPropagateBackpressureClientComposition = false;
-    std::unique_ptr<SurfaceInterceptor> mInterceptor;
+    sp<SurfaceInterceptor> mInterceptor;
 
     SurfaceTracing mTracing{*this};
     std::mutex mTracingLock;
@@ -1122,7 +1122,7 @@
 
     const std::shared_ptr<TimeStats> mTimeStats;
     const std::unique_ptr<FrameTracer> mFrameTracer;
-    const std::shared_ptr<frametimeline::FrameTimeline> mFrameTimeline;
+    const std::unique_ptr<frametimeline::FrameTimeline> mFrameTimeline;
     bool mUseHwcVirtualDisplays = false;
     // If blurs should be enabled on this device.
     bool mSupportsBlur = false;
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
index fb08e69..93d36a6 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
@@ -68,9 +68,8 @@
     return std::make_unique<Scheduler>(configs, callback);
 }
 
-std::unique_ptr<SurfaceInterceptor> DefaultFactory::createSurfaceInterceptor(
-        SurfaceFlinger* flinger) {
-    return std::make_unique<android::impl::SurfaceInterceptor>(flinger);
+sp<SurfaceInterceptor> DefaultFactory::createSurfaceInterceptor(SurfaceFlinger* flinger) {
+    return new android::impl::SurfaceInterceptor(flinger);
 }
 
 sp<StartPropertySetThread> DefaultFactory::createStartPropertySetThread(
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
index 86e5a7a..e06c2f4 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
@@ -32,7 +32,7 @@
             const scheduler::RefreshRateConfigs&) override;
     std::unique_ptr<Scheduler> createScheduler(const scheduler::RefreshRateConfigs&,
                                                ISchedulerCallback&) override;
-    std::unique_ptr<SurfaceInterceptor> createSurfaceInterceptor(SurfaceFlinger*) override;
+    sp<SurfaceInterceptor> createSurfaceInterceptor(SurfaceFlinger*) override;
     sp<StartPropertySetThread> createStartPropertySetThread(bool timestampPropertyValue) override;
     sp<DisplayDevice> createDisplayDevice(DisplayDeviceCreationArgs&) override;
     sp<GraphicBuffer> createGraphicBuffer(uint32_t width, uint32_t height, PixelFormat format,
diff --git a/services/surfaceflinger/SurfaceFlingerFactory.h b/services/surfaceflinger/SurfaceFlingerFactory.h
index 753476e..41ccc10 100644
--- a/services/surfaceflinger/SurfaceFlingerFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerFactory.h
@@ -73,7 +73,7 @@
             const scheduler::RefreshRateConfigs&) = 0;
     virtual std::unique_ptr<Scheduler> createScheduler(const scheduler::RefreshRateConfigs&,
                                                        ISchedulerCallback&) = 0;
-    virtual std::unique_ptr<SurfaceInterceptor> createSurfaceInterceptor(SurfaceFlinger*) = 0;
+    virtual sp<SurfaceInterceptor> createSurfaceInterceptor(SurfaceFlinger*) = 0;
 
     virtual sp<StartPropertySetThread> createStartPropertySetThread(
             bool timestampPropertyValue) = 0;
diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp
index c15d0df..d6b5338 100644
--- a/services/surfaceflinger/SurfaceInterceptor.cpp
+++ b/services/surfaceflinger/SurfaceInterceptor.cpp
@@ -45,6 +45,11 @@
 {
 }
 
+void SurfaceInterceptor::binderDied(const wp<IBinder>& who) {
+    // TODO: Implement
+    (void)who;
+}
+
 void SurfaceInterceptor::enable(const SortedVector<sp<Layer>>& layers,
         const DefaultKeyedVector< wp<IBinder>, DisplayDeviceState>& displays)
 {
diff --git a/services/surfaceflinger/SurfaceInterceptor.h b/services/surfaceflinger/SurfaceInterceptor.h
index 1798b5a..62cc717 100644
--- a/services/surfaceflinger/SurfaceInterceptor.h
+++ b/services/surfaceflinger/SurfaceInterceptor.h
@@ -21,6 +21,8 @@
 
 #include <mutex>
 
+#include <binder/IBinder.h>
+
 #include <gui/LayerState.h>
 
 #include <utils/KeyedVector.h>
@@ -48,7 +50,7 @@
 
 constexpr auto DEFAULT_FILENAME = "/data/misc/wmtrace/transaction_trace.pb";
 
-class SurfaceInterceptor {
+class SurfaceInterceptor : public IBinder::DeathRecipient {
 public:
     virtual ~SurfaceInterceptor();
 
@@ -58,6 +60,8 @@
     virtual void disable() = 0;
     virtual bool isEnabled() = 0;
 
+    virtual void binderDied(const wp<IBinder>& who) = 0;
+
     // Intercept display and surface transactions
     virtual void saveTransaction(
             const Vector<ComposerState>& stateUpdates,
@@ -95,6 +99,8 @@
     void disable() override;
     bool isEnabled() override;
 
+    void binderDied(const wp<IBinder>& who) override;
+
     // Intercept display and surface transactions
     void saveTransaction(const Vector<ComposerState>& stateUpdates,
                          const DefaultKeyedVector<wp<IBinder>, DisplayDeviceState>& displays,
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index 9354c0d..b750d6b 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -155,7 +155,7 @@
     renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine();
     Hwc2::mock::Composer* mComposer = nullptr;
     mock::MessageQueue* mMessageQueue = new mock::MessageQueue();
-    mock::SurfaceInterceptor* mSurfaceInterceptor = new mock::SurfaceInterceptor();
+    sp<mock::SurfaceInterceptor> mSurfaceInterceptor = new mock::SurfaceInterceptor;
 
     mock::VsyncController* mVsyncController = new mock::VsyncController;
     mock::VSyncTracker* mVSyncTracker = new mock::VSyncTracker;
@@ -194,7 +194,7 @@
     injectMockScheduler();
     mFlinger.mutableEventQueue().reset(mMessageQueue);
     mFlinger.setupRenderEngine(std::unique_ptr<renderengine::RenderEngine>(mRenderEngine));
-    mFlinger.mutableInterceptor().reset(mSurfaceInterceptor);
+    mFlinger.mutableInterceptor() = mSurfaceInterceptor;
 
     injectMockComposer(0);
 }
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index ae94f16..f680bdb 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -141,6 +141,7 @@
 
 void EventThreadTest::createThread(std::unique_ptr<VSyncSource> source) {
     mThread = std::make_unique<impl::EventThread>(std::move(source),
+                                                  /*tokenManager=*/nullptr,
                                                   mInterceptVSyncCallRecorder.getInvocable());
 
     // EventThread should register itself as VSyncSource callback.
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 89476e9..98b20e8 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -83,8 +83,8 @@
         return nullptr;
     }
 
-    std::unique_ptr<SurfaceInterceptor> createSurfaceInterceptor(SurfaceFlinger* flinger) override {
-        return std::make_unique<android::impl::SurfaceInterceptor>(flinger);
+    sp<SurfaceInterceptor> createSurfaceInterceptor(SurfaceFlinger* flinger) override {
+        return new android::impl::SurfaceInterceptor(flinger);
     }
 
     sp<StartPropertySetThread> createStartPropertySetThread(bool timestampPropertyValue) override {
@@ -323,7 +323,9 @@
         return mFlinger->setPowerModeInternal(display, mode);
     }
 
-    auto onMessageReceived(int32_t what) { return mFlinger->onMessageReceived(what, systemTime()); }
+    auto onMessageReceived(int32_t what) {
+        return mFlinger->onMessageReceived(what, /*vsyncId=*/0, systemTime());
+    }
 
     auto renderScreenImplLocked(const RenderArea& renderArea,
                                 SurfaceFlinger::TraverseLayersFunction traverseLayers,
@@ -422,7 +424,7 @@
         mutableCurrentState().displays.clear();
         mutableDrawingState().displays.clear();
         mutableEventQueue().reset();
-        mutableInterceptor().reset();
+        mutableInterceptor().clear();
         mFlinger->mScheduler.reset();
         mFlinger->mCompositionEngine->setHwComposer(std::unique_ptr<HWComposer>());
         mFlinger->mCompositionEngine->setRenderEngine(
diff --git a/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.h b/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.h
index ccb7bb9..2f3f524 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.h
@@ -33,6 +33,7 @@
                       const DefaultKeyedVector<wp<IBinder>, DisplayDeviceState>&));
     MOCK_METHOD0(disable, void());
     MOCK_METHOD0(isEnabled, bool());
+    MOCK_METHOD1(binderDied, void(const wp<IBinder>&));
     MOCK_METHOD6(saveTransaction,
                  void(const Vector<ComposerState>&,
                       const DefaultKeyedVector<wp<IBinder>, DisplayDeviceState>&,