SF: remove DispSyncSource

DispSyncSource is a legacy reminder of DispSync which was removed
a while ago. This changes removes the DispSyncSource and instead use
the VsyncDispatch interface directly.

Test: SF unit tests
Bug: 255601557
Bug: 256196556
Change-Id: I4247c3927b9ee9443437bf960f8cedc29759c4ac
diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.cpp b/services/surfaceflinger/Scheduler/DispSyncSource.cpp
deleted file mode 100644
index 4af1f5c..0000000
--- a/services/surfaceflinger/Scheduler/DispSyncSource.cpp
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Copyright 2018 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.
- */
-
-#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-
-#include "DispSyncSource.h"
-
-#include <android-base/stringprintf.h>
-#include <utils/Trace.h>
-#include <mutex>
-
-#include "EventThread.h"
-#include "VSyncTracker.h"
-#include "VsyncController.h"
-
-namespace android::scheduler {
-using base::StringAppendF;
-using namespace std::chrono_literals;
-
-class CallbackRepeater {
-public:
-    CallbackRepeater(VSyncDispatch& dispatch, VSyncDispatch::Callback cb, const char* name,
-                     std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration,
-                     std::chrono::nanoseconds notBefore)
-          : mName(name),
-            mCallback(cb),
-            mRegistration(dispatch,
-                          std::bind(&CallbackRepeater::callback, this, std::placeholders::_1,
-                                    std::placeholders::_2, std::placeholders::_3),
-                          mName),
-            mStarted(false),
-            mWorkDuration(workDuration),
-            mReadyDuration(readyDuration),
-            mLastCallTime(notBefore) {}
-
-    ~CallbackRepeater() {
-        std::lock_guard lock(mMutex);
-        mRegistration.cancel();
-    }
-
-    void start(std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration) {
-        std::lock_guard lock(mMutex);
-        mStarted = true;
-        mWorkDuration = workDuration;
-        mReadyDuration = readyDuration;
-
-        auto const scheduleResult =
-                mRegistration.schedule({.workDuration = mWorkDuration.count(),
-                                        .readyDuration = mReadyDuration.count(),
-                                        .earliestVsync = mLastCallTime.count()});
-        LOG_ALWAYS_FATAL_IF((!scheduleResult.has_value()), "Error scheduling callback");
-    }
-
-    void stop() {
-        std::lock_guard lock(mMutex);
-        LOG_ALWAYS_FATAL_IF(!mStarted, "DispSyncInterface misuse: callback already stopped");
-        mStarted = false;
-        mRegistration.cancel();
-    }
-
-    void dump(std::string& result) const {
-        std::lock_guard lock(mMutex);
-        const auto relativeLastCallTime =
-                mLastCallTime - std::chrono::steady_clock::now().time_since_epoch();
-        StringAppendF(&result, "\t%s: ", mName.c_str());
-        StringAppendF(&result, "mWorkDuration=%.2f mReadyDuration=%.2f last vsync time ",
-                      mWorkDuration.count() / 1e6f, mReadyDuration.count() / 1e6f);
-        StringAppendF(&result, "%.2fms relative to now (%s)\n", relativeLastCallTime.count() / 1e6f,
-                      mStarted ? "running" : "stopped");
-    }
-
-private:
-    void callback(nsecs_t vsyncTime, nsecs_t wakeupTime, nsecs_t readyTime) {
-        {
-            std::lock_guard lock(mMutex);
-            mLastCallTime = std::chrono::nanoseconds(vsyncTime);
-        }
-
-        mCallback(vsyncTime, wakeupTime, readyTime);
-
-        {
-            std::lock_guard lock(mMutex);
-            if (!mStarted) {
-                return;
-            }
-            auto const scheduleResult =
-                    mRegistration.schedule({.workDuration = mWorkDuration.count(),
-                                            .readyDuration = mReadyDuration.count(),
-                                            .earliestVsync = vsyncTime});
-            LOG_ALWAYS_FATAL_IF(!scheduleResult.has_value(), "Error rescheduling callback");
-        }
-    }
-
-    const std::string mName;
-    scheduler::VSyncDispatch::Callback mCallback;
-
-    mutable std::mutex mMutex;
-    VSyncCallbackRegistration mRegistration GUARDED_BY(mMutex);
-    bool mStarted GUARDED_BY(mMutex) = false;
-    std::chrono::nanoseconds mWorkDuration GUARDED_BY(mMutex) = 0ns;
-    std::chrono::nanoseconds mReadyDuration GUARDED_BY(mMutex) = 0ns;
-    std::chrono::nanoseconds mLastCallTime GUARDED_BY(mMutex) = 0ns;
-};
-
-DispSyncSource::DispSyncSource(VSyncDispatch& vSyncDispatch, VSyncTracker& vSyncTracker,
-                               std::chrono::nanoseconds workDuration,
-                               std::chrono::nanoseconds readyDuration, bool traceVsync,
-                               const char* name)
-      : mName(name),
-        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 =
-            std::make_unique<CallbackRepeater>(vSyncDispatch,
-                                               std::bind(&DispSyncSource::onVsyncCallback, this,
-                                                         std::placeholders::_1,
-                                                         std::placeholders::_2,
-                                                         std::placeholders::_3),
-                                               name, workDuration, readyDuration,
-                                               std::chrono::steady_clock::now().time_since_epoch());
-}
-
-DispSyncSource::~DispSyncSource() = default;
-
-void DispSyncSource::setVSyncEnabled(bool enable) {
-    std::lock_guard lock(mVsyncMutex);
-    if (enable) {
-        mCallbackRepeater->start(mWorkDuration, mReadyDuration);
-        // ATRACE_INT(mVsyncOnLabel.c_str(), 1);
-    } else {
-        mCallbackRepeater->stop();
-        // ATRACE_INT(mVsyncOnLabel.c_str(), 0);
-    }
-    mEnabled = enable;
-}
-
-void DispSyncSource::setCallback(VSyncSource::Callback* callback) {
-    std::lock_guard lock(mCallbackMutex);
-    mCallback = callback;
-}
-
-void DispSyncSource::setDuration(std::chrono::nanoseconds workDuration,
-                                 std::chrono::nanoseconds readyDuration) {
-    std::lock_guard lock(mVsyncMutex);
-    mWorkDuration = workDuration;
-    mReadyDuration = readyDuration;
-
-    // If we're not enabled, we don't need to mess with the listeners
-    if (!mEnabled) {
-        return;
-    }
-
-    mCallbackRepeater->start(mWorkDuration, mReadyDuration);
-}
-
-void DispSyncSource::onVsyncCallback(nsecs_t vsyncTime, nsecs_t targetWakeupTime,
-                                     nsecs_t readyTime) {
-    VSyncSource::Callback* callback;
-    {
-        std::lock_guard lock(mCallbackMutex);
-        callback = mCallback;
-    }
-
-    if (mTraceVsync) {
-        mValue = (mValue + 1) % 2;
-    }
-
-    if (callback != nullptr) {
-        callback->onVSyncEvent(targetWakeupTime, {vsyncTime, readyTime});
-    }
-}
-
-VSyncSource::VSyncData DispSyncSource::getLatestVSyncData() const {
-    std::lock_guard lock(mVsyncMutex);
-    nsecs_t expectedPresentationTime = mVSyncTracker.nextAnticipatedVSyncTimeFrom(
-            systemTime() + mWorkDuration.get().count() + mReadyDuration.count());
-    nsecs_t deadline = expectedPresentationTime - mReadyDuration.count();
-    return {expectedPresentationTime, deadline};
-}
-
-void DispSyncSource::dump(std::string& result) const {
-    std::lock_guard lock(mVsyncMutex);
-    StringAppendF(&result, "DispSyncSource: %s(%s)\n", mName, mEnabled ? "enabled" : "disabled");
-}
-
-} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.h b/services/surfaceflinger/Scheduler/DispSyncSource.h
deleted file mode 100644
index edcd3ac..0000000
--- a/services/surfaceflinger/Scheduler/DispSyncSource.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright 2018 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.
- */
-#pragma once
-
-#include <mutex>
-#include <string>
-
-#include "EventThread.h"
-#include "TracedOrdinal.h"
-#include "VSyncDispatch.h"
-
-namespace android::scheduler {
-class CallbackRepeater;
-class VSyncTracker;
-
-class DispSyncSource final : public VSyncSource {
-public:
-    DispSyncSource(VSyncDispatch& vSyncDispatch, VSyncTracker& vSyncTracker,
-                   std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration,
-                   bool traceVsync, const char* name);
-
-    ~DispSyncSource() override;
-
-    // The following methods are implementation of VSyncSource.
-    const char* getName() const override { return mName; }
-    void setVSyncEnabled(bool enable) override;
-    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;
-
-private:
-    void onVsyncCallback(nsecs_t vsyncTime, nsecs_t targetWakeupTime, nsecs_t readyTime);
-
-    const char* const mName;
-    TracedOrdinal<int> mValue;
-
-    const bool mTraceVsync;
-    const std::string mVsyncOnLabel;
-
-    const VSyncTracker& mVSyncTracker;
-
-    std::unique_ptr<CallbackRepeater> mCallbackRepeater;
-
-    std::mutex mCallbackMutex;
-    VSyncSource::Callback* mCallback GUARDED_BY(mCallbackMutex) = nullptr;
-
-    mutable std::mutex mVsyncMutex;
-    TracedOrdinal<std::chrono::nanoseconds> mWorkDuration GUARDED_BY(mVsyncMutex);
-    std::chrono::nanoseconds mReadyDuration GUARDED_BY(mVsyncMutex);
-    bool mEnabled GUARDED_BY(mVsyncMutex) = false;
-};
-
-} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index 008d8c4..a902a8e 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -28,6 +28,7 @@
 #include <cstdint>
 #include <optional>
 #include <type_traits>
+#include <utility>
 
 #include <android-base/stringprintf.h>
 
@@ -43,6 +44,8 @@
 
 #include "DisplayHardware/DisplayMode.h"
 #include "FrameTimeline.h"
+#include "VSyncDispatch.h"
+#include "VSyncTracker.h"
 
 #include "EventThread.h"
 
@@ -235,20 +238,29 @@
 
 namespace impl {
 
-EventThread::EventThread(std::unique_ptr<VSyncSource> vsyncSource,
+EventThread::EventThread(const char* name, scheduler::VsyncSchedule& vsyncSchedule,
                          android::frametimeline::TokenManager* tokenManager,
                          ThrottleVsyncCallback throttleVsyncCallback,
-                         GetVsyncPeriodFunction getVsyncPeriodFunction)
-      : mVSyncSource(std::move(vsyncSource)),
+                         GetVsyncPeriodFunction getVsyncPeriodFunction,
+                         std::chrono::nanoseconds workDuration,
+                         std::chrono::nanoseconds readyDuration)
+      : mThreadName(name),
+        mVsyncTracer(base::StringPrintf("VSYNC-%s", name), 0),
+        mWorkDuration(base::StringPrintf("VsyncWorkDuration-%s", name), workDuration),
+        mReadyDuration(readyDuration),
+        mVsyncSchedule(vsyncSchedule),
+        mVsyncRegistration(
+                vsyncSchedule.getDispatch(),
+                [this](nsecs_t vsyncTime, nsecs_t wakeupTime, nsecs_t readyTime) {
+                    onVsync(vsyncTime, wakeupTime, readyTime);
+                },
+                name),
         mTokenManager(tokenManager),
         mThrottleVsyncCallback(std::move(throttleVsyncCallback)),
-        mGetVsyncPeriodFunction(std::move(getVsyncPeriodFunction)),
-        mThreadName(mVSyncSource->getName()) {
+        mGetVsyncPeriodFunction(std::move(getVsyncPeriodFunction)) {
     LOG_ALWAYS_FATAL_IF(getVsyncPeriodFunction == nullptr,
             "getVsyncPeriodFunction must not be null");
 
-    mVSyncSource->setCallback(this);
-
     mThread = std::thread([this]() NO_THREAD_SAFETY_ANALYSIS {
         std::unique_lock<std::mutex> lock(mMutex);
         threadMain(lock);
@@ -270,8 +282,6 @@
 }
 
 EventThread::~EventThread() {
-    mVSyncSource->setCallback(nullptr);
-
     {
         std::lock_guard<std::mutex> lock(mMutex);
         mState = State::Quit;
@@ -283,7 +293,12 @@
 void EventThread::setDuration(std::chrono::nanoseconds workDuration,
                               std::chrono::nanoseconds readyDuration) {
     std::lock_guard<std::mutex> lock(mMutex);
-    mVSyncSource->setDuration(workDuration, readyDuration);
+    mWorkDuration = workDuration;
+    mReadyDuration = readyDuration;
+
+    mVsyncRegistration.update({.workDuration = mWorkDuration.get().count(),
+                               .readyDuration = mReadyDuration.count(),
+                               .earliestVsync = mLastVsyncCallbackTime.ns()});
 }
 
 sp<EventThreadConnection> EventThread::createEventConnection(
@@ -358,13 +373,14 @@
     VsyncEventData vsyncEventData;
     nsecs_t frameInterval = mGetVsyncPeriodFunction(connection->mOwnerUid);
     vsyncEventData.frameInterval = frameInterval;
-    VSyncSource::VSyncData vsyncData;
-    {
+    const auto [presentTime, deadline] = [&]() -> std::pair<nsecs_t, nsecs_t> {
         std::lock_guard<std::mutex> lock(mMutex);
-        vsyncData = mVSyncSource->getLatestVSyncData();
-    }
+        const auto vsyncTime = mVsyncSchedule.getTracker().nextAnticipatedVSyncTimeFrom(
+                systemTime() + mWorkDuration.get().count() + mReadyDuration.count());
+        return {vsyncTime, vsyncTime - mReadyDuration.count()};
+    }();
     generateFrameTimeline(vsyncEventData, frameInterval, systemTime(SYSTEM_TIME_MONOTONIC),
-                          vsyncData.expectedPresentationTime, vsyncData.deadlineTimestamp);
+                          presentTime, deadline);
     return vsyncEventData;
 }
 
@@ -388,13 +404,14 @@
     mCondition.notify_all();
 }
 
-void EventThread::onVSyncEvent(nsecs_t timestamp, VSyncSource::VSyncData vsyncData) {
+void EventThread::onVsync(nsecs_t vsyncTime, nsecs_t wakeupTime, nsecs_t readyTime) {
     std::lock_guard<std::mutex> lock(mMutex);
+    mLastVsyncCallbackTime = TimePoint::fromNs(vsyncTime);
 
     LOG_FATAL_IF(!mVSyncState);
-    mPendingEvents.push_back(makeVSync(mVSyncState->displayId, timestamp, ++mVSyncState->count,
-                                       vsyncData.expectedPresentationTime,
-                                       vsyncData.deadlineTimestamp));
+    mVsyncTracer = (mVsyncTracer + 1) % 2;
+    mPendingEvents.push_back(makeVSync(mVSyncState->displayId, wakeupTime, ++mVSyncState->count,
+                                       vsyncTime, readyTime));
     mCondition.notify_all();
 }
 
@@ -456,12 +473,12 @@
         auto it = mDisplayEventConnections.begin();
         while (it != mDisplayEventConnections.end()) {
             if (const auto connection = it->promote()) {
-                vsyncRequested |= connection->vsyncRequest != VSyncRequest::None;
-
                 if (event && shouldConsumeEvent(*event, connection)) {
                     consumers.push_back(connection);
                 }
 
+                vsyncRequested |= connection->vsyncRequest != VSyncRequest::None;
+
                 ++it;
             } else {
                 it = mDisplayEventConnections.erase(it);
@@ -473,25 +490,24 @@
             consumers.clear();
         }
 
-        State nextState;
         if (mVSyncState && vsyncRequested) {
-            nextState = mVSyncState->synthetic ? State::SyntheticVSync : State::VSync;
+            mState = mVSyncState->synthetic ? State::SyntheticVSync : State::VSync;
         } else {
             ALOGW_IF(!mVSyncState, "Ignoring VSYNC request while display is disconnected");
-            nextState = State::Idle;
+            mState = State::Idle;
         }
 
-        if (mState != nextState) {
-            if (mState == State::VSync) {
-                mVSyncSource->setVSyncEnabled(false);
-            } else if (nextState == State::VSync) {
-                mVSyncSource->setVSyncEnabled(true);
-            }
-
-            mState = nextState;
+        if (mState == State::VSync) {
+            const auto scheduleResult =
+                    mVsyncRegistration.schedule({.workDuration = mWorkDuration.get().count(),
+                                                 .readyDuration = mReadyDuration.count(),
+                                                 .earliestVsync = mLastVsyncCallbackTime.ns()});
+            LOG_ALWAYS_FATAL_IF(!scheduleResult, "Error scheduling callback");
+        } else {
+            mVsyncRegistration.cancel();
         }
 
-        if (event) {
+        if (!mPendingEvents.empty()) {
             continue;
         }
 
@@ -506,15 +522,6 @@
             if (mCondition.wait_for(lock, timeout) == std::cv_status::timeout) {
                 if (mState == State::VSync) {
                     ALOGW("Faking VSYNC due to driver stall for thread %s", mThreadName);
-                    std::string debugInfo = "VsyncSource debug info:\n";
-                    mVSyncSource->dump(debugInfo);
-                    // Log the debug info line-by-line to avoid logcat overflow
-                    auto pos = debugInfo.find('\n');
-                    while (pos != std::string::npos) {
-                        ALOGW("%s", debugInfo.substr(0, pos).c_str());
-                        debugInfo = debugInfo.substr(pos + 1);
-                        pos = debugInfo.find('\n');
-                    }
                 }
 
                 LOG_FATAL_IF(!mVSyncState);
@@ -527,6 +534,8 @@
             }
         }
     }
+    // cancel any pending vsync event before exiting
+    mVsyncRegistration.cancel();
 }
 
 bool EventThread::shouldConsumeEvent(const DisplayEventReceiver::Event& event,
@@ -657,6 +666,12 @@
         StringAppendF(&result, "none\n");
     }
 
+    const auto relativeLastCallTime =
+            ticks<std::milli, float>(mLastVsyncCallbackTime - TimePoint::now());
+    StringAppendF(&result, "mWorkDuration=%.2f mReadyDuration=%.2f last vsync time ",
+                  mWorkDuration.get().count() / 1e6f, mReadyDuration.count() / 1e6f);
+    StringAppendF(&result, "%.2fms relative to now\n", relativeLastCallTime);
+
     StringAppendF(&result, "  pending events (count=%zu):\n", mPendingEvents.size());
     for (const auto& event : mPendingEvents) {
         StringAppendF(&result, "    %s\n", toString(event).c_str());
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index 43c3598..ab9085e 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -33,6 +33,9 @@
 #include <vector>
 
 #include "DisplayHardware/DisplayMode.h"
+#include "TracedOrdinal.h"
+#include "VSyncDispatch.h"
+#include "VsyncSchedule.h"
 
 // ---------------------------------------------------------------------------
 namespace android {
@@ -64,32 +67,6 @@
     // Subsequent values are periods.
 };
 
-class VSyncSource {
-public:
-    class VSyncData {
-    public:
-        nsecs_t expectedPresentationTime;
-        nsecs_t deadlineTimestamp;
-    };
-
-    class Callback {
-    public:
-        virtual ~Callback() {}
-        virtual void onVSyncEvent(nsecs_t when, VSyncData vsyncData) = 0;
-    };
-
-    virtual ~VSyncSource() {}
-
-    virtual const char* getName() const = 0;
-    virtual void setVSyncEnabled(bool enable) = 0;
-    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;
-};
-
 class EventThreadConnection : public gui::BnDisplayEventConnection {
 public:
     EventThreadConnection(EventThread*, uid_t callingUid, ResyncCallback,
@@ -160,13 +137,14 @@
 
 namespace impl {
 
-class EventThread : public android::EventThread, private VSyncSource::Callback {
+class EventThread : public android::EventThread {
 public:
     using ThrottleVsyncCallback = std::function<bool(nsecs_t, uid_t)>;
     using GetVsyncPeriodFunction = std::function<nsecs_t(uid_t)>;
 
-    EventThread(std::unique_ptr<VSyncSource>, frametimeline::TokenManager*, ThrottleVsyncCallback,
-                GetVsyncPeriodFunction);
+    EventThread(const char* name, scheduler::VsyncSchedule&, frametimeline::TokenManager*,
+                ThrottleVsyncCallback, GetVsyncPeriodFunction,
+                std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration);
     ~EventThread();
 
     sp<EventThreadConnection> createEventConnection(
@@ -213,8 +191,7 @@
     void removeDisplayEventConnectionLocked(const wp<EventThreadConnection>& connection)
             REQUIRES(mMutex);
 
-    // Implements VSyncSource::Callback
-    void onVSyncEvent(nsecs_t timestamp, VSyncSource::VSyncData vsyncData) override;
+    void onVsync(nsecs_t vsyncTime, nsecs_t wakeupTime, nsecs_t readyTime);
 
     int64_t generateToken(nsecs_t timestamp, nsecs_t deadlineTimestamp,
                           nsecs_t expectedPresentationTime) const;
@@ -222,12 +199,17 @@
                                nsecs_t timestamp, nsecs_t preferredExpectedPresentationTime,
                                nsecs_t preferredDeadlineTimestamp) const;
 
-    const std::unique_ptr<VSyncSource> mVSyncSource GUARDED_BY(mMutex);
+    const char* const mThreadName;
+    TracedOrdinal<int> mVsyncTracer;
+    TracedOrdinal<std::chrono::nanoseconds> mWorkDuration GUARDED_BY(mMutex);
+    std::chrono::nanoseconds mReadyDuration GUARDED_BY(mMutex);
+    scheduler::VsyncSchedule& mVsyncSchedule;
+    TimePoint mLastVsyncCallbackTime GUARDED_BY(mMutex) = TimePoint::now();
+    scheduler::VSyncCallbackRegistration mVsyncRegistration GUARDED_BY(mMutex);
     frametimeline::TokenManager* const mTokenManager;
 
     const ThrottleVsyncCallback mThrottleVsyncCallback;
     const GetVsyncPeriodFunction mGetVsyncPeriodFunction;
-    const char* const mThreadName;
 
     std::thread mThread;
     mutable std::mutex mMutex;
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.cpp b/services/surfaceflinger/Scheduler/MessageQueue.cpp
index ae10ff4..e827c12 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.cpp
+++ b/services/surfaceflinger/Scheduler/MessageQueue.cpp
@@ -78,7 +78,8 @@
 void MessageQueue::initVsync(scheduler::VSyncDispatch& dispatch,
                              frametimeline::TokenManager& tokenManager,
                              std::chrono::nanoseconds workDuration) {
-    setDuration(workDuration);
+    std::lock_guard lock(mVsync.mutex);
+    mVsync.workDuration = workDuration;
     mVsync.tokenManager = &tokenManager;
     mVsync.registration = std::make_unique<
             scheduler::VSyncCallbackRegistration>(dispatch,
@@ -89,16 +90,20 @@
                                                   "sf");
 }
 
+void MessageQueue::destroyVsync() {
+    std::lock_guard lock(mVsync.mutex);
+    mVsync.tokenManager = nullptr;
+    mVsync.registration.reset();
+}
+
 void MessageQueue::setDuration(std::chrono::nanoseconds workDuration) {
     ATRACE_CALL();
     std::lock_guard lock(mVsync.mutex);
     mVsync.workDuration = workDuration;
-    if (mVsync.scheduledFrameTime) {
-        mVsync.scheduledFrameTime =
-                mVsync.registration->schedule({.workDuration = mVsync.workDuration.get().count(),
-                                               .readyDuration = 0,
-                                               .earliestVsync = mVsync.lastCallbackTime.ns()});
-    }
+    mVsync.scheduledFrameTime =
+            mVsync.registration->update({.workDuration = mVsync.workDuration.get().count(),
+                                         .readyDuration = 0,
+                                         .earliestVsync = mVsync.lastCallbackTime.ns()});
 }
 
 void MessageQueue::waitMessage() {
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.h b/services/surfaceflinger/Scheduler/MessageQueue.h
index 04de492..71f8645 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.h
+++ b/services/surfaceflinger/Scheduler/MessageQueue.h
@@ -75,6 +75,7 @@
 
     virtual void initVsync(scheduler::VSyncDispatch&, frametimeline::TokenManager&,
                            std::chrono::nanoseconds workDuration) = 0;
+    virtual void destroyVsync() = 0;
     virtual void setDuration(std::chrono::nanoseconds workDuration) = 0;
     virtual void waitMessage() = 0;
     virtual void postMessage(sp<MessageHandler>&&) = 0;
@@ -138,6 +139,7 @@
 
     void initVsync(scheduler::VSyncDispatch&, frametimeline::TokenManager&,
                    std::chrono::nanoseconds workDuration) override;
+    void destroyVsync() override;
     void setDuration(std::chrono::nanoseconds workDuration) override;
 
     void waitMessage() override;
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 74a81b7..bc465ce 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -42,7 +42,6 @@
 #include <numeric>
 
 #include "../Layer.h"
-#include "DispSyncSource.h"
 #include "Display/DisplayMap.h"
 #include "EventThread.h"
 #include "FrameRateOverrideMappings.h"
@@ -65,6 +64,11 @@
       : impl::MessageQueue(compositor), mFeatures(features), mSchedulerCallback(callback) {}
 
 Scheduler::~Scheduler() {
+    // MessageQueue depends on VsyncSchedule, so first destroy it.
+    // Otherwise, MessageQueue will get destroyed after Scheduler's dtor,
+    // which will cause a use-after-free issue.
+    Impl::destroyVsync();
+
     // Stop timers and wait for their threads to exit.
     mDisplayPowerTimer.reset();
     mTouchTimer.reset();
@@ -142,14 +146,6 @@
     mVsyncSchedule.emplace(features);
 }
 
-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>(mVsyncSchedule->getDispatch(),
-                                                       mVsyncSchedule->getTracker(), workDuration,
-                                                       readyDuration, traceVsync, name);
-}
-
 std::optional<Fps> Scheduler::getFrameRateOverride(uid_t uid) const {
     const bool supportsFrameRateOverrideByContent =
             leaderSelectorPtr()->supportsAppFrameRateOverrideByContent();
@@ -194,12 +190,12 @@
                                              frametimeline::TokenManager* tokenManager,
                                              std::chrono::nanoseconds workDuration,
                                              std::chrono::nanoseconds readyDuration) {
-    auto vsyncSource = makePrimaryDispSyncSource(connectionName, workDuration, readyDuration);
     auto throttleVsync = makeThrottleVsyncCallback();
     auto getVsyncPeriod = makeGetVsyncPeriodFunction();
-    auto eventThread = std::make_unique<impl::EventThread>(std::move(vsyncSource), tokenManager,
-                                                           std::move(throttleVsync),
-                                                           std::move(getVsyncPeriod));
+    auto eventThread =
+            std::make_unique<impl::EventThread>(connectionName, *mVsyncSchedule, tokenManager,
+                                                std::move(throttleVsync), std::move(getVsyncPeriod),
+                                                workDuration, readyDuration);
     return createConnection(std::move(eventThread));
 }
 
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index f189426..20221d1 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -223,11 +223,6 @@
 
     size_t getEventThreadConnectionCount(ConnectionHandle handle);
 
-    std::unique_ptr<VSyncSource> makePrimaryDispSyncSource(const char* name,
-                                                           std::chrono::nanoseconds workDuration,
-                                                           std::chrono::nanoseconds readyDuration,
-                                                           bool traceVsync = true);
-
     // Stores the preferred refresh rate that an app should run at.
     // FrameRateOverride.refreshRateHz == 0 means no preference.
     void setPreferredRefreshRateForUid(FrameRateOverride);
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatch.h b/services/surfaceflinger/Scheduler/VSyncDispatch.h
index 2bfe204..9520131 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatch.h
+++ b/services/surfaceflinger/Scheduler/VSyncDispatch.h
@@ -126,6 +126,17 @@
      */
     virtual ScheduleResult schedule(CallbackToken token, ScheduleTiming scheduleTiming) = 0;
 
+    /*
+     * Update the timing information for a scheduled callback.
+     * If the callback is not scheduled, then this function does nothing.
+     *
+     * \param [in] token           The callback to schedule.
+     * \param [in] scheduleTiming  The timing information for this schedule call
+     * \return                     The expected callback time if a callback was scheduled.
+     *                             std::nullopt if the callback is not registered.
+     */
+    virtual ScheduleResult update(CallbackToken token, ScheduleTiming scheduleTiming) = 0;
+
     /* Cancels a scheduled callback, if possible.
      *
      * \param [in] token    The callback to cancel.
@@ -159,6 +170,9 @@
     // See documentation for VSyncDispatch::schedule.
     ScheduleResult schedule(VSyncDispatch::ScheduleTiming scheduleTiming);
 
+    // See documentation for VSyncDispatch::update.
+    ScheduleResult update(VSyncDispatch::ScheduleTiming scheduleTiming);
+
     // See documentation for VSyncDispatch::cancel.
     CancelResult cancel();
 
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
index cc9f7cf..73d52cf 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
@@ -347,38 +347,54 @@
 
 ScheduleResult VSyncDispatchTimerQueue::schedule(CallbackToken token,
                                                  ScheduleTiming scheduleTiming) {
-    ScheduleResult result;
-    {
-        std::lock_guard lock(mMutex);
+    std::lock_guard lock(mMutex);
+    return scheduleLocked(token, scheduleTiming);
+}
 
-        auto it = mCallbacks.find(token);
-        if (it == mCallbacks.end()) {
-            return result;
-        }
-        auto& callback = it->second;
-        auto const now = mTimeKeeper->now();
+ScheduleResult VSyncDispatchTimerQueue::scheduleLocked(CallbackToken token,
+                                                       ScheduleTiming scheduleTiming) {
+    auto it = mCallbacks.find(token);
+    if (it == mCallbacks.end()) {
+        return {};
+    }
+    auto& callback = it->second;
+    auto const now = mTimeKeeper->now();
 
-        /* If the timer thread will run soon, we'll apply this work update via the callback
-         * timer recalculation to avoid cancelling a callback that is about to fire. */
-        auto const rearmImminent = now > mIntendedWakeupTime;
-        if (CC_UNLIKELY(rearmImminent)) {
-            callback->addPendingWorkloadUpdate(scheduleTiming);
-            return getExpectedCallbackTime(mTracker, now, scheduleTiming);
-        }
+    /* If the timer thread will run soon, we'll apply this work update via the callback
+     * timer recalculation to avoid cancelling a callback that is about to fire. */
+    auto const rearmImminent = now > mIntendedWakeupTime;
+    if (CC_UNLIKELY(rearmImminent)) {
+        callback->addPendingWorkloadUpdate(scheduleTiming);
+        return getExpectedCallbackTime(mTracker, now, scheduleTiming);
+    }
 
-        result = callback->schedule(scheduleTiming, mTracker, now);
-        if (!result.has_value()) {
-            return result;
-        }
+    const ScheduleResult result = callback->schedule(scheduleTiming, mTracker, now);
+    if (!result.has_value()) {
+        return {};
+    }
 
-        if (callback->wakeupTime() < mIntendedWakeupTime - mTimerSlack) {
-            rearmTimerSkippingUpdateFor(now, it);
-        }
+    if (callback->wakeupTime() < mIntendedWakeupTime - mTimerSlack) {
+        rearmTimerSkippingUpdateFor(now, it);
     }
 
     return result;
 }
 
+ScheduleResult VSyncDispatchTimerQueue::update(CallbackToken token, ScheduleTiming scheduleTiming) {
+    std::lock_guard lock(mMutex);
+    const auto it = mCallbacks.find(token);
+    if (it == mCallbacks.end()) {
+        return {};
+    }
+
+    auto& callback = it->second;
+    if (!callback->targetVsync().has_value()) {
+        return {};
+    }
+
+    return scheduleLocked(token, scheduleTiming);
+}
+
 CancelResult VSyncDispatchTimerQueue::cancel(CallbackToken token) {
     std::lock_guard lock(mMutex);
 
@@ -451,6 +467,13 @@
     return mDispatch.get().schedule(mToken, scheduleTiming);
 }
 
+ScheduleResult VSyncCallbackRegistration::update(VSyncDispatch::ScheduleTiming scheduleTiming) {
+    if (!mValidToken) {
+        return std::nullopt;
+    }
+    return mDispatch.get().update(mToken, scheduleTiming);
+}
+
 CancelResult VSyncCallbackRegistration::cancel() {
     if (!mValidToken) {
         return CancelResult::Error;
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h
index 4f2f87a..c3af136 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h
+++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h
@@ -127,6 +127,7 @@
     CallbackToken registerCallback(Callback, std::string callbackName) final;
     void unregisterCallback(CallbackToken) final;
     ScheduleResult schedule(CallbackToken, ScheduleTiming) final;
+    ScheduleResult update(CallbackToken, ScheduleTiming) final;
     CancelResult cancel(CallbackToken) final;
     void dump(std::string&) const final;
 
@@ -143,6 +144,7 @@
     void rearmTimerSkippingUpdateFor(nsecs_t now, CallbackMap::iterator const& skipUpdate)
             REQUIRES(mMutex);
     void cancelTimer() REQUIRES(mMutex);
+    ScheduleResult scheduleLocked(CallbackToken, ScheduleTiming) REQUIRES(mMutex);
 
     static constexpr nsecs_t kInvalidTime = std::numeric_limits<int64_t>::max();
     std::unique_ptr<TimeKeeper> const mTimeKeeper;
diff --git a/services/surfaceflinger/Scheduler/VsyncSchedule.h b/services/surfaceflinger/Scheduler/VsyncSchedule.h
index 8c17409..173b1d0 100644
--- a/services/surfaceflinger/Scheduler/VsyncSchedule.h
+++ b/services/surfaceflinger/Scheduler/VsyncSchedule.h
@@ -22,6 +22,14 @@
 #include <scheduler/Features.h>
 #include <scheduler/Time.h>
 
+namespace android {
+class EventThreadTest;
+}
+
+namespace android::fuzz {
+class SchedulerFuzzer;
+}
+
 namespace android::scheduler {
 
 // TODO(b/185535769): Rename classes, and remove aliases.
@@ -54,6 +62,8 @@
 
 private:
     friend class TestableScheduler;
+    friend class android::EventThreadTest;
+    friend class android::fuzz::SchedulerFuzzer;
 
     using TrackerPtr = std::unique_ptr<VsyncTracker>;
     using DispatchPtr = std::unique_ptr<VsyncDispatch>;