Merge "Adding aidl file to share deviceProductInfo constants bw java and c++" into sc-dev
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index cfc405a..3a2c769 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1208,10 +1208,6 @@
 
 static void DumpPacketStats() {
     DumpFile("NETWORK DEV INFO", "/proc/net/dev");
-    DumpFile("QTAGUID NETWORK INTERFACES INFO", "/proc/net/xt_qtaguid/iface_stat_all");
-    DumpFile("QTAGUID NETWORK INTERFACES INFO (xt)", "/proc/net/xt_qtaguid/iface_stat_fmt");
-    DumpFile("QTAGUID CTRL INFO", "/proc/net/xt_qtaguid/ctrl");
-    DumpFile("QTAGUID STATS INFO", "/proc/net/xt_qtaguid/stats");
 }
 
 static void DumpIpAddrAndRules() {
diff --git a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
index a7a6563..c20d9f6 100644
--- a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
+++ b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
@@ -113,5 +113,14 @@
      * Returns the debug flag for the given package.
      * Unknown packages will cause the call to fail.
      */
-     boolean isPackageDebuggable(in String packageName);
+    boolean isPackageDebuggable(in String packageName);
+
+    /**
+     * Check whether the given feature name and version is one of the available
+     * features as returned by {@link PackageManager#getSystemAvailableFeatures()}. Since
+     * features are defined to always be backwards compatible, this returns true
+     * if the available feature version is greater than or equal to the
+     * requested version.
+     */
+    boolean hasSystemFeature(in String featureName, in int version);
 }
diff --git a/libs/binder/ndk/include_cpp/android/binder_to_string.h b/libs/binder/ndk/include_cpp/android/binder_to_string.h
index 5842925..ef71a81 100644
--- a/libs/binder/ndk/include_cpp/android/binder_to_string.h
+++ b/libs/binder/ndk/include_cpp/android/binder_to_string.h
@@ -136,8 +136,7 @@
     template <typename _U>
     static std::enable_if_t<
 #ifdef HAS_NDK_INTERFACE
-            std::is_base_of_v<::ndk::ICInterface, _U> || std::is_same_v<::ndk::SpAIBinder, _U> ||
-                    std::is_same_v<::ndk::ScopedFileDescriptor, _U> ||
+            std::is_base_of_v<::ndk::ICInterface, _U> ||
                     std::is_same_v<::ndk::AParcelableHolder, _U>
 #else
             std::is_base_of_v<IInterface, _U> || std::is_same_v<IBinder, _U> ||
@@ -168,13 +167,19 @@
         return std::to_string(t);
     } else if constexpr (std::is_same_v<std::string, _T>) {
         return t;
+#ifdef HAS_NDK_INTERFACE
+    } else if constexpr (std::is_same_v<::ndk::SpAIBinder, _T>) {
+        return (t.get() == nullptr) ? "(null)" : "";
+    } else if constexpr (std::is_same_v<::ndk::ScopedFileDescriptor, _T>) {
+        return (t.get() == -1) ? "(null)" : "";
+#endif
 #ifdef HAS_STRING16
     } else if constexpr (std::is_same_v<String16, _T>) {
         std::stringstream out;
         out << t;
         return out.str();
 #endif
-    } else if constexpr (details::IsPointerLike<_T>::value) {
+    } else if constexpr (details::IsPointerLike<_T>::value || std::is_pointer_v<_T>) {
         if (!t) return "(null)";
         std::stringstream out;
         out << ToString(*t);
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index dc91fc6..ff059d7 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -149,6 +149,10 @@
         sampling: true,
         profile_file: "libgui/libgui.profdata",
     },
+
+    lto: {
+        thin: true,
+    },
 }
 
 // Used by media codec services exclusively as a static lib for
diff --git a/libs/renderengine/RenderEngine.cpp b/libs/renderengine/RenderEngine.cpp
index b2ad22d..79839c1 100644
--- a/libs/renderengine/RenderEngine.cpp
+++ b/libs/renderengine/RenderEngine.cpp
@@ -49,7 +49,8 @@
         case RenderEngineType::THREADED:
             ALOGD("Threaded RenderEngine with GLES Backend");
             return renderengine::threaded::RenderEngineThreaded::create(
-                    [args]() { return android::renderengine::gl::GLESRenderEngine::create(args); });
+                    [args]() { return android::renderengine::gl::GLESRenderEngine::create(args); },
+                    renderEngineType);
         case RenderEngineType::SKIA_GL:
             ALOGD("RenderEngine with SkiaGL Backend");
             return renderengine::skia::SkiaGLRenderEngine::create(args);
@@ -66,12 +67,14 @@
                             .setPrecacheToneMapperShaderOnly(args.precacheToneMapperShaderOnly)
                             .setSupportsBackgroundBlur(args.supportsBackgroundBlur)
                             .setContextPriority(args.contextPriority)
-                            .setRenderEngineType(RenderEngineType::SKIA_GL_THREADED)
+                            .setRenderEngineType(renderEngineType)
                             .build();
             ALOGD("Threaded RenderEngine with SkiaGL Backend");
-            return renderengine::threaded::RenderEngineThreaded::create([skiaArgs]() {
-                return android::renderengine::skia::SkiaGLRenderEngine::create(skiaArgs);
-            });
+            return renderengine::threaded::RenderEngineThreaded::create(
+                    [skiaArgs]() {
+                        return android::renderengine::skia::SkiaGLRenderEngine::create(skiaArgs);
+                    },
+                    renderEngineType);
         }
         case RenderEngineType::GLES:
         default:
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index 70ae0b2..397f038 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -379,7 +379,8 @@
 GLESRenderEngine::GLESRenderEngine(const RenderEngineCreationArgs& args, EGLDisplay display,
                                    EGLConfig config, EGLContext ctxt, EGLSurface stub,
                                    EGLContext protectedContext, EGLSurface protectedStub)
-      : mEGLDisplay(display),
+      : RenderEngine(args.renderEngineType),
+        mEGLDisplay(display),
         mEGLConfig(config),
         mEGLContext(ctxt),
         mStubSurface(stub),
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index 163a163..572d348 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -87,6 +87,10 @@
 
     static std::unique_ptr<RenderEngine> create(const RenderEngineCreationArgs& args);
 
+    RenderEngine() : RenderEngine(RenderEngineType::GLES) {}
+
+    RenderEngine(RenderEngineType type) : mRenderEngineType(type) {}
+
     virtual ~RenderEngine() = 0;
 
     // ----- BEGIN DEPRECATED INTERFACE -----
@@ -192,8 +196,14 @@
     // also supports background blur.  If false, no blur will be applied when drawing layers.
     virtual bool supportsBackgroundBlur() = 0;
 
+    // Returns the current type of RenderEngine instance that was created.
+    // TODO(b/180767535): This is only implemented to allow for backend-specific behavior, which
+    // we should not allow in general, so remove this.
+    RenderEngineType getRenderEngineType() const { return mRenderEngineType; }
+
 protected:
     friend class threaded::RenderEngineThreaded;
+    const RenderEngineType mRenderEngineType;
 };
 
 struct RenderEngineCreationArgs {
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index 6c6db46..cbb02a3 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -266,13 +266,13 @@
 SkiaGLRenderEngine::SkiaGLRenderEngine(const RenderEngineCreationArgs& args, EGLDisplay display,
                                        EGLContext ctxt, EGLSurface placeholder,
                                        EGLContext protectedContext, EGLSurface protectedPlaceholder)
-      : mEGLDisplay(display),
+      : SkiaRenderEngine(args.renderEngineType),
+        mEGLDisplay(display),
         mEGLContext(ctxt),
         mPlaceholderSurface(placeholder),
         mProtectedEGLContext(protectedContext),
         mProtectedPlaceholderSurface(protectedPlaceholder),
-        mUseColorManagement(args.useColorManagement),
-        mRenderEngineType(args.renderEngineType) {
+        mUseColorManagement(args.useColorManagement) {
     sk_sp<const GrGLInterface> glInterface(GrGLCreateNativeInterface());
     LOG_ALWAYS_FATAL_IF(!glInterface.get());
 
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h
index ad26206..1c3a633 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.h
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.h
@@ -130,10 +130,6 @@
     bool mInProtectedContext = false;
     // Object to capture commands send to Skia.
     std::unique_ptr<SkiaCapture> mCapture;
-
-    // Keep this information as a local variable to determine whether the access of the GL
-    // operations is working on the same threads.
-    const RenderEngineType mRenderEngineType = RenderEngineType::SKIA_GL;
 };
 
 } // namespace skia
diff --git a/libs/renderengine/skia/SkiaRenderEngine.h b/libs/renderengine/skia/SkiaRenderEngine.h
index 12b8586..79a1040 100644
--- a/libs/renderengine/skia/SkiaRenderEngine.h
+++ b/libs/renderengine/skia/SkiaRenderEngine.h
@@ -36,6 +36,7 @@
 class SkiaRenderEngine : public RenderEngine {
 public:
     static std::unique_ptr<SkiaRenderEngine> create(const RenderEngineCreationArgs& args);
+    SkiaRenderEngine(RenderEngineType type) : RenderEngine(type) {}
     ~SkiaRenderEngine() override {}
 
     virtual void primeCache() const override{};
diff --git a/libs/renderengine/tests/RenderEngineThreadedTest.cpp b/libs/renderengine/tests/RenderEngineThreadedTest.cpp
index 08b672a..63aa4c8 100644
--- a/libs/renderengine/tests/RenderEngineThreadedTest.cpp
+++ b/libs/renderengine/tests/RenderEngineThreadedTest.cpp
@@ -32,7 +32,8 @@
 
     void SetUp() override {
         mThreadedRE = renderengine::threaded::RenderEngineThreaded::create(
-                [this]() { return std::unique_ptr<renderengine::RenderEngine>(mRenderEngine); });
+                [this]() { return std::unique_ptr<renderengine::RenderEngine>(mRenderEngine); },
+                renderengine::RenderEngine::RenderEngineType::THREADED);
     }
 
     std::unique_ptr<renderengine::threaded::RenderEngineThreaded> mThreadedRE;
diff --git a/libs/renderengine/threaded/RenderEngineThreaded.cpp b/libs/renderengine/threaded/RenderEngineThreaded.cpp
index f448135..7c7d165 100644
--- a/libs/renderengine/threaded/RenderEngineThreaded.cpp
+++ b/libs/renderengine/threaded/RenderEngineThreaded.cpp
@@ -34,11 +34,13 @@
 namespace renderengine {
 namespace threaded {
 
-std::unique_ptr<RenderEngineThreaded> RenderEngineThreaded::create(CreateInstanceFactory factory) {
-    return std::make_unique<RenderEngineThreaded>(std::move(factory));
+std::unique_ptr<RenderEngineThreaded> RenderEngineThreaded::create(CreateInstanceFactory factory,
+                                                                   RenderEngineType type) {
+    return std::make_unique<RenderEngineThreaded>(std::move(factory), type);
 }
 
-RenderEngineThreaded::RenderEngineThreaded(CreateInstanceFactory factory) {
+RenderEngineThreaded::RenderEngineThreaded(CreateInstanceFactory factory, RenderEngineType type)
+      : RenderEngine(type) {
     ATRACE_CALL();
 
     std::lock_guard lockThread(mThreadMutex);
diff --git a/libs/renderengine/threaded/RenderEngineThreaded.h b/libs/renderengine/threaded/RenderEngineThreaded.h
index 8279cbc..d362e17 100644
--- a/libs/renderengine/threaded/RenderEngineThreaded.h
+++ b/libs/renderengine/threaded/RenderEngineThreaded.h
@@ -37,9 +37,10 @@
  */
 class RenderEngineThreaded : public RenderEngine {
 public:
-    static std::unique_ptr<RenderEngineThreaded> create(CreateInstanceFactory factory);
+    static std::unique_ptr<RenderEngineThreaded> create(CreateInstanceFactory factory,
+                                                        RenderEngineType type);
 
-    RenderEngineThreaded(CreateInstanceFactory factory);
+    RenderEngineThreaded(CreateInstanceFactory factory, RenderEngineType type);
     ~RenderEngineThreaded() override;
     void primeCache() const override;
 
diff --git a/opengl/libs/EGL/egl_angle_platform.cpp b/opengl/libs/EGL/egl_angle_platform.cpp
index dc8e587..c29181d 100644
--- a/opengl/libs/EGL/egl_angle_platform.cpp
+++ b/opengl/libs/EGL/egl_angle_platform.cpp
@@ -129,8 +129,8 @@
         return false;
     }
 
-    angleResetDisplayPlatform = reinterpret_cast<ResetDisplayPlatformFunc>(
-            eglGetProcAddress("ANGLEResetDisplayPlatform"));
+    angleResetDisplayPlatform =
+            reinterpret_cast<ResetDisplayPlatformFunc>(dlsym(so, "ANGLEResetDisplayPlatform"));
 
     PlatformMethods* platformMethods = nullptr;
     if (!((angleGetDisplayPlatform)(dpy, g_PlatformMethodNames, g_NumPlatformMethods, nullptr,
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index d0a5c09..465e8be 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -1439,7 +1439,7 @@
     ALOGD("notifySensorEvent eventTime=%" PRId64 ", hwTimestamp=%" PRId64 ", deviceId=%d, "
           "source=0x%x, sensorType=%s",
           entry->eventTime, entry->hwTimestamp, entry->deviceId, entry->source,
-          NamedEnum::string(sensorType).c_str());
+          NamedEnum::string(entry->sensorType).c_str());
 #endif
     std::unique_ptr<CommandEntry> commandEntry =
             std::make_unique<CommandEntry>(&InputDispatcher::doNotifySensorLockedInterruptible);
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index d0a9ca7..1a7fcd5 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -1771,7 +1771,17 @@
     }
 }
 
-status_t EventHub::openDeviceLocked(const std::string& devicePath) {
+void EventHub::openDeviceLocked(const std::string& devicePath) {
+    // If an input device happens to register around the time when EventHub's constructor runs, it
+    // is possible that the same input event node (for example, /dev/input/event3) will be noticed
+    // in both 'inotify' callback and also in the 'scanDirLocked' pass. To prevent duplicate devices
+    // from getting registered, ensure that this path is not already covered by an existing device.
+    for (const auto& [deviceId, device] : mDevices) {
+        if (device->path == devicePath) {
+            return; // device was already registered
+        }
+    }
+
     char buffer[80];
 
     ALOGV("Opening device: %s", devicePath.c_str());
@@ -1779,7 +1789,7 @@
     int fd = open(devicePath.c_str(), O_RDWR | O_CLOEXEC | O_NONBLOCK);
     if (fd < 0) {
         ALOGE("could not open %s, %s\n", devicePath.c_str(), strerror(errno));
-        return -1;
+        return;
     }
 
     InputDeviceIdentifier identifier;
@@ -1798,7 +1808,7 @@
         if (identifier.name == item) {
             ALOGI("ignoring event id %s driver %s\n", devicePath.c_str(), item.c_str());
             close(fd);
-            return -1;
+            return;
         }
     }
 
@@ -1807,7 +1817,7 @@
     if (ioctl(fd, EVIOCGVERSION, &driverVersion)) {
         ALOGE("could not get driver version for %s, %s\n", devicePath.c_str(), strerror(errno));
         close(fd);
-        return -1;
+        return;
     }
 
     // Get device identifier.
@@ -1815,7 +1825,7 @@
     if (ioctl(fd, EVIOCGID, &inputId)) {
         ALOGE("could not get device input id for %s, %s\n", devicePath.c_str(), strerror(errno));
         close(fd);
-        return -1;
+        return;
     }
     identifier.bus = inputId.bustype;
     identifier.product = inputId.product;
@@ -2013,7 +2023,7 @@
     if (device->classes == Flags<InputDeviceClass>(0)) {
         ALOGV("Dropping device: id=%d, path='%s', name='%s'", deviceId, devicePath.c_str(),
               device->identifier.name.c_str());
-        return -1;
+        return;
     }
 
     // Classify InputDeviceClass::BATTERY.
@@ -2043,7 +2053,7 @@
     }
 
     if (registerDeviceForEpollLocked(*device) != OK) {
-        return -1;
+        return;
     }
 
     device->configureFd();
@@ -2056,7 +2066,6 @@
           toString(mBuiltInKeyboardId == deviceId));
 
     addDeviceLocked(std::move(device));
-    return OK;
 }
 
 void EventHub::openVideoDeviceLocked(const std::string& devicePath) {
diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h
index 4059729..5e5f85e 100644
--- a/services/inputflinger/reader/include/EventHub.h
+++ b/services/inputflinger/reader/include/EventHub.h
@@ -567,7 +567,10 @@
         bool configureLightsLocked();
     };
 
-    status_t openDeviceLocked(const std::string& devicePath);
+    /**
+     * Create a new device for the provided path.
+     */
+    void openDeviceLocked(const std::string& devicePath);
     void openVideoDeviceLocked(const std::string& devicePath);
     /**
      * Try to associate a video device with an input device. If the association succeeds,
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 097f7de..a96dffd 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -414,12 +414,6 @@
         return true;
     }
 
-    // If the next planned present time is not current, return and try again later
-    if (frameIsEarly(expectedPresentTime)) {
-        ATRACE_NAME("frameIsEarly()");
-        return false;
-    }
-
     // If this layer doesn't have a frame is shouldn't be presented
     if (!hasFrameUpdate()) {
         return false;
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
index ff000c9..75229e9 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
@@ -504,6 +504,17 @@
         if (mLastLatchTime != 0 && mPredictions.endTime <= mLastLatchTime) {
             // Buffer Stuffing.
             mJankType |= JankType::BufferStuffing;
+            // In a stuffed state, the frame could be stuck on a dequeue wait for quite some time.
+            // Because of this dequeue wait, it can be hard to tell if a frame was genuinely late.
+            // We try to do this by moving the deadline. Since the queue could be stuffed by more
+            // than one buffer, we take the last latch time as reference and give one vsync
+            // worth of time for the frame to be ready.
+            nsecs_t adjustedDeadline = mLastLatchTime + refreshRate.getPeriodNsecs();
+            if (adjustedDeadline > mActuals.endTime) {
+                mFrameReadyMetadata = FrameReadyMetadata::OnTimeFinish;
+            } else {
+                mFrameReadyMetadata = FrameReadyMetadata::LateFinish;
+            }
         }
         if (mFrameReadyMetadata == FrameReadyMetadata::OnTimeFinish) {
             // Finish on time, Present late
@@ -511,14 +522,18 @@
                 // Propagate displayFrame's jank if it exists
                 mJankType |= displayFrameJankType;
             } else {
-                if (deltaToVsync < mJankClassificationThresholds.presentThreshold ||
-                    deltaToVsync >= refreshRate.getPeriodNsecs() -
-                                    mJankClassificationThresholds.presentThreshold) {
-                    // Delta factor of vsync
-                    mJankType |= JankType::SurfaceFlingerScheduling;
-                } else {
-                    // Delta not a factor of vsync
-                    mJankType |= JankType::PredictionError;
+                if (!(mJankType & JankType::BufferStuffing)) {
+                    // In a stuffed state, if the app finishes on time and there is no display frame
+                    // jank, only buffer stuffing is the root cause of the jank.
+                    if (deltaToVsync < mJankClassificationThresholds.presentThreshold ||
+                        deltaToVsync >= refreshRate.getPeriodNsecs() -
+                                        mJankClassificationThresholds.presentThreshold) {
+                        // Delta factor of vsync
+                        mJankType |= JankType::SurfaceFlingerScheduling;
+                    } else {
+                        // Delta not a factor of vsync
+                        mJankType |= JankType::PredictionError;
+                    }
                 }
             }
         } else if (mFrameReadyMetadata == FrameReadyMetadata::LateFinish) {
@@ -683,13 +698,14 @@
 }
 
 FrameTimeline::FrameTimeline(std::shared_ptr<TimeStats> timeStats, pid_t surfaceFlingerPid,
-                             JankClassificationThresholds thresholds)
+                             JankClassificationThresholds thresholds, nsecs_t hwcDuration)
       : mMaxDisplayFrames(kDefaultMaxDisplayFrames),
         mTimeStats(std::move(timeStats)),
         mSurfaceFlingerPid(surfaceFlingerPid),
-        mJankClassificationThresholds(thresholds) {
-    mCurrentDisplayFrame =
-            std::make_shared<DisplayFrame>(mTimeStats, thresholds, &mTraceCookieCounter);
+        mJankClassificationThresholds(thresholds),
+        mHwcDuration(hwcDuration) {
+    mCurrentDisplayFrame = std::make_shared<DisplayFrame>(mTimeStats, thresholds, hwcDuration,
+                                                          &mTraceCookieCounter);
 }
 
 void FrameTimeline::onBootFinished() {
@@ -732,11 +748,13 @@
 
 FrameTimeline::DisplayFrame::DisplayFrame(std::shared_ptr<TimeStats> timeStats,
                                           JankClassificationThresholds thresholds,
+                                          nsecs_t hwcDuration,
                                           TraceCookieCounter* traceCookieCounter)
       : mSurfaceFlingerPredictions(TimelineItem()),
         mSurfaceFlingerActuals(TimelineItem()),
         mTimeStats(timeStats),
         mJankClassificationThresholds(thresholds),
+        mHwcDuration(hwcDuration),
         mTraceCookieCounter(*traceCookieCounter) {
     mSurfaceFrames.reserve(kNumSurfaceFramesInitial);
 }
@@ -808,7 +826,7 @@
     const nsecs_t presentDelta =
             mSurfaceFlingerActuals.presentTime - mSurfaceFlingerPredictions.presentTime;
     const nsecs_t deadlineDelta =
-            mSurfaceFlingerActuals.endTime - mSurfaceFlingerPredictions.endTime;
+            mSurfaceFlingerActuals.endTime - (mSurfaceFlingerPredictions.endTime - mHwcDuration);
 
     // How far off was the presentDelta when compared to the vsyncPeriod. Used in checking if there
     // was a prediction error or not.
@@ -822,8 +840,9 @@
         mFramePresentMetadata = FramePresentMetadata::OnTimePresent;
     }
 
-    if (mSurfaceFlingerActuals.endTime - mSurfaceFlingerPredictions.endTime >
-        mJankClassificationThresholds.deadlineThreshold) {
+    if (mSurfaceFlingerActuals.endTime > mSurfaceFlingerPredictions.endTime - mHwcDuration) {
+        // SF needs to have finished at least mHwcDuration ahead of the deadline for it to be
+        // on time.
         mFrameReadyMetadata = FrameReadyMetadata::LateFinish;
     } else {
         mFrameReadyMetadata = FrameReadyMetadata::OnTimeFinish;
@@ -875,8 +894,13 @@
                     mJankType = JankType::PredictionError;
                 }
             } else if (mFrameReadyMetadata == FrameReadyMetadata::LateFinish) {
-                // Finish late, Present late
-                mJankType = JankType::SurfaceFlingerCpuDeadlineMissed;
+                if (mFrameStartMetadata == FrameStartMetadata::LateStart) {
+                    // Late start, Late finish, Late Present
+                    mJankType = JankType::SurfaceFlingerScheduling;
+                } else {
+                    // OnTime start, Finish late, Present late
+                    mJankType = JankType::SurfaceFlingerCpuDeadlineMissed;
+                }
             } else {
                 // Finish time unknown
                 mJankType = JankType::Unknown;
@@ -1066,7 +1090,7 @@
     mDisplayFrames.push_back(mCurrentDisplayFrame);
     mCurrentDisplayFrame.reset();
     mCurrentDisplayFrame = std::make_shared<DisplayFrame>(mTimeStats, mJankClassificationThresholds,
-                                                          &mTraceCookieCounter);
+                                                          mHwcDuration, &mTraceCookieCounter);
 }
 
 nsecs_t FrameTimeline::DisplayFrame::getBaseTime() const {
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.h b/services/surfaceflinger/FrameTimeline/FrameTimeline.h
index d65769b..7c6a0cc 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.h
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.h
@@ -342,7 +342,7 @@
     class DisplayFrame {
     public:
         DisplayFrame(std::shared_ptr<TimeStats> timeStats, JankClassificationThresholds thresholds,
-                     TraceCookieCounter* traceCookieCounter);
+                     nsecs_t hwcDuration, TraceCookieCounter* traceCookieCounter);
         virtual ~DisplayFrame() = default;
         // Dumpsys interface - dumps only if the DisplayFrame itself is janky or is at least one
         // SurfaceFrame is janky.
@@ -371,6 +371,7 @@
         // Functions to be used only in testing.
         TimelineItem getActuals() const { return mSurfaceFlingerActuals; };
         TimelineItem getPredictions() const { return mSurfaceFlingerPredictions; };
+        FrameStartMetadata getFrameStartMetadata() const { return mFrameStartMetadata; };
         FramePresentMetadata getFramePresentMetadata() const { return mFramePresentMetadata; };
         FrameReadyMetadata getFrameReadyMetadata() const { return mFrameReadyMetadata; };
         int32_t getJankType() const { return mJankType; }
@@ -394,6 +395,7 @@
         TimelineItem mSurfaceFlingerActuals;
         std::shared_ptr<TimeStats> mTimeStats;
         const JankClassificationThresholds mJankClassificationThresholds;
+        const nsecs_t mHwcDuration;
 
         // Collection of predictions and actual values sent over by Layers
         std::vector<std::shared_ptr<SurfaceFrame>> mSurfaceFrames;
@@ -419,7 +421,8 @@
     };
 
     FrameTimeline(std::shared_ptr<TimeStats> timeStats, pid_t surfaceFlingerPid,
-                  JankClassificationThresholds thresholds = {});
+                  JankClassificationThresholds thresholds = {},
+                  nsecs_t hwcDuration = kDefaultHwcDuration);
     ~FrameTimeline() = default;
 
     frametimeline::TokenManager* getTokenManager() override { return &mTokenManager; }
@@ -464,6 +467,11 @@
     std::shared_ptr<TimeStats> mTimeStats;
     const pid_t mSurfaceFlingerPid;
     const JankClassificationThresholds mJankClassificationThresholds;
+    // In SF Predictions, both end & present are the same. The predictions consider the time used by
+    // composer as well, but we have no way to estimate how much time the composer needs. We are
+    // assuming an arbitrary time for the composer work.
+    const nsecs_t mHwcDuration;
+    static constexpr nsecs_t kDefaultHwcDuration = std::chrono::nanoseconds(3ms).count();
     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
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 23758c9..a072554 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -924,6 +924,8 @@
 
     pid_t getOwnerPid() { return mOwnerPid; }
 
+    virtual bool frameIsEarly(nsecs_t /*expectedPresentTime*/) const { return false; }
+
     // This layer is not a clone, but it's the parent to the cloned hierarchy. The
     // variable mClonedChild represents the top layer that will be cloned so this
     // layer will be the parent of mClonedChild.
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index 09615f9..e06bc88 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -481,6 +481,12 @@
     // 1) The region sampling thread is the last owner of the buffer, and the freeing of the buffer
     // happens in this thread, as opposed to the main thread.
     // 2) The listener(s) receive their notifications prior to freeing the buffer.
+    if (mCachedBuffer != nullptr && mCachedBuffer != buffer) {
+        if (mFlinger.getRenderEngine().getRenderEngineType() ==
+            renderengine::RenderEngine::RenderEngineType::SKIA_GL_THREADED) {
+            mFlinger.getRenderEngine().unbindExternalTextureBuffer(mCachedBuffer->getId());
+        }
+    }
     mCachedBuffer = buffer;
     ATRACE_INT(lumaSamplingStepTag, static_cast<int>(samplingStep::noWorkNeeded));
 }
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 5364adf..350a3c8 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -496,6 +496,9 @@
     // the window manager died on us. prepare its eulogy.
     mBootFinished = false;
 
+    // Sever the link to inputflinger since its gone as well.
+    static_cast<void>(schedule([=] { mInputFlinger = nullptr; }));
+
     // restore initial conditions (default device unblank, etc)
     initializeDisplays();
 
@@ -3361,6 +3364,10 @@
         if (!layer) {
             continue;
         }
+        if (layer->frameIsEarly(expectedPresentTime)) {
+            ATRACE_NAME("frameIsEarly()");
+            return false;
+        }
 
         if (!mScheduler->isVsyncValid(expectedPresentTime, layer->getOwnerUid())) {
             ATRACE_NAME("!isVsyncValidForUid");
@@ -4945,8 +4952,6 @@
         case GET_DISPLAYED_CONTENT_SAMPLE:
         case NOTIFY_POWER_BOOST:
         case SET_GLOBAL_SHADOW_SETTINGS:
-        case ADD_FPS_LISTENER:
-        case REMOVE_FPS_LISTENER:
         case ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN: {
             // ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN is used by CTS tests, which acquire the
             // necessary permission dynamically. Don't use the permission cache for this check.
@@ -5009,6 +5014,8 @@
             // This is not sensitive information, so should not require permission control.
             return OK;
         }
+        case ADD_FPS_LISTENER:
+        case REMOVE_FPS_LISTENER:
         case ADD_REGION_SAMPLING_LISTENER:
         case REMOVE_REGION_SAMPLING_LISTENER: {
             // codes that require permission check
@@ -5865,6 +5872,15 @@
                                             regionSampling, grayscale, captureResults);
         });
 
+        // TODO(b/180767535): Remove this once we optimize buffer lifecycle for RenderEngine
+        // Only do this when we're not doing region sampling, to allow the region sampling thread to
+        // manage buffer lifecycle itself.
+        if (!regionSampling &&
+            getRenderEngine().getRenderEngineType() ==
+                    renderengine::RenderEngine::RenderEngineType::SKIA_GL_THREADED) {
+            getRenderEngine().unbindExternalTextureBuffer(buffer->getId());
+        }
+
         captureResults.result = result;
         captureListener->onScreenCaptureCompleted(captureResults);
     }));
@@ -5984,8 +6000,12 @@
     base::unique_fd bufferFence;
     base::unique_fd drawFence;
     getRenderEngine().useProtectedContext(useProtected);
+
+    // TODO(b/180767535): Remove this once we optimize buffer lifecycle for RenderEngine
+    const bool useFramebufferCache = getRenderEngine().getRenderEngineType() ==
+            renderengine::RenderEngine::RenderEngineType::SKIA_GL_THREADED;
     getRenderEngine().drawLayers(clientCompositionDisplay, clientCompositionLayerPointers, buffer,
-                                 /*useFramebufferCache=*/false, std::move(bufferFence), &drawFence);
+                                 useFramebufferCache, std::move(bufferFence), &drawFence);
 
     if (drawFence >= 0) {
         sp<Fence> releaseFence = new Fence(dup(drawFence));
diff --git a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
index 9a4e020..7e6141e 100644
--- a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
@@ -67,7 +67,7 @@
     void SetUp() override {
         mTimeStats = std::make_shared<mock::TimeStats>();
         mFrameTimeline = std::make_unique<impl::FrameTimeline>(mTimeStats, kSurfaceFlingerPid,
-                                                               kTestThresholds);
+                                                               kTestThresholds, kHwcDuration);
         mFrameTimeline->registerDataSource();
         mTokenManager = &mFrameTimeline->mTokenManager;
         mTraceCookieCounter = &mFrameTimeline->mTraceCookieCounter;
@@ -162,6 +162,7 @@
     static constexpr JankClassificationThresholds kTestThresholds{kPresentThreshold,
                                                                   kDeadlineThreshold,
                                                                   kStartThreshold};
+    static constexpr nsecs_t kHwcDuration = std::chrono::nanoseconds(3ns).count();
 };
 
 static const std::string sLayerNameOne = "layer1";
@@ -420,37 +421,29 @@
 
 // Tests related to TimeStats
 TEST_F(FrameTimelineTest, presentFenceSignaled_reportsLongSfCpu) {
-    Fps refreshRate = Fps(11);
+    Fps refreshRate = Fps::fromPeriodNsecs(11);
+    // Deadline delta is 2ms because, sf's adjusted deadline is 60 - composerTime(3) = 57ms.
     EXPECT_CALL(*mTimeStats,
                 incrementJankyFrames(
                         TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne,
                                                    sLayerNameOne,
-                                                   JankType::SurfaceFlingerCpuDeadlineMissed,
-                                                   std::chrono::duration_cast<
-                                                           std::chrono::nanoseconds>(3ms)
-                                                           .count(),
-                                                   std::chrono::duration_cast<
-                                                           std::chrono::nanoseconds>(10ms)
-                                                           .count(),
+                                                   JankType::SurfaceFlingerCpuDeadlineMissed, 2, 10,
                                                    0}));
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
-    int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions(
-            {std::chrono::nanoseconds(10ms).count(), std::chrono::nanoseconds(20ms).count(),
-             std::chrono::nanoseconds(60ms).count()});
-    int64_t sfToken1 = mTokenManager->generateTokenForPredictions(
-            {std::chrono::nanoseconds(52ms).count(), std::chrono::nanoseconds(56ms).count(),
-             std::chrono::nanoseconds(60ms).count()});
+    int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 60});
+    int64_t sfToken1 = mTokenManager->generateTokenForPredictions({52, 60, 60});
+
     auto surfaceFrame1 =
             mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
                                                        sUidOne, sLayerIdOne, sLayerNameOne,
                                                        sLayerNameOne);
-    mFrameTimeline->setSfWakeUp(sfToken1, std::chrono::nanoseconds(52ms).count(), refreshRate);
-    surfaceFrame1->setAcquireFenceTime(std::chrono::nanoseconds(20ms).count());
+    mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate);
+    surfaceFrame1->setAcquireFenceTime(20);
     surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
     mFrameTimeline->addSurfaceFrame(surfaceFrame1);
-    presentFence1->signalForTest(std::chrono::nanoseconds(70ms).count());
+    presentFence1->signalForTest(70);
 
-    mFrameTimeline->setSfPresent(std::chrono::nanoseconds(59ms).count(), presentFence1);
+    mFrameTimeline->setSfPresent(59, presentFence1);
 }
 
 TEST_F(FrameTimelineTest, presentFenceSignaled_reportsDisplayMiss) {
@@ -458,186 +451,153 @@
     EXPECT_CALL(*mTimeStats,
                 incrementJankyFrames(TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne,
                                                                 sLayerNameOne, JankType::DisplayHAL,
-                                                                0, 0, 0}));
+                                                                -1, 0, 0}));
 
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
-    int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions(
-            {std::chrono::nanoseconds(10ms).count(), std::chrono::nanoseconds(20ms).count(),
-             std::chrono::nanoseconds(60ms).count()});
-    int64_t sfToken1 = mTokenManager->generateTokenForPredictions(
-            {std::chrono::nanoseconds(52ms).count(), std::chrono::nanoseconds(56ms).count(),
-             std::chrono::nanoseconds(60ms).count()});
+    int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 60});
+    int64_t sfToken1 = mTokenManager->generateTokenForPredictions({52, 60, 60});
+
     auto surfaceFrame1 =
             mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
                                                        sUidOne, sLayerIdOne, sLayerNameOne,
                                                        sLayerNameOne);
-    mFrameTimeline->setSfWakeUp(sfToken1, std::chrono::nanoseconds(52ms).count(), refreshRate);
+    mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate);
     surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
-    surfaceFrame1->setAcquireFenceTime(std::chrono::nanoseconds(20ms).count());
+    surfaceFrame1->setAcquireFenceTime(20);
     mFrameTimeline->addSurfaceFrame(surfaceFrame1);
-    presentFence1->signalForTest(std::chrono::nanoseconds(90ms).count());
-    mFrameTimeline->setSfPresent(std::chrono::nanoseconds(56ms).count(), presentFence1);
+    presentFence1->signalForTest(90);
+    mFrameTimeline->setSfPresent(56, presentFence1);
     EXPECT_EQ(surfaceFrame1->getJankType(), JankType::DisplayHAL);
 }
 
 TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppMiss) {
     Fps refreshRate = Fps(11.0);
     EXPECT_CALL(*mTimeStats,
-                incrementJankyFrames(
-                        TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne,
-                                                   sLayerNameOne, JankType::AppDeadlineMissed, 0, 0,
-                                                   std::chrono::duration_cast<
-                                                           std::chrono::nanoseconds>(25ms)
-                                                           .count()}));
+                incrementJankyFrames(TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne,
+                                                                sLayerNameOne,
+                                                                JankType::AppDeadlineMissed, -1, 0,
+                                                                25}));
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
-    int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions(
-            {std::chrono::nanoseconds(10ms).count(), std::chrono::nanoseconds(20ms).count(),
-             std::chrono::nanoseconds(60ms).count()});
-    int64_t sfToken1 = mTokenManager->generateTokenForPredictions(
-            {std::chrono::nanoseconds(82ms).count(), std::chrono::nanoseconds(86ms).count(),
-             std::chrono::nanoseconds(90ms).count()});
+    int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 60});
+    int64_t sfToken1 = mTokenManager->generateTokenForPredictions({82, 90, 90});
+
     auto surfaceFrame1 =
             mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
                                                        sUidOne, sLayerIdOne, sLayerNameOne,
                                                        sLayerNameOne);
-    surfaceFrame1->setAcquireFenceTime(std::chrono::nanoseconds(45ms).count());
-    mFrameTimeline->setSfWakeUp(sfToken1, std::chrono::nanoseconds(52ms).count(), refreshRate);
+    surfaceFrame1->setAcquireFenceTime(45);
+    mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate);
 
     surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
     mFrameTimeline->addSurfaceFrame(surfaceFrame1);
-    presentFence1->signalForTest(std::chrono::nanoseconds(90ms).count());
-    mFrameTimeline->setSfPresent(std::chrono::nanoseconds(86ms).count(), presentFence1);
+    presentFence1->signalForTest(90);
+    mFrameTimeline->setSfPresent(86, presentFence1);
 
     EXPECT_EQ(surfaceFrame1->getJankType(), JankType::AppDeadlineMissed);
 }
 
 TEST_F(FrameTimelineTest, presentFenceSignaled_reportsSfScheduling) {
-    Fps refreshRate = Fps::fromPeriodNsecs(std::chrono::nanoseconds(32ms).count());
+    Fps refreshRate = Fps::fromPeriodNsecs(32);
     EXPECT_CALL(*mTimeStats,
-                incrementJankyFrames(
-                        TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne,
-                                                   sLayerNameOne,
-                                                   JankType::SurfaceFlingerScheduling, 0, 0,
-                                                   std::chrono::duration_cast<
-                                                           std::chrono::nanoseconds>(-10ms)
-                                                           .count()}));
+                incrementJankyFrames(TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne,
+                                                                sLayerNameOne,
+                                                                JankType::SurfaceFlingerScheduling,
+                                                                -1, 0, -10}));
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
-    int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions(
-            {std::chrono::nanoseconds(40ms).count(), std::chrono::nanoseconds(60ms).count(),
-             std::chrono::nanoseconds(92ms).count()});
-    int64_t sfToken1 = mTokenManager->generateTokenForPredictions(
-            {std::chrono::nanoseconds(52ms).count(), std::chrono::nanoseconds(56ms).count(),
-             std::chrono::nanoseconds(60ms).count()});
+    int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({40, 60, 92});
+    int64_t sfToken1 = mTokenManager->generateTokenForPredictions({52, 60, 60});
+
     auto surfaceFrame1 =
             mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
                                                        sUidOne, sLayerIdOne, sLayerNameOne,
                                                        sLayerNameOne);
-    surfaceFrame1->setAcquireFenceTime(std::chrono::nanoseconds(50ms).count());
-    mFrameTimeline->setSfWakeUp(sfToken1, std::chrono::nanoseconds(52ms).count(), refreshRate);
+    surfaceFrame1->setAcquireFenceTime(50);
+    mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate);
 
     surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
     mFrameTimeline->addSurfaceFrame(surfaceFrame1);
-    presentFence1->signalForTest(std::chrono::nanoseconds(60ms).count());
-    mFrameTimeline->setSfPresent(std::chrono::nanoseconds(56ms).count(), presentFence1);
+    presentFence1->signalForTest(60);
+    mFrameTimeline->setSfPresent(56, presentFence1);
 
     EXPECT_EQ(surfaceFrame1->getJankType(), JankType::SurfaceFlingerScheduling);
 }
 
 TEST_F(FrameTimelineTest, presentFenceSignaled_reportsSfPredictionError) {
-    Fps refreshRate = Fps(16.66f);
+    Fps refreshRate = Fps::fromPeriodNsecs(16);
     EXPECT_CALL(*mTimeStats,
-                incrementJankyFrames(
-                        TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne,
-                                                   sLayerNameOne, JankType::PredictionError, 0,
-                                                   std::chrono::duration_cast<
-                                                           std::chrono::nanoseconds>(5ms)
-                                                           .count(),
-                                                   0}));
+                incrementJankyFrames(TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne,
+                                                                sLayerNameOne,
+                                                                JankType::PredictionError, -1, 5,
+                                                                0}));
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
-    int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions(
-            {std::chrono::nanoseconds(30ms).count(), std::chrono::nanoseconds(40ms).count(),
-             std::chrono::nanoseconds(60ms).count()});
-    int64_t sfToken1 = mTokenManager->generateTokenForPredictions(
-            {std::chrono::nanoseconds(52ms).count(), std::chrono::nanoseconds(56ms).count(),
-             std::chrono::nanoseconds(60ms).count()});
+    int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({30, 40, 60});
+    int64_t sfToken1 = mTokenManager->generateTokenForPredictions({52, 60, 60});
+
     auto surfaceFrame1 =
             mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
                                                        sUidOne, sLayerIdOne, sLayerNameOne,
                                                        sLayerNameOne);
-    surfaceFrame1->setAcquireFenceTime(std::chrono::nanoseconds(40ms).count());
-    mFrameTimeline->setSfWakeUp(sfToken1, std::chrono::nanoseconds(52ms).count(), refreshRate);
+    surfaceFrame1->setAcquireFenceTime(40);
+    mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate);
 
     surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
     mFrameTimeline->addSurfaceFrame(surfaceFrame1);
-    presentFence1->signalForTest(std::chrono::nanoseconds(65ms).count());
-    mFrameTimeline->setSfPresent(std::chrono::nanoseconds(56ms).count(), presentFence1);
+    presentFence1->signalForTest(65);
+    mFrameTimeline->setSfPresent(56, presentFence1);
 
     EXPECT_EQ(surfaceFrame1->getJankType(), JankType::PredictionError);
 }
 
 TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppBufferStuffing) {
-    Fps refreshRate = Fps::fromPeriodNsecs(std::chrono::nanoseconds(32ms).count());
+    Fps refreshRate = Fps::fromPeriodNsecs(32);
     EXPECT_CALL(*mTimeStats,
-                incrementJankyFrames(
-                        TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne,
-                                                   sLayerNameOne,
-                                                   JankType::BufferStuffing |
-                                                           JankType::SurfaceFlingerScheduling,
-                                                   0, 0, 0}));
+                incrementJankyFrames(TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne,
+                                                                sLayerNameOne,
+                                                                JankType::BufferStuffing, -1, 0,
+                                                                0}));
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
-    int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions(
-            {std::chrono::nanoseconds(30ms).count(), std::chrono::nanoseconds(40ms).count(),
-             std::chrono::nanoseconds(58ms).count()});
-    int64_t sfToken1 = mTokenManager->generateTokenForPredictions(
-            {std::chrono::nanoseconds(82ms).count(), std::chrono::nanoseconds(86ms).count(),
-             std::chrono::nanoseconds(90ms).count()});
+    int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({30, 40, 58});
+    int64_t sfToken1 = mTokenManager->generateTokenForPredictions({82, 90, 90});
+
     auto surfaceFrame1 =
             mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
                                                        sUidOne, sLayerIdOne, sLayerNameOne,
                                                        sLayerNameOne);
-    surfaceFrame1->setAcquireFenceTime(std::chrono::nanoseconds(40ms).count());
-    mFrameTimeline->setSfWakeUp(sfToken1, std::chrono::nanoseconds(82ms).count(), refreshRate);
+    surfaceFrame1->setAcquireFenceTime(40);
+    mFrameTimeline->setSfWakeUp(sfToken1, 82, refreshRate);
 
     surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented,
-                                   /*previousLatchTime*/
-                                   std::chrono::nanoseconds(56ms).count());
+                                   /*previousLatchTime*/ 56);
     mFrameTimeline->addSurfaceFrame(surfaceFrame1);
-    presentFence1->signalForTest(std::chrono::nanoseconds(90ms).count());
-    mFrameTimeline->setSfPresent(std::chrono::nanoseconds(86ms).count(), presentFence1);
+    presentFence1->signalForTest(90);
+    mFrameTimeline->setSfPresent(86, presentFence1);
 
-    EXPECT_EQ(surfaceFrame1->getJankType(),
-              JankType::BufferStuffing | JankType::SurfaceFlingerScheduling);
+    EXPECT_EQ(surfaceFrame1->getJankType(), JankType::BufferStuffing);
 }
 
 TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppMissWithRenderRate) {
-    Fps refreshRate = Fps(11.0);
-    Fps renderRate = Fps(30.0);
+    Fps refreshRate = Fps::fromPeriodNsecs(11);
+    Fps renderRate = Fps::fromPeriodNsecs(30);
     EXPECT_CALL(*mTimeStats,
                 incrementJankyFrames(
                         TimeStats::JankyFramesInfo{refreshRate, renderRate, sUidOne, sLayerNameOne,
-                                                   JankType::AppDeadlineMissed, 0, 0,
-                                                   std::chrono::duration_cast<
-                                                           std::chrono::nanoseconds>(25ms)
-                                                           .count()}));
+                                                   JankType::AppDeadlineMissed, -1, 0, 25}));
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
-    int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions(
-            {std::chrono::nanoseconds(10ms).count(), std::chrono::nanoseconds(20ms).count(),
-             std::chrono::nanoseconds(60ms).count()});
-    int64_t sfToken1 = mTokenManager->generateTokenForPredictions(
-            {std::chrono::nanoseconds(82ms).count(), std::chrono::nanoseconds(86ms).count(),
-             std::chrono::nanoseconds(90ms).count()});
+    int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 60});
+    int64_t sfToken1 = mTokenManager->generateTokenForPredictions({82, 90, 90});
+
     auto surfaceFrame1 =
             mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
                                                        sUidOne, sLayerIdOne, sLayerNameOne,
                                                        sLayerNameOne);
-    surfaceFrame1->setAcquireFenceTime(std::chrono::nanoseconds(45ms).count());
-    mFrameTimeline->setSfWakeUp(sfToken1, std::chrono::nanoseconds(52ms).count(), refreshRate);
+    surfaceFrame1->setAcquireFenceTime(45);
+    mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate);
 
     surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
     surfaceFrame1->setRenderRate(renderRate);
     mFrameTimeline->addSurfaceFrame(surfaceFrame1);
-    presentFence1->signalForTest(std::chrono::nanoseconds(90ms).count());
-    mFrameTimeline->setSfPresent(std::chrono::nanoseconds(86ms).count(), presentFence1);
+    presentFence1->signalForTest(90);
+    mFrameTimeline->setSfPresent(86, presentFence1);
 
     EXPECT_EQ(surfaceFrame1->getJankType(), JankType::AppDeadlineMissed);
 }
@@ -893,7 +853,7 @@
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
 
     tracingSession->StartBlocking();
-    int64_t displayFrameToken1 = mTokenManager->generateTokenForPredictions({10, 25, 30});
+    int64_t displayFrameToken1 = mTokenManager->generateTokenForPredictions({10, 30, 30});
 
     // Set up the display frame
     mFrameTimeline->setSfWakeUp(displayFrameToken1, 20, Fps::fromPeriodNsecs(11));
@@ -933,7 +893,7 @@
     // Packet - 1 : FrameEnd (ExpectedDisplayFrame)
     const auto& packet1 = packets[1];
     ASSERT_TRUE(packet1.has_timestamp());
-    EXPECT_EQ(packet1.timestamp(), 25u);
+    EXPECT_EQ(packet1.timestamp(), 30u);
     ASSERT_TRUE(packet1.has_frame_timeline_event());
 
     const auto& event1 = packet1.frame_timeline_event();
@@ -1179,12 +1139,9 @@
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
 
     tracingSession->StartBlocking();
-    constexpr nsecs_t appStartTime =
-            std::chrono::duration_cast<std::chrono::nanoseconds>(10ms).count();
-    constexpr nsecs_t appEndTime =
-            std::chrono::duration_cast<std::chrono::nanoseconds>(20ms).count();
-    constexpr nsecs_t appPresentTime =
-            std::chrono::duration_cast<std::chrono::nanoseconds>(30ms).count();
+    constexpr nsecs_t appStartTime = std::chrono::nanoseconds(10ms).count();
+    constexpr nsecs_t appEndTime = std::chrono::nanoseconds(20ms).count();
+    constexpr nsecs_t appPresentTime = std::chrono::nanoseconds(30ms).count();
     int64_t surfaceFrameToken =
             mTokenManager->generateTokenForPredictions({appStartTime, appEndTime, appPresentTime});
 
@@ -1197,12 +1154,9 @@
     surfaceFrame1->setActualQueueTime(appEndTime);
     surfaceFrame1->setAcquireFenceTime(appEndTime);
 
-    constexpr nsecs_t sfStartTime =
-            std::chrono::duration_cast<std::chrono::nanoseconds>(20ms).count();
-    constexpr nsecs_t sfEndTime =
-            std::chrono::duration_cast<std::chrono::nanoseconds>(30ms).count();
-    constexpr nsecs_t sfPresentTime =
-            std::chrono::duration_cast<std::chrono::nanoseconds>(30ms).count();
+    constexpr nsecs_t sfStartTime = std::chrono::nanoseconds(20ms).count();
+    constexpr nsecs_t sfEndTime = std::chrono::nanoseconds(30ms).count();
+    constexpr nsecs_t sfPresentTime = std::chrono::nanoseconds(30ms).count();
     int64_t displayFrameToken =
             mTokenManager->generateTokenForPredictions({sfStartTime, sfEndTime, sfPresentTime});
 
@@ -1261,7 +1215,7 @@
     EXPECT_CALL(*mTimeStats, incrementJankyFrames(_));
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     int64_t surfaceFrameToken = mTokenManager->generateTokenForPredictions({10, 20, 30});
-    int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 30});
+    int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 30, 30});
     auto surfaceFrame =
             mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId}, sPidOne,
                                                        sUidOne, sLayerIdOne, sLayerNameOne,
@@ -1292,8 +1246,8 @@
 TEST_F(FrameTimelineTest, jankClassification_displayFrameOnTimeFinishEarlyPresent) {
     Fps vsyncRate = Fps::fromPeriodNsecs(11);
     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 sfToken1 = mTokenManager->generateTokenForPredictions({22, 30, 40});
+    int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 60, 70});
     mFrameTimeline->setSfWakeUp(sfToken1, 22, vsyncRate);
     mFrameTimeline->setSfPresent(26, presentFence1);
     auto displayFrame = getDisplayFrame(0);
@@ -1331,8 +1285,8 @@
 TEST_F(FrameTimelineTest, jankClassification_displayFrameOnTimeFinishLatePresent) {
     Fps vsyncRate = Fps::fromPeriodNsecs(11);
     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 sfToken1 = mTokenManager->generateTokenForPredictions({22, 30, 40});
+    int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 60, 70});
     mFrameTimeline->setSfWakeUp(sfToken1, 22, vsyncRate);
     mFrameTimeline->setSfPresent(26, presentFence1);
     auto displayFrame = getDisplayFrame(0);
@@ -1411,11 +1365,33 @@
     EXPECT_EQ(displayFrame->getJankType(), JankType::SurfaceFlingerCpuDeadlineMissed);
 }
 
+TEST_F(FrameTimelineTest, jankClassification_displayFrameLateStartLateFinishLatePresent) {
+    auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+    int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 40});
+    mFrameTimeline->setSfWakeUp(sfToken1, 26, Fps::fromPeriodNsecs(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->getFrameStartMetadata(), FrameStartMetadata::LateStart);
+    EXPECT_EQ(displayFrame->getFramePresentMetadata(), FramePresentMetadata::LatePresent);
+    EXPECT_EQ(displayFrame->getFrameReadyMetadata(), FrameReadyMetadata::LateFinish);
+    EXPECT_EQ(displayFrame->getJankType(), JankType::SurfaceFlingerScheduling);
+}
+
 TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishEarlyPresent) {
     EXPECT_CALL(*mTimeStats, incrementJankyFrames(_));
     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 sfToken1 = mTokenManager->generateTokenForPredictions({22, 30, 40});
+    int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 60, 70});
     int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({5, 16, 40});
     int64_t surfaceFrameToken2 = mTokenManager->generateTokenForPredictions({25, 36, 70});
     auto surfaceFrame1 =
@@ -1426,7 +1402,7 @@
     mFrameTimeline->setSfWakeUp(sfToken1, 22, Fps::fromPeriodNsecs(11));
     surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
     mFrameTimeline->addSurfaceFrame(surfaceFrame1);
-    mFrameTimeline->setSfPresent(26, presentFence1);
+    mFrameTimeline->setSfPresent(27, presentFence1);
     auto displayFrame1 = getDisplayFrame(0);
     auto& presentedSurfaceFrame1 = getSurfaceFrame(0, 0);
     presentFence1->signalForTest(30);
@@ -1446,7 +1422,7 @@
     mFrameTimeline->setSfWakeUp(sfToken2, 52, Fps::fromPeriodNsecs(11));
     surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented);
     mFrameTimeline->addSurfaceFrame(surfaceFrame2);
-    mFrameTimeline->setSfPresent(56, presentFence2);
+    mFrameTimeline->setSfPresent(57, presentFence2);
     auto displayFrame2 = getDisplayFrame(1);
     auto& presentedSurfaceFrame2 = getSurfaceFrame(1, 0);
 
@@ -1494,8 +1470,8 @@
 TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishLatePresent) {
     EXPECT_CALL(*mTimeStats, incrementJankyFrames(_));
     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 sfToken1 = mTokenManager->generateTokenForPredictions({22, 30, 40});
+    int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 60, 70});
     int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({5, 16, 40});
     int64_t surfaceFrameToken2 = mTokenManager->generateTokenForPredictions({25, 36, 70});
     auto surfaceFrame1 =
@@ -1526,7 +1502,7 @@
     mFrameTimeline->setSfWakeUp(sfToken2, 52, Fps::fromPeriodNsecs(11));
     surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented);
     mFrameTimeline->addSurfaceFrame(surfaceFrame2);
-    mFrameTimeline->setSfPresent(56, presentFence2);
+    mFrameTimeline->setSfPresent(57, presentFence2);
     auto displayFrame2 = getDisplayFrame(1);
     auto& presentedSurfaceFrame2 = getSurfaceFrame(1, 0);
 
@@ -1575,7 +1551,7 @@
     EXPECT_CALL(*mTimeStats, incrementJankyFrames(_));
 
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
-    int64_t sfToken1 = mTokenManager->generateTokenForPredictions({42, 46, 50});
+    int64_t sfToken1 = mTokenManager->generateTokenForPredictions({42, 50, 50});
     int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({5, 26, 60});
     auto surfaceFrame1 =
             mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
@@ -1617,8 +1593,8 @@
 
     EXPECT_CALL(*mTimeStats, incrementJankyFrames(_)).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 sfToken1 = mTokenManager->generateTokenForPredictions({32, 40, 40});
+    int64_t sfToken2 = mTokenManager->generateTokenForPredictions({42, 50, 50});
     int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({5, 16, 30});
     int64_t surfaceFrameToken2 = mTokenManager->generateTokenForPredictions({25, 36, 50});
     auto surfaceFrame1 =
@@ -1693,8 +1669,8 @@
     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});
+    int64_t sfToken1 = mTokenManager->generateTokenForPredictions({52, 60, 60});
+    int64_t sfToken2 = mTokenManager->generateTokenForPredictions({112, 120, 120});
     auto surfaceFrame1 =
             mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
                                                        sUidOne, sLayerIdOne, sLayerNameOne,
@@ -1764,12 +1740,90 @@
               JankType::AppDeadlineMissed | JankType::BufferStuffing);
 }
 
+TEST_F(FrameTimelineTest, jankClassification_appDeadlineAdjustedForBufferStuffing) {
+    // Layer specific increment
+    EXPECT_CALL(*mTimeStats, incrementJankyFrames(_)).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, 60, 60});
+    int64_t sfToken2 = mTokenManager->generateTokenForPredictions({82, 90, 90});
+    auto surfaceFrame1 =
+            mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
+                                                       sUidOne, sLayerIdOne, sLayerNameOne,
+                                                       sLayerNameOne);
+    surfaceFrame1->setAcquireFenceTime(50);
+    mFrameTimeline->setSfWakeUp(sfToken1, 52, Fps::fromPeriodNsecs(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, sInputEventId}, sPidOne,
+                                                       sUidOne, sLayerIdOne, sLayerNameOne,
+                                                       sLayerNameOne);
+    surfaceFrame2->setAcquireFenceTime(80);
+    mFrameTimeline->setSfWakeUp(sfToken2, 82, Fps::fromPeriodNsecs(30));
+    // Setting previous latch time to 54, adjusted deadline will be 54 + vsyncTime(30) = 84
+    surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented, 54);
+    mFrameTimeline->addSurfaceFrame(surfaceFrame2);
+    mFrameTimeline->setSfPresent(86, presentFence2);
+    auto displayFrame2 = getDisplayFrame(1);
+    auto& presentedSurfaceFrame2 = getSurfaceFrame(1, 0);
+    presentFence2->signalForTest(90);
+
+    // 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, 90);
+    actuals2 = presentedSurfaceFrame2.getActuals();
+    EXPECT_EQ(actuals2.presentTime, 90);
+
+    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::OnTimeFinish);
+    EXPECT_EQ(presentedSurfaceFrame2.getJankType(), JankType::BufferStuffing);
+}
+
 TEST_F(FrameTimelineTest, computeFps_noLayerIds_returnsZero) {
     EXPECT_EQ(mFrameTimeline->computeFps({}), 0.0f);
 }
 
 TEST_F(FrameTimelineTest, computeFps_singleDisplayFrame_returnsZero) {
-    const auto oneHundredMs = std::chrono::duration_cast<std::chrono::nanoseconds>(100ms).count();
+    const auto oneHundredMs = std::chrono::nanoseconds(100ms).count();
 
     auto surfaceFrame1 =
             mFrameTimeline->createSurfaceFrameForToken(FrameTimelineInfo(), sPidOne, sUidOne,
@@ -1784,8 +1838,8 @@
 }
 
 TEST_F(FrameTimelineTest, computeFps_twoDisplayFrames_oneLayer) {
-    const auto oneHundredMs = std::chrono::duration_cast<std::chrono::nanoseconds>(100ms).count();
-    const auto twoHundredMs = std::chrono::duration_cast<std::chrono::nanoseconds>(200ms).count();
+    const auto oneHundredMs = std::chrono::nanoseconds(100ms).count();
+    const auto twoHundredMs = std::chrono::nanoseconds(200ms).count();
     auto surfaceFrame1 =
             mFrameTimeline->createSurfaceFrameForToken(FrameTimelineInfo(), sPidOne, sUidOne,
                                                        sLayerIdOne, sLayerNameOne, sLayerNameOne);
@@ -1808,8 +1862,8 @@
 }
 
 TEST_F(FrameTimelineTest, computeFps_twoDisplayFrames_twoLayers) {
-    const auto oneHundredMs = std::chrono::duration_cast<std::chrono::nanoseconds>(100ms).count();
-    const auto twoHundredMs = std::chrono::duration_cast<std::chrono::nanoseconds>(200ms).count();
+    const auto oneHundredMs = std::chrono::nanoseconds(100ms).count();
+    const auto twoHundredMs = std::chrono::nanoseconds(200ms).count();
     auto surfaceFrame1 =
             mFrameTimeline->createSurfaceFrameForToken(FrameTimelineInfo(), sPidOne, sUidOne,
                                                        sLayerIdOne, sLayerNameOne, sLayerNameOne);
@@ -1832,8 +1886,8 @@
 }
 
 TEST_F(FrameTimelineTest, computeFps_filtersOutLayers) {
-    const auto oneHundredMs = std::chrono::duration_cast<std::chrono::nanoseconds>(100ms).count();
-    const auto twoHundredMs = std::chrono::duration_cast<std::chrono::nanoseconds>(200ms).count();
+    const auto oneHundredMs = std::chrono::nanoseconds(100ms).count();
+    const auto twoHundredMs = std::chrono::nanoseconds(200ms).count();
     auto surfaceFrame1 =
             mFrameTimeline->createSurfaceFrameForToken(FrameTimelineInfo(), sPidOne, sUidOne,
                                                        sLayerIdOne, sLayerNameOne, sLayerNameOne);
@@ -1856,11 +1910,11 @@
 }
 
 TEST_F(FrameTimelineTest, computeFps_averagesOverMultipleFrames) {
-    const auto oneHundredMs = std::chrono::duration_cast<std::chrono::nanoseconds>(100ms).count();
-    const auto twoHundredMs = std::chrono::duration_cast<std::chrono::nanoseconds>(200ms).count();
-    const auto threeHundredMs = std::chrono::duration_cast<std::chrono::nanoseconds>(300ms).count();
-    const auto fiveHundredMs = std::chrono::duration_cast<std::chrono::nanoseconds>(500ms).count();
-    const auto sixHundredMs = std::chrono::duration_cast<std::chrono::nanoseconds>(600ms).count();
+    const auto oneHundredMs = std::chrono::nanoseconds(100ms).count();
+    const auto twoHundredMs = std::chrono::nanoseconds(200ms).count();
+    const auto threeHundredMs = std::chrono::nanoseconds(300ms).count();
+    const auto fiveHundredMs = std::chrono::nanoseconds(500ms).count();
+    const auto sixHundredMs = std::chrono::nanoseconds(600ms).count();
     auto surfaceFrame1 =
             mFrameTimeline->createSurfaceFrameForToken(FrameTimelineInfo(), sPidOne, sUidOne,
                                                        sLayerIdOne, sLayerNameOne, sLayerNameOne);