Add method to get current vsync from sf directly.

Bug: 205721584
Test: atest libsurfaceflinger_unittest
Test: atest DisplayEventReceiverTest
Change-Id: I38d4bd20bc2f2ad7ff964c3d613c28919478c0fc
diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.cpp b/services/surfaceflinger/Scheduler/DispSyncSource.cpp
index c593340..747032b 100644
--- a/services/surfaceflinger/Scheduler/DispSyncSource.cpp
+++ b/services/surfaceflinger/Scheduler/DispSyncSource.cpp
@@ -23,6 +23,7 @@
 #include <mutex>
 
 #include "EventThread.h"
+#include "VSyncTracker.h"
 #include "VsyncController.h"
 
 namespace android::scheduler {
@@ -114,7 +115,7 @@
     std::chrono::nanoseconds mLastCallTime GUARDED_BY(mMutex) = 0ns;
 };
 
-DispSyncSource::DispSyncSource(scheduler::VSyncDispatch& vSyncDispatch,
+DispSyncSource::DispSyncSource(VSyncDispatch& vSyncDispatch, VSyncTracker& vSyncTracker,
                                std::chrono::nanoseconds workDuration,
                                std::chrono::nanoseconds readyDuration, bool traceVsync,
                                const char* name)
@@ -122,6 +123,7 @@
         mValue(base::StringPrintf("VSYNC-%s", name), 0),
         mTraceVsync(traceVsync),
         mVsyncOnLabel(base::StringPrintf("VsyncOn-%s", name)),
+        mVSyncTracker(vSyncTracker),
         mWorkDuration(base::StringPrintf("VsyncWorkDuration-%s", name), workDuration),
         mReadyDuration(readyDuration) {
     mCallbackRepeater =
@@ -184,6 +186,14 @@
     }
 }
 
+VSyncSource::VSyncData DispSyncSource::getLatestVSyncData() const {
+    std::lock_guard lock(mVsyncMutex);
+    nsecs_t expectedPresentTime = mVSyncTracker.nextAnticipatedVSyncTimeFrom(
+            systemTime() + mWorkDuration.get().count() + mReadyDuration.count());
+    nsecs_t deadline = expectedPresentTime - mWorkDuration.get().count() - mReadyDuration.count();
+    return {expectedPresentTime, deadline};
+}
+
 void DispSyncSource::dump(std::string& result) const {
     std::lock_guard lock(mVsyncMutex);
     StringAppendF(&result, "DispSyncSource: %s(%s)\n", mName, mEnabled ? "enabled" : "disabled");
diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.h b/services/surfaceflinger/Scheduler/DispSyncSource.h
index 2fce235..edcd3ac 100644
--- a/services/surfaceflinger/Scheduler/DispSyncSource.h
+++ b/services/surfaceflinger/Scheduler/DispSyncSource.h
@@ -24,11 +24,13 @@
 
 namespace android::scheduler {
 class CallbackRepeater;
+class VSyncTracker;
 
 class DispSyncSource final : public VSyncSource {
 public:
-    DispSyncSource(VSyncDispatch& vSyncDispatch, std::chrono::nanoseconds workDuration,
-                   std::chrono::nanoseconds readyDuration, bool traceVsync, const char* name);
+    DispSyncSource(VSyncDispatch& vSyncDispatch, VSyncTracker& vSyncTracker,
+                   std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration,
+                   bool traceVsync, const char* name);
 
     ~DispSyncSource() override;
 
@@ -38,6 +40,7 @@
     void setCallback(VSyncSource::Callback* callback) override;
     void setDuration(std::chrono::nanoseconds workDuration,
                      std::chrono::nanoseconds readyDuration) override;
+    VSyncData getLatestVSyncData() const override;
 
     void dump(std::string&) const override;
 
@@ -50,6 +53,8 @@
     const bool mTraceVsync;
     const std::string mVsyncOnLabel;
 
+    const VSyncTracker& mVSyncTracker;
+
     std::unique_ptr<CallbackRepeater> mCallbackRepeater;
 
     std::mutex mCallbackMutex;
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index adc1009..2d0da46 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -181,11 +181,17 @@
 }
 
 binder::Status EventThreadConnection::requestNextVsync() {
-    ATRACE_NAME("requestNextVsync");
+    ATRACE_CALL();
     mEventThread->requestNextVsync(this);
     return binder::Status::ok();
 }
 
+binder::Status EventThreadConnection::getLatestVsyncEventData(VsyncEventData* outVsyncEventData) {
+    ATRACE_CALL();
+    *outVsyncEventData = mEventThread->getLatestVsyncEventData(this);
+    return binder::Status::ok();
+}
+
 status_t EventThreadConnection::postEvent(const DisplayEventReceiver::Event& event) {
     constexpr auto toStatus = [](ssize_t size) {
         return size < 0 ? status_t(size) : status_t(NO_ERROR);
@@ -330,6 +336,15 @@
     }
 }
 
+VsyncEventData EventThread::getLatestVsyncEventData(
+        const sp<EventThreadConnection>& connection) const {
+    nsecs_t frameInterval = mGetVsyncPeriodFunction(connection->mOwnerUid);
+    VsyncEventData vsyncEventData;
+    vsyncEventData.frameInterval = frameInterval;
+    generateFrameTimeline(vsyncEventData, frameInterval, systemTime(SYSTEM_TIME_MONOTONIC));
+    return vsyncEventData;
+}
+
 void EventThread::onScreenReleased() {
     std::lock_guard<std::mutex> lock(mMutex);
     if (!mVSyncState || mVSyncState->synthetic) {
@@ -561,27 +576,64 @@
     return FrameTimelineInfo::INVALID_VSYNC_ID;
 }
 
-void EventThread::generateFrameTimeline(DisplayEventReceiver::Event& event) const {
+void EventThread::generateFrameTimeline(
+        nsecs_t frameInterval, nsecs_t timestamp, nsecs_t preferredExpectedVSyncTimestamp,
+        nsecs_t preferredDeadlineTimestamp,
+        std::function<void(int64_t index)> setPreferredFrameTimelineIndex,
+        std::function<void(int64_t index, int64_t vsyncId, nsecs_t expectedVSyncTimestamp,
+                           nsecs_t deadlineTimestamp)>
+                setFrameTimeline) const {
     // Add 1 to ensure the preferredFrameTimelineIndex entry (when multiplier == 0) is included.
-    for (int multiplier = -VsyncEventData::kFrameTimelinesLength + 1, currentIndex = 0;
+    for (int64_t multiplier = -VsyncEventData::kFrameTimelinesLength + 1, currentIndex = 0;
          currentIndex < VsyncEventData::kFrameTimelinesLength; multiplier++) {
-        nsecs_t deadline = event.vsync.deadlineTimestamp + multiplier * event.vsync.frameInterval;
+        nsecs_t deadline = preferredDeadlineTimestamp + multiplier * frameInterval;
         // Valid possible frame timelines must have future values.
-        if (deadline > event.header.timestamp) {
+        if (deadline > timestamp) {
             if (multiplier == 0) {
-                event.vsync.preferredFrameTimelineIndex = currentIndex;
+                setPreferredFrameTimelineIndex(currentIndex);
             }
-            nsecs_t expectedVSync =
-                    event.vsync.expectedVSyncTimestamp + multiplier * event.vsync.frameInterval;
-            event.vsync.frameTimelines[currentIndex] =
-                    {.vsyncId = generateToken(event.header.timestamp, deadline, expectedVSync),
-                     .deadlineTimestamp = deadline,
-                     .expectedVSyncTimestamp = expectedVSync};
+            nsecs_t expectedVSyncTimestamp =
+                    preferredExpectedVSyncTimestamp + multiplier * frameInterval;
+            setFrameTimeline(currentIndex,
+                             generateToken(timestamp, deadline, expectedVSyncTimestamp),
+                             expectedVSyncTimestamp, deadline);
             currentIndex++;
         }
     }
 }
 
+void EventThread::generateFrameTimeline(DisplayEventReceiver::Event& event) const {
+    generateFrameTimeline(
+            event.vsync.frameInterval, event.header.timestamp, event.vsync.expectedVSyncTimestamp,
+            event.vsync.deadlineTimestamp,
+            [&](int index) { event.vsync.preferredFrameTimelineIndex = index; },
+            [&](int64_t index, int64_t vsyncId, nsecs_t expectedVSyncTimestamp,
+                nsecs_t deadlineTimestamp) {
+                event.vsync.frameTimelines[index] = {.vsyncId = vsyncId,
+                                                     .deadlineTimestamp = deadlineTimestamp,
+                                                     .expectedVSyncTimestamp =
+                                                             expectedVSyncTimestamp};
+            });
+}
+
+void EventThread::generateFrameTimeline(VsyncEventData& out, const nsecs_t frameInterval,
+                                        const nsecs_t timestamp) const {
+    VSyncSource::VSyncData vsyncData;
+    {
+        std::lock_guard<std::mutex> lock(mMutex);
+        vsyncData = mVSyncSource->getLatestVSyncData();
+    }
+    generateFrameTimeline(
+            frameInterval, timestamp, vsyncData.expectedVSyncTimestamp, vsyncData.deadlineTimestamp,
+            [&](int index) { out.preferredFrameTimelineIndex = index; },
+            [&](int64_t index, int64_t vsyncId, nsecs_t expectedVSyncTimestamp,
+                nsecs_t deadlineTimestamp) {
+                out.frameTimelines[index] =
+                        VsyncEventData::FrameTimeline(vsyncId, deadlineTimestamp,
+                                                      expectedVSyncTimestamp);
+            });
+}
+
 void EventThread::dispatchEvent(const DisplayEventReceiver::Event& event,
                                 const DisplayEventConsumers& consumers) {
     for (const auto& consumer : consumers) {
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index c3b9129..a858169 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -45,6 +45,8 @@
 class TokenManager;
 } // namespace frametimeline
 
+using gui::VsyncEventData;
+
 // ---------------------------------------------------------------------------
 
 using ResyncCallback = std::function<void()>;
@@ -81,6 +83,7 @@
     virtual void setCallback(Callback* callback) = 0;
     virtual void setDuration(std::chrono::nanoseconds workDuration,
                              std::chrono::nanoseconds readyDuration) = 0;
+    virtual VSyncData getLatestVSyncData() const = 0;
 
     virtual void dump(std::string& result) const = 0;
 };
@@ -96,6 +99,7 @@
     binder::Status stealReceiveChannel(gui::BitTube* outChannel) override;
     binder::Status setVsyncRate(int rate) override;
     binder::Status requestNextVsync() override; // asynchronous
+    binder::Status getLatestVsyncEventData(VsyncEventData* outVsyncEventData) override;
 
     // Called in response to requestNextVsync.
     const ResyncCallback resyncCallback;
@@ -145,6 +149,8 @@
     virtual void setVsyncRate(uint32_t rate, const sp<EventThreadConnection>& connection) = 0;
     // Requests the next vsync. If resetIdleTimer is set to true, it resets the idle timer.
     virtual void requestNextVsync(const sp<EventThreadConnection>& connection) = 0;
+    virtual VsyncEventData getLatestVsyncEventData(
+            const sp<EventThreadConnection>& connection) const = 0;
 
     // Retrieves the number of event connections tracked by this EventThread.
     virtual size_t getEventThreadConnectionCount() = 0;
@@ -169,6 +175,8 @@
     status_t registerDisplayEventConnection(const sp<EventThreadConnection>& connection) override;
     void setVsyncRate(uint32_t rate, const sp<EventThreadConnection>& connection) override;
     void requestNextVsync(const sp<EventThreadConnection>& connection) override;
+    VsyncEventData getLatestVsyncEventData(
+            const sp<EventThreadConnection>& connection) const override;
 
     // called before the screen is turned off from main thread
     void onScreenReleased() override;
@@ -211,6 +219,15 @@
     int64_t generateToken(nsecs_t timestamp, nsecs_t deadlineTimestamp,
                           nsecs_t expectedVSyncTimestamp) const;
     void generateFrameTimeline(DisplayEventReceiver::Event& event) const;
+    void generateFrameTimeline(VsyncEventData& out, const nsecs_t frameInterval,
+                               const nsecs_t timestamp) const;
+    void generateFrameTimeline(
+            nsecs_t frameInterval, nsecs_t timestamp, nsecs_t preferredExpectedVSyncTimestamp,
+            nsecs_t preferredDeadlineTimestamp,
+            std::function<void(int64_t index)> setPreferredFrameTimelineIndex,
+            std::function<void(int64_t index, int64_t vsyncId, nsecs_t expectedVSyncTimestamp,
+                               nsecs_t deadlineTimestamp)>
+                    setFrameTimeline) const;
 
     const std::unique_ptr<VSyncSource> mVSyncSource GUARDED_BY(mMutex);
     frametimeline::TokenManager* const mTokenManager;
diff --git a/services/surfaceflinger/Scheduler/InjectVSyncSource.h b/services/surfaceflinger/Scheduler/InjectVSyncSource.h
index 7b93f1e..760a4ee 100644
--- a/services/surfaceflinger/Scheduler/InjectVSyncSource.h
+++ b/services/surfaceflinger/Scheduler/InjectVSyncSource.h
@@ -46,6 +46,7 @@
     const char* getName() const override { return "inject"; }
     void setVSyncEnabled(bool) override {}
     void setDuration(std::chrono::nanoseconds, std::chrono::nanoseconds) override {}
+    VSyncData getLatestVSyncData() const override { return {}; }
     void dump(std::string&) const override {}
 
 private:
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 665d36982..de27bd1 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -134,7 +134,8 @@
 std::unique_ptr<VSyncSource> Scheduler::makePrimaryDispSyncSource(
         const char* name, std::chrono::nanoseconds workDuration,
         std::chrono::nanoseconds readyDuration, bool traceVsync) {
-    return std::make_unique<scheduler::DispSyncSource>(getVsyncDispatch(), workDuration,
+    return std::make_unique<scheduler::DispSyncSource>(mVsyncSchedule->getDispatch(),
+                                                       mVsyncSchedule->getTracker(), workDuration,
                                                        readyDuration, traceVsync, name);
 }
 
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
index 06bbfd2..09ffb02 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
@@ -100,8 +100,9 @@
 void SchedulerFuzzer::fuzzDispSyncSource() {
     std::unique_ptr<FuzzImplVSyncDispatch> vSyncDispatch =
             std::make_unique<FuzzImplVSyncDispatch>();
+    std::unique_ptr<FuzzImplVSyncTracker> vSyncTracker = std::make_unique<FuzzImplVSyncTracker>();
     std::unique_ptr<scheduler::DispSyncSource> dispSyncSource = std::make_unique<
-            scheduler::DispSyncSource>(*vSyncDispatch,
+            scheduler::DispSyncSource>(*vSyncDispatch, *vSyncTracker,
                                        (std::chrono::nanoseconds)
                                                mFdp.ConsumeIntegral<uint64_t>() /*workDuration*/,
                                        (std::chrono::nanoseconds)mFdp.ConsumeIntegral<uint64_t>()
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.h b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.h
index 89cf819..84b3912 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.h
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.h
@@ -103,6 +103,8 @@
     void setDuration(std::chrono::nanoseconds /* workDuration */,
                      std::chrono::nanoseconds /* readyDuration */) override {}
 
+    VSyncData getLatestVSyncData() const override { return {}; }
+
     void dump(std::string& /* result */) const override {}
 };
 
diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp
index 7b86229..2ede830 100644
--- a/services/surfaceflinger/tests/Android.bp
+++ b/services/surfaceflinger/tests/Android.bp
@@ -31,6 +31,7 @@
         "Credentials_test.cpp",
         "DereferenceSurfaceControl_test.cpp",
         "DisplayConfigs_test.cpp",
+        "DisplayEventReceiver_test.cpp",
         "EffectLayer_test.cpp",
         "InvalidHandles_test.cpp",
         "LayerCallback_test.cpp",
diff --git a/services/surfaceflinger/tests/DisplayEventReceiver_test.cpp b/services/surfaceflinger/tests/DisplayEventReceiver_test.cpp
new file mode 100644
index 0000000..01adbc8
--- /dev/null
+++ b/services/surfaceflinger/tests/DisplayEventReceiver_test.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+#include <gui/DisplayEventReceiver.h>
+
+namespace android {
+
+class DisplayEventReceiverTest : public ::testing::Test {
+public:
+    void SetUp() override { EXPECT_EQ(NO_ERROR, mDisplayEventReceiver.initCheck()); }
+
+    DisplayEventReceiver mDisplayEventReceiver;
+};
+
+TEST_F(DisplayEventReceiverTest, getLatestVsyncEventData) {
+    const nsecs_t now = systemTime();
+    VsyncEventData vsyncEventData;
+    EXPECT_EQ(NO_ERROR, mDisplayEventReceiver.getLatestVsyncEventData(&vsyncEventData));
+
+    EXPECT_NE(std::numeric_limits<size_t>::max(), vsyncEventData.preferredFrameTimelineIndex);
+    EXPECT_GT(vsyncEventData.frameTimelines[0].deadlineTimestamp, now)
+            << "Deadline timestamp should be greater than frame time";
+    for (size_t i = 0; i < vsyncEventData.frameTimelines.size(); i++) {
+        EXPECT_NE(FrameTimelineInfo::INVALID_VSYNC_ID, vsyncEventData.frameTimelines[i].id);
+        EXPECT_GT(vsyncEventData.frameTimelines[i].expectedPresentTime,
+                  vsyncEventData.frameTimelines[i].deadlineTimestamp)
+                << "Expected vsync timestamp should be greater than deadline";
+        if (i > 0) {
+            EXPECT_GT(vsyncEventData.frameTimelines[i].deadlineTimestamp,
+                      vsyncEventData.frameTimelines[i - 1].deadlineTimestamp)
+                    << "Deadline timestamp out of order for frame timeline " << i;
+            EXPECT_GT(vsyncEventData.frameTimelines[i].expectedPresentTime,
+                      vsyncEventData.frameTimelines[i - 1].expectedPresentTime)
+                    << "Expected vsync timestamp out of order for frame timeline " << i;
+        }
+    }
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
index 5a0ea35..0b6b475 100644
--- a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
@@ -28,6 +28,7 @@
 #include "AsyncCallRecorder.h"
 #include "Scheduler/DispSyncSource.h"
 #include "Scheduler/VSyncDispatch.h"
+#include "mock/MockVSyncTracker.h"
 
 namespace android {
 namespace {
@@ -125,12 +126,13 @@
     DispSyncSourceTest();
     ~DispSyncSourceTest() override;
 
-    void createDispSync();
+    void SetUp() override;
     void createDispSyncSource();
 
     void onVSyncEvent(nsecs_t when, VSyncSource::VSyncData) override;
 
     std::unique_ptr<MockVSyncDispatch> mVSyncDispatch;
+    std::unique_ptr<mock::VSyncTracker> mVSyncTracker;
     std::unique_ptr<scheduler::DispSyncSource> mDispSyncSource;
 
     AsyncCallRecorder<void (*)(nsecs_t, VSyncSource::VSyncData)> mVSyncEventCallRecorder;
@@ -154,20 +156,21 @@
     ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
 }
 
+void DispSyncSourceTest::SetUp() {
+    mVSyncDispatch = std::make_unique<MockVSyncDispatch>();
+    mVSyncTracker = std::make_unique<mock::VSyncTracker>();
+}
+
 void DispSyncSourceTest::onVSyncEvent(nsecs_t when, VSyncSource::VSyncData vsyncData) {
     ALOGD("onVSyncEvent: %" PRId64, when);
 
     mVSyncEventCallRecorder.recordCall(when, vsyncData);
 }
 
-void DispSyncSourceTest::createDispSync() {
-    mVSyncDispatch = std::make_unique<MockVSyncDispatch>();
-}
-
 void DispSyncSourceTest::createDispSyncSource() {
-    mDispSyncSource =
-            std::make_unique<scheduler::DispSyncSource>(*mVSyncDispatch, mWorkDuration,
-                                                        mReadyDuration, true, mName.c_str());
+    mDispSyncSource = std::make_unique<scheduler::DispSyncSource>(*mVSyncDispatch, *mVSyncTracker,
+                                                                  mWorkDuration, mReadyDuration,
+                                                                  true, mName.c_str());
     mDispSyncSource->setCallback(this);
 }
 
@@ -176,13 +179,10 @@
  */
 
 TEST_F(DispSyncSourceTest, createDispSync) {
-    createDispSync();
     EXPECT_TRUE(mVSyncDispatch);
 }
 
 TEST_F(DispSyncSourceTest, createDispSyncSource) {
-    createDispSync();
-
     InSequence seq;
     EXPECT_CALL(*mVSyncDispatch, registerCallback(_, mName)).WillOnce(Return(mFakeToken));
     EXPECT_CALL(*mVSyncDispatch, cancel(mFakeToken))
@@ -194,8 +194,6 @@
 }
 
 TEST_F(DispSyncSourceTest, noCallbackAfterInit) {
-    createDispSync();
-
     InSequence seq;
     EXPECT_CALL(*mVSyncDispatch, registerCallback(_, mName)).Times(1);
     EXPECT_CALL(*mVSyncDispatch, cancel(_)).Times(1);
@@ -210,8 +208,6 @@
 }
 
 TEST_F(DispSyncSourceTest, waitForCallbacks) {
-    createDispSync();
-
     InSequence seq;
     EXPECT_CALL(*mVSyncDispatch, registerCallback(_, mName)).Times(1);
     EXPECT_CALL(*mVSyncDispatch,
@@ -239,8 +235,6 @@
 }
 
 TEST_F(DispSyncSourceTest, waitForCallbacksWithDurationChange) {
-    createDispSync();
-
     InSequence seq;
     EXPECT_CALL(*mVSyncDispatch, registerCallback(_, mName)).Times(1);
     EXPECT_CALL(*mVSyncDispatch,
@@ -296,5 +290,27 @@
     EXPECT_CALL(*mVSyncDispatch, unregisterCallback(_)).Times(1);
 }
 
+TEST_F(DispSyncSourceTest, getLatestVsyncData) {
+    const nsecs_t now = systemTime();
+    const nsecs_t vsyncInternalDuration = mWorkDuration.count() + mReadyDuration.count();
+    EXPECT_CALL(*mVSyncTracker, nextAnticipatedVSyncTimeFrom(_))
+            .WillOnce(Return(now + vsyncInternalDuration + 1));
+    {
+        InSequence seq;
+        EXPECT_CALL(*mVSyncDispatch, registerCallback(_, mName)).Times(1);
+        EXPECT_CALL(*mVSyncDispatch, cancel(_)).Times(1);
+        EXPECT_CALL(*mVSyncDispatch, unregisterCallback(_)).Times(1);
+    }
+
+    createDispSyncSource();
+    EXPECT_TRUE(mDispSyncSource);
+
+    const auto vsyncData = mDispSyncSource->getLatestVSyncData();
+    ASSERT_GT(vsyncData.deadlineTimestamp, now);
+    ASSERT_GT(vsyncData.expectedVSyncTimestamp, vsyncData.deadlineTimestamp);
+    EXPECT_EQ(vsyncData.deadlineTimestamp,
+              vsyncData.expectedVSyncTimestamp - vsyncInternalDuration);
+}
+
 } // namespace
 } // namespace android
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index e5f7b03..cc0a40f 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -59,6 +59,7 @@
                  void(std::chrono::nanoseconds workDuration,
                       std::chrono::nanoseconds readyDuration));
     MOCK_METHOD1(pauseVsyncCallback, void(bool));
+    MOCK_METHOD(VSyncSource::VSyncData, getLatestVSyncData, (), (const, override));
     MOCK_CONST_METHOD1(dump, void(std::string&));
 };
 
@@ -257,7 +258,7 @@
     ASSERT_TRUE(args.has_value()) << " did not receive an event for timestamp "
                                   << expectedTimestamp;
     const auto& event = std::get<0>(args.value());
-    for (int i = 0; i < gui::VsyncEventData::kFrameTimelinesLength; i++) {
+    for (int i = 0; i < VsyncEventData::kFrameTimelinesLength; i++) {
         auto prediction =
                 mTokenManager->getPredictionsForToken(event.vsync.frameTimelines[i].vsyncId);
         EXPECT_TRUE(prediction.has_value());
@@ -332,6 +333,8 @@
 
 namespace {
 
+using namespace testing;
+
 /* ------------------------------------------------------------------------
  * Test cases
  */
@@ -399,6 +402,52 @@
     expectVsyncEventFrameTimelinesCorrect(123, 789);
 }
 
+TEST_F(EventThreadTest, getLatestVsyncEventData) {
+    const nsecs_t now = systemTime();
+    const nsecs_t preferredDeadline = now + 10000000;
+    const nsecs_t preferredExpectedVSyncTimestamp = now + 20000000;
+    const VSyncSource::VSyncData preferredData = {preferredExpectedVSyncTimestamp,
+                                                  preferredDeadline};
+    EXPECT_CALL(*mVSyncSource, getLatestVSyncData()).WillOnce(Return(preferredData));
+
+    VsyncEventData vsyncEventData = mThread->getLatestVsyncEventData(mConnection);
+    EXPECT_GT(vsyncEventData.frameTimelines[0].deadlineTimestamp, now)
+            << "Deadline timestamp should be greater than frame time";
+    for (size_t i = 0; i < VsyncEventData::kFrameTimelinesLength; i++) {
+        auto prediction =
+                mTokenManager->getPredictionsForToken(vsyncEventData.frameTimelines[i].id);
+        EXPECT_TRUE(prediction.has_value());
+        EXPECT_EQ(prediction.value().endTime, vsyncEventData.frameTimelines[i].deadlineTimestamp)
+                << "Deadline timestamp does not match cached value";
+        EXPECT_EQ(prediction.value().presentTime,
+                  vsyncEventData.frameTimelines[i].expectedPresentTime)
+                << "Expected vsync timestamp does not match cached value";
+        EXPECT_GT(vsyncEventData.frameTimelines[i].expectedPresentTime,
+                  vsyncEventData.frameTimelines[i].deadlineTimestamp)
+                << "Expected vsync timestamp should be greater than deadline";
+
+        if (i > 0) {
+            EXPECT_GT(vsyncEventData.frameTimelines[i].deadlineTimestamp,
+                      vsyncEventData.frameTimelines[i - 1].deadlineTimestamp)
+                    << "Deadline timestamp out of order for frame timeline " << i;
+            EXPECT_GT(vsyncEventData.frameTimelines[i].expectedPresentTime,
+                      vsyncEventData.frameTimelines[i - 1].expectedPresentTime)
+                    << "Expected vsync timestamp out of order for frame timeline " << i;
+        }
+
+        // Vsync ID order lines up with registration into test token manager.
+        EXPECT_EQ(i, vsyncEventData.frameTimelines[i].id)
+                << "Vsync ID incorrect for frame timeline " << i;
+        if (i == vsyncEventData.preferredFrameTimelineIndex) {
+            EXPECT_EQ(vsyncEventData.frameTimelines[i].deadlineTimestamp, preferredDeadline)
+                    << "Preferred deadline timestamp incorrect" << i;
+            EXPECT_EQ(vsyncEventData.frameTimelines[i].expectedPresentTime,
+                      preferredExpectedVSyncTimestamp)
+                    << "Preferred expected vsync timestamp incorrect" << i;
+        }
+    }
+}
+
 TEST_F(EventThreadTest, setVsyncRateZeroPostsNoVSyncEventsToThatConnection) {
     // Create a first connection, register it, and request a vsync rate of zero.
     ConnectionEventRecorder firstConnectionEventRecorder{0};
diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
index d25973e..c5ca86a 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
@@ -44,6 +44,8 @@
                  status_t(const sp<android::EventThreadConnection> &));
     MOCK_METHOD2(setVsyncRate, void(uint32_t, const sp<android::EventThreadConnection> &));
     MOCK_METHOD1(requestNextVsync, void(const sp<android::EventThreadConnection> &));
+    MOCK_METHOD(VsyncEventData, getLatestVsyncEventData,
+                (const sp<android::EventThreadConnection> &), (const));
     MOCK_METHOD1(requestLatestConfig, void(const sp<android::EventThreadConnection> &));
     MOCK_METHOD1(pauseVsyncCallback, void(bool));
     MOCK_METHOD0(getEventThreadConnectionCount, size_t());