SF: Decouple MessageQueue

Define an ICompositor interface against which MessageQueue (which ought
to be an implementation detail of Scheduler) is implemented. Change the
equivocal invalidate/refresh nomenclature to commit/composite. Schedule
sampling only after composite.

Bug: 185535769
Test: libsurfaceflinger_unittest
Change-Id: I0c18f312459bae48531449f24f7b53c104fc5812
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index ef05fe2..160b2ea 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -486,7 +486,7 @@
     // try again later
     if (!fenceHasSignaled()) {
         ATRACE_NAME("!fenceHasSignaled()");
-        mFlinger->signalLayerUpdate();
+        mFlinger->onLayerUpdate();
         return false;
     }
 
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 8bbe438..bf38177 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -228,7 +228,7 @@
     if (updateResult == BufferQueue::PRESENT_LATER) {
         // Producer doesn't want buffer to be displayed yet.  Signal a
         // layer update so we check again at the next opportunity.
-        mFlinger->signalLayerUpdate();
+        mFlinger->onLayerUpdate();
         return BAD_VALUE;
     } else if (updateResult == BufferLayerConsumer::BUFFER_REJECTED) {
         // If the buffer has been rejected, remove it from the shadow queue
@@ -309,7 +309,7 @@
     // Decrement the queued-frames count.  Signal another event if we
     // have more frames pending.
     if ((queuedBuffer && more_frames_pending) || mAutoRefresh) {
-        mFlinger->signalLayerUpdate();
+        mFlinger->onLayerUpdate();
     }
 
     return NO_ERROR;
@@ -412,7 +412,7 @@
     mFlinger->mInterceptor->saveBufferUpdate(layerId, item.mGraphicBuffer->getWidth(),
                                              item.mGraphicBuffer->getHeight(), item.mFrameNumber);
 
-    mFlinger->signalLayerUpdate();
+    mFlinger->onLayerUpdate();
     mConsumer->onBufferAvailable(item);
 }
 
@@ -458,7 +458,7 @@
     bool sidebandStreamChanged = false;
     if (mSidebandStreamChanged.compare_exchange_strong(sidebandStreamChanged, true)) {
         // mSidebandStreamChanged was changed to true
-        mFlinger->signalLayerUpdate();
+        mFlinger->onLayerUpdate();
     }
 }
 
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 4eeaba1..f0099c2 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -595,7 +595,7 @@
     setTransactionFlags(eTransactionNeeded);
     if (!mSidebandStreamChanged.exchange(true)) {
         // mSidebandStreamChanged was false
-        mFlinger->signalLayerUpdate();
+        mFlinger->onLayerUpdate();
     }
     return true;
 }
@@ -713,7 +713,7 @@
 
 void BufferStateLayer::setAutoRefresh(bool autoRefresh) {
     if (!mAutoRefresh.exchange(autoRefresh)) {
-        mFlinger->signalLayerUpdate();
+        mFlinger->onLayerUpdate();
     }
 }
 
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h
index 95d553d..93586ed 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h
@@ -85,8 +85,8 @@
     // to prevent an early presentation of a frame.
     std::shared_ptr<FenceTime> previousPresentFence;
 
-    // The predicted next invalidation time
-    std::optional<std::chrono::steady_clock::time_point> nextInvalidateTime;
+    // If set, a frame has been scheduled for that time.
+    std::optional<std::chrono::steady_clock::time_point> scheduledFrameTime;
 };
 
 } // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 048d7c2..fad1fa7 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -1314,7 +1314,7 @@
 
 void Output::renderCachedSets(const CompositionRefreshArgs& refreshArgs) {
     if (mPlanner) {
-        mPlanner->renderCachedSets(getState(), refreshArgs.nextInvalidateTime);
+        mPlanner->renderCachedSets(getState(), refreshArgs.scheduledFrameTime);
     }
 }
 
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 3397118..fd09ae4 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -466,9 +466,9 @@
     return false;
 }
 
-void DisplayDevice::onInvalidate() {
+void DisplayDevice::animateRefreshRateOverlay() {
     if (mRefreshRateOverlay) {
-        mRefreshRateOverlay->onInvalidate();
+        mRefreshRateOverlay->animate();
     }
 }
 
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 4a731bd..4b9718f 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -234,7 +234,7 @@
     void enableRefreshRateOverlay(bool enable, bool showSpinner);
     bool isRefreshRateOverlayEnabled() const { return mRefreshRateOverlay != nullptr; }
     bool onKernelTimerChanged(std::optional<DisplayModeId>, bool timerExpired);
-    void onInvalidate();
+    void animateRefreshRateOverlay();
 
     void onVsync(nsecs_t timestamp);
     nsecs_t getVsyncPeriodFromHWC() const;
diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp
index ec81e63..2502d66 100644
--- a/services/surfaceflinger/RefreshRateOverlay.cpp
+++ b/services/surfaceflinger/RefreshRateOverlay.cpp
@@ -284,7 +284,7 @@
     t.apply();
 }
 
-void RefreshRateOverlay::onInvalidate() {
+void RefreshRateOverlay::animate() {
     if (!mCurrentFps.has_value()) return;
 
     const auto& buffers = getOrCreateBuffers(*mCurrentFps);
diff --git a/services/surfaceflinger/RefreshRateOverlay.h b/services/surfaceflinger/RefreshRateOverlay.h
index 354510a..65d446c 100644
--- a/services/surfaceflinger/RefreshRateOverlay.h
+++ b/services/surfaceflinger/RefreshRateOverlay.h
@@ -46,7 +46,7 @@
     void setLayerStack(ui::LayerStack);
     void setViewport(ui::Size);
     void changeRefreshRate(const Fps&);
-    void onInvalidate();
+    void animate();
 
 private:
     class SevenSegmentDrawer {
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index aa2fec5..9465b19 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -150,7 +150,7 @@
     if (mSampleRequestTime.has_value()) {
         ATRACE_INT(lumaSamplingStepTag, static_cast<int>(samplingStep::waitForSamplePhase));
         mSampleRequestTime.reset();
-        mFlinger.scheduleRegionSamplingThread();
+        mFlinger.scheduleSample();
     }
 }
 
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.cpp b/services/surfaceflinger/Scheduler/MessageQueue.cpp
index 4d51125..043a536 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.cpp
+++ b/services/surfaceflinger/Scheduler/MessageQueue.cpp
@@ -27,49 +27,55 @@
 #include "EventThread.h"
 #include "FrameTimeline.h"
 #include "MessageQueue.h"
-#include "SurfaceFlinger.h"
 
 namespace android::impl {
 
-void MessageQueue::Handler::dispatchRefresh() {
-    if ((mEventMask.fetch_or(eventMaskRefresh) & eventMaskRefresh) == 0) {
-        mQueue.mLooper->sendMessage(this, Message(MessageQueue::REFRESH));
+void MessageQueue::Handler::dispatchComposite() {
+    if ((mEventMask.fetch_or(kComposite) & kComposite) == 0) {
+        mQueue.mLooper->sendMessage(this, Message(kComposite));
     }
 }
 
-void MessageQueue::Handler::dispatchInvalidate(int64_t vsyncId, nsecs_t expectedVSyncTimestamp) {
-    if ((mEventMask.fetch_or(eventMaskInvalidate) & eventMaskInvalidate) == 0) {
+void MessageQueue::Handler::dispatchCommit(int64_t vsyncId, nsecs_t expectedVsyncTime) {
+    if ((mEventMask.fetch_or(kCommit) & kCommit) == 0) {
         mVsyncId = vsyncId;
-        mExpectedVSyncTime = expectedVSyncTimestamp;
-        mQueue.mLooper->sendMessage(this, Message(MessageQueue::INVALIDATE));
+        mExpectedVsyncTime = expectedVsyncTime;
+        mQueue.mLooper->sendMessage(this, Message(kCommit));
     }
 }
 
-bool MessageQueue::Handler::invalidatePending() {
-    constexpr auto pendingMask = eventMaskInvalidate | eventMaskRefresh;
-    return (mEventMask.load() & pendingMask) != 0;
+bool MessageQueue::Handler::isFramePending() const {
+    constexpr auto kPendingMask = kCommit | kComposite;
+    return (mEventMask.load() & kPendingMask) != 0;
 }
 
 void MessageQueue::Handler::handleMessage(const Message& message) {
+    const nsecs_t frameTime = systemTime();
     switch (message.what) {
-        case INVALIDATE:
-            mEventMask.fetch_and(~eventMaskInvalidate);
-            mQueue.mFlinger->onMessageReceived(message.what, mVsyncId, mExpectedVSyncTime);
-            break;
-        case REFRESH:
-            mEventMask.fetch_and(~eventMaskRefresh);
-            mQueue.mFlinger->onMessageReceived(message.what, mVsyncId, mExpectedVSyncTime);
+        case kCommit:
+            mEventMask.fetch_and(~kCommit);
+            if (!mQueue.mCompositor.commit(frameTime, mVsyncId, mExpectedVsyncTime)) {
+                return;
+            }
+            // Composite immediately, rather than after pending tasks through scheduleComposite.
+            [[fallthrough]];
+        case kComposite:
+            mEventMask.fetch_and(~kComposite);
+            mQueue.mCompositor.composite(frameTime);
+            mQueue.mCompositor.sample();
             break;
     }
 }
 
-// ---------------------------------------------------------------------------
+MessageQueue::MessageQueue(ICompositor& compositor)
+      : MessageQueue(compositor, sp<Handler>::make(*this)) {}
 
-void MessageQueue::init(const sp<SurfaceFlinger>& flinger) {
-    mFlinger = flinger;
-    mLooper = new Looper(true);
-    mHandler = new Handler(*this);
-}
+constexpr bool kAllowNonCallbacks = true;
+
+MessageQueue::MessageQueue(ICompositor& compositor, sp<Handler> handler)
+      : mCompositor(compositor),
+        mLooper(sp<Looper>::make(kAllowNonCallbacks)),
+        mHandler(std::move(handler)) {}
 
 // TODO(b/169865816): refactor VSyncInjections to use MessageQueue directly
 // and remove the EventThread from MessageQueue
@@ -110,11 +116,13 @@
     {
         std::lock_guard lock(mVsync.mutex);
         mVsync.lastCallbackTime = std::chrono::nanoseconds(vsyncTime);
-        mVsync.scheduled = false;
+        mVsync.scheduledFrameTime.reset();
     }
-    mHandler->dispatchInvalidate(mVsync.tokenManager->generateTokenForPredictions(
-                                         {targetWakeupTime, readyTime, vsyncTime}),
-                                 vsyncTime);
+
+    const auto vsyncId = mVsync.tokenManager->generateTokenForPredictions(
+            {targetWakeupTime, readyTime, vsyncTime});
+
+    mHandler->dispatchCommit(vsyncId, vsyncTime);
 }
 
 void MessageQueue::initVsync(scheduler::VSyncDispatch& dispatch,
@@ -135,8 +143,8 @@
     ATRACE_CALL();
     std::lock_guard lock(mVsync.mutex);
     mVsync.workDuration = workDuration;
-    if (mVsync.scheduled) {
-        mVsync.expectedWakeupTime = mVsync.registration->schedule(
+    if (mVsync.scheduledFrameTime) {
+        mVsync.scheduledFrameTime = mVsync.registration->schedule(
                 {mVsync.workDuration.get().count(),
                  /*readyDuration=*/0, mVsync.lastCallbackTime.count()});
     }
@@ -168,7 +176,7 @@
     mLooper->sendMessage(handler, Message());
 }
 
-void MessageQueue::invalidate() {
+void MessageQueue::scheduleCommit() {
     ATRACE_CALL();
 
     {
@@ -181,15 +189,14 @@
     }
 
     std::lock_guard lock(mVsync.mutex);
-    mVsync.scheduled = true;
-    mVsync.expectedWakeupTime =
+    mVsync.scheduledFrameTime =
             mVsync.registration->schedule({.workDuration = mVsync.workDuration.get().count(),
                                            .readyDuration = 0,
                                            .earliestVsync = mVsync.lastCallbackTime.count()});
 }
 
-void MessageQueue::refresh() {
-    mHandler->dispatchRefresh();
+void MessageQueue::scheduleComposite() {
+    mHandler->dispatchComposite();
 }
 
 void MessageQueue::injectorCallback() {
@@ -198,24 +205,22 @@
     while ((n = DisplayEventReceiver::getEvents(&mInjector.tube, buffer, 8)) > 0) {
         for (int i = 0; i < n; i++) {
             if (buffer[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
-                mHandler->dispatchInvalidate(buffer[i].vsync.vsyncId,
-                                             buffer[i].vsync.expectedVSyncTimestamp);
+                mHandler->dispatchCommit(buffer[i].vsync.vsyncId,
+                                         buffer[i].vsync.expectedVSyncTimestamp);
                 break;
             }
         }
     }
 }
 
-std::optional<std::chrono::steady_clock::time_point> MessageQueue::nextExpectedInvalidate() {
-    if (mHandler->invalidatePending()) {
-        return std::chrono::steady_clock::now();
+auto MessageQueue::getScheduledFrameTime() const -> std::optional<Clock::time_point> {
+    if (mHandler->isFramePending()) {
+        return Clock::now();
     }
 
     std::lock_guard lock(mVsync.mutex);
-    if (mVsync.scheduled) {
-        LOG_ALWAYS_FATAL_IF(!mVsync.expectedWakeupTime.has_value(), "callback was never scheduled");
-        const auto expectedWakeupTime = std::chrono::nanoseconds(*mVsync.expectedWakeupTime);
-        return std::optional<std::chrono::steady_clock::time_point>(expectedWakeupTime);
+    if (const auto time = mVsync.scheduledFrameTime) {
+        return Clock::time_point(std::chrono::nanoseconds(*time));
     }
 
     return std::nullopt;
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.h b/services/surfaceflinger/Scheduler/MessageQueue.h
index 58ce9b9..2c908a6 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.h
+++ b/services/surfaceflinger/Scheduler/MessageQueue.h
@@ -33,7 +33,14 @@
 
 namespace android {
 
-class SurfaceFlinger;
+struct ICompositor {
+    virtual bool commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expectedVsyncTime) = 0;
+    virtual void composite(nsecs_t frameTime) = 0;
+    virtual void sample() = 0;
+
+protected:
+    ~ICompositor() = default;
+};
 
 template <typename F>
 class Task : public MessageHandler {
@@ -56,65 +63,65 @@
 
 class MessageQueue {
 public:
-    enum {
-        INVALIDATE = 0,
-        REFRESH = 1,
-    };
-
     virtual ~MessageQueue() = default;
 
-    virtual void init(const sp<SurfaceFlinger>& flinger) = 0;
     virtual void initVsync(scheduler::VSyncDispatch&, frametimeline::TokenManager&,
                            std::chrono::nanoseconds workDuration) = 0;
     virtual void setDuration(std::chrono::nanoseconds workDuration) = 0;
     virtual void setInjector(sp<EventThreadConnection>) = 0;
     virtual void waitMessage() = 0;
     virtual void postMessage(sp<MessageHandler>&&) = 0;
-    virtual void invalidate() = 0;
-    virtual void refresh() = 0;
-    virtual std::optional<std::chrono::steady_clock::time_point> nextExpectedInvalidate() = 0;
-};
+    virtual void scheduleCommit() = 0;
+    virtual void scheduleComposite() = 0;
 
-// ---------------------------------------------------------------------------
+    using Clock = std::chrono::steady_clock;
+    virtual std::optional<Clock::time_point> getScheduledFrameTime() const = 0;
+};
 
 namespace impl {
 
 class MessageQueue : public android::MessageQueue {
 protected:
     class Handler : public MessageHandler {
-        enum : uint32_t {
-            eventMaskInvalidate = 0x1,
-            eventMaskRefresh = 0x2,
-            eventMaskTransaction = 0x4
-        };
+        static constexpr uint32_t kCommit = 0b1;
+        static constexpr uint32_t kComposite = 0b10;
+
         MessageQueue& mQueue;
-        std::atomic<uint32_t> mEventMask;
-        std::atomic<int64_t> mVsyncId;
-        std::atomic<nsecs_t> mExpectedVSyncTime;
+        std::atomic<uint32_t> mEventMask = 0;
+        std::atomic<int64_t> mVsyncId = 0;
+        std::atomic<nsecs_t> mExpectedVsyncTime = 0;
 
     public:
-        explicit Handler(MessageQueue& queue) : mQueue(queue), mEventMask(0) {}
+        explicit Handler(MessageQueue& queue) : mQueue(queue) {}
         void handleMessage(const Message& message) override;
-        virtual void dispatchRefresh();
-        virtual void dispatchInvalidate(int64_t vsyncId, nsecs_t expectedVSyncTimestamp);
-        virtual bool invalidatePending();
+
+        bool isFramePending() const;
+
+        virtual void dispatchCommit(int64_t vsyncId, nsecs_t expectedVsyncTime);
+        void dispatchComposite();
     };
 
     friend class Handler;
 
-    sp<SurfaceFlinger> mFlinger;
-    sp<Looper> mLooper;
+    // For tests.
+    MessageQueue(ICompositor&, sp<Handler>);
+
+    void vsyncCallback(nsecs_t vsyncTime, nsecs_t targetWakeupTime, nsecs_t readyTime);
+
+private:
+    ICompositor& mCompositor;
+    const sp<Looper> mLooper;
+    const sp<Handler> mHandler;
 
     struct Vsync {
         frametimeline::TokenManager* tokenManager = nullptr;
         std::unique_ptr<scheduler::VSyncCallbackRegistration> registration;
 
-        std::mutex mutex;
+        mutable std::mutex mutex;
         TracedOrdinal<std::chrono::nanoseconds> workDuration
                 GUARDED_BY(mutex) = {"VsyncWorkDuration-sf", std::chrono::nanoseconds(0)};
         std::chrono::nanoseconds lastCallbackTime GUARDED_BY(mutex) = std::chrono::nanoseconds{0};
-        bool scheduled GUARDED_BY(mutex) = false;
-        std::optional<nsecs_t> expectedWakeupTime GUARDED_BY(mutex);
+        std::optional<nsecs_t> scheduledFrameTime GUARDED_BY(mutex);
         TracedOrdinal<int> value = {"VSYNC-sf", 0};
     };
 
@@ -127,14 +134,11 @@
     Vsync mVsync;
     Injector mInjector;
 
-    sp<Handler> mHandler;
-
-    void vsyncCallback(nsecs_t vsyncTime, nsecs_t targetWakeupTime, nsecs_t readyTime);
     void injectorCallback();
 
 public:
-    ~MessageQueue() override = default;
-    void init(const sp<SurfaceFlinger>& flinger) override;
+    explicit MessageQueue(ICompositor&);
+
     void initVsync(scheduler::VSyncDispatch&, frametimeline::TokenManager&,
                    std::chrono::nanoseconds workDuration) override;
     void setDuration(std::chrono::nanoseconds workDuration) override;
@@ -143,13 +147,10 @@
     void waitMessage() override;
     void postMessage(sp<MessageHandler>&&) override;
 
-    // sends INVALIDATE message at next VSYNC
-    void invalidate() override;
+    void scheduleCommit() override;
+    void scheduleComposite() override;
 
-    // sends REFRESH message at next VSYNC
-    void refresh() override;
-
-    std::optional<std::chrono::steady_clock::time_point> nextExpectedInvalidate() override;
+    std::optional<Clock::time_point> getScheduledFrameTime() const override;
 };
 
 } // namespace impl
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 12e741b..c6a19de 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -870,7 +870,7 @@
 
 void Scheduler::onNewVsyncPeriodChangeTimeline(const hal::VsyncPeriodChangeTimeline& timeline) {
     if (timeline.refreshRequired) {
-        mSchedulerCallback.scheduleRefresh(FrameHint::kNone);
+        mSchedulerCallback.scheduleComposite(FrameHint::kNone);
     }
 
     std::lock_guard<std::mutex> lock(mVsyncTimelineLock);
@@ -882,12 +882,12 @@
     }
 }
 
-void Scheduler::onDisplayRefreshed(nsecs_t timestamp) {
-    const bool refresh = [=] {
+void Scheduler::onPostComposition(nsecs_t presentTime) {
+    const bool recomposite = [=] {
         std::lock_guard<std::mutex> lock(mVsyncTimelineLock);
         if (mLastVsyncPeriodChangeTimeline && mLastVsyncPeriodChangeTimeline->refreshRequired) {
-            if (timestamp < mLastVsyncPeriodChangeTimeline->refreshTimeNanos) {
-                // We need to schedule another refresh as refreshTimeNanos is still in the future.
+            if (presentTime < mLastVsyncPeriodChangeTimeline->refreshTimeNanos) {
+                // We need to composite again as refreshTimeNanos is still in the future.
                 return true;
             }
 
@@ -896,8 +896,8 @@
         return false;
     }();
 
-    if (refresh) {
-        mSchedulerCallback.scheduleRefresh(FrameHint::kNone);
+    if (recomposite) {
+        mSchedulerCallback.scheduleComposite(FrameHint::kNone);
     }
 }
 
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 3f3debe..0a33dbb 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -59,7 +59,7 @@
     // Indicates frame activity, i.e. whether commit and/or composite is taking place.
     enum class FrameHint { kNone, kActive };
 
-    virtual void scheduleRefresh(FrameHint) = 0;
+    virtual void scheduleComposite(FrameHint) = 0;
     virtual void setVsyncEnabled(bool) = 0;
     virtual void changeRefreshRate(const scheduler::RefreshRateConfigs::RefreshRate&,
                                    scheduler::RefreshRateConfigEvent) = 0;
@@ -162,8 +162,8 @@
     // Notifies the scheduler about a refresh rate timeline change.
     void onNewVsyncPeriodChangeTimeline(const hal::VsyncPeriodChangeTimeline& timeline);
 
-    // Notifies the scheduler when the display was refreshed
-    void onDisplayRefreshed(nsecs_t timestamp);
+    // Notifies the scheduler post composition.
+    void onPostComposition(nsecs_t presentTime);
 
     // Notifies the scheduler when the display size has changed. Called from SF's main thread
     void onActiveDisplayAreaChanged(uint32_t displayArea);
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index e90af3a..bb65bae 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -371,7 +371,7 @@
         mTimeStats(std::make_shared<impl::TimeStats>()),
         mFrameTracer(mFactory.createFrameTracer()),
         mFrameTimeline(mFactory.createFrameTimeline(mTimeStats, getpid())),
-        mEventQueue(mFactory.createMessageQueue()),
+        mEventQueue(mFactory.createMessageQueue(*this)),
         mCompositionEngine(mFactory.createCompositionEngine()),
         mHwcServiceName(base::GetProperty("debug.sf.hwc_service_name"s, "default"s)),
         mTunnelModeEnabledReporter(new TunnelModeEnabledReporter()),
@@ -506,10 +506,6 @@
 
 SurfaceFlinger::~SurfaceFlinger() = default;
 
-void SurfaceFlinger::onFirstRef() {
-    mEventQueue->init(this);
-}
-
 void SurfaceFlinger::binderDied(const wp<IBinder>&) {
     // the window manager died on us. prepare its eulogy.
     mBootFinished = false;
@@ -1104,7 +1100,7 @@
     }
 
     if (display->setDesiredActiveMode(info)) {
-        scheduleRefresh(FrameHint::kNone);
+        scheduleComposite(FrameHint::kNone);
 
         // Start receiving vsync samples now, so that we can detect a period
         // switch.
@@ -1704,31 +1700,26 @@
     return mScheduler->createDisplayEventConnection(handle, eventRegistration);
 }
 
-void SurfaceFlinger::scheduleInvalidate(FrameHint hint) {
+void SurfaceFlinger::scheduleCommit(FrameHint hint) {
     if (hint == FrameHint::kActive) {
         mScheduler->resetIdleTimer();
     }
     mPowerAdvisor.notifyDisplayUpdateImminent();
-    mEventQueue->invalidate();
+    mEventQueue->scheduleCommit();
 }
 
-void SurfaceFlinger::scheduleRefresh(FrameHint hint) {
-    mForceRefresh = true;
-    scheduleInvalidate(hint);
+void SurfaceFlinger::scheduleComposite(FrameHint hint) {
+    mMustComposite = true;
+    scheduleCommit(hint);
 }
 
 void SurfaceFlinger::scheduleRepaint() {
     mGeometryDirty = true;
-    scheduleRefresh(FrameHint::kActive);
+    scheduleComposite(FrameHint::kActive);
 }
 
-void SurfaceFlinger::signalLayerUpdate() {
-    scheduleInvalidate(FrameHint::kActive);
-}
-
-void SurfaceFlinger::signalRefresh() {
-    mRefreshPending = true;
-    mEventQueue->refresh();
+void SurfaceFlinger::scheduleSample() {
+    static_cast<void>(schedule([this] { sample(); }));
 }
 
 nsecs_t SurfaceFlinger::getVsyncPeriodFromHWC() const {
@@ -1834,7 +1825,7 @@
 
 void SurfaceFlinger::onComposerHalRefresh(hal::HWDisplayId) {
     Mutex::Autolock lock(mStateLock);
-    scheduleRefresh(FrameHint::kNone);
+    scheduleComposite(FrameHint::kNone);
 }
 
 void SurfaceFlinger::setVsyncEnabled(bool enabled) {
@@ -1889,40 +1880,26 @@
                                                           : stats.vsyncTime + stats.vsyncPeriod;
 }
 
-void SurfaceFlinger::onMessageReceived(int32_t what, int64_t vsyncId, nsecs_t expectedVSyncTime) {
-    switch (what) {
-        case MessageQueue::INVALIDATE: {
-            onMessageInvalidate(vsyncId, expectedVSyncTime);
-            break;
-        }
-        case MessageQueue::REFRESH: {
-            onMessageRefresh();
-            break;
-        }
-    }
-}
-
-void SurfaceFlinger::onMessageInvalidate(int64_t vsyncId, nsecs_t expectedVSyncTime) {
-    const nsecs_t frameStart = systemTime();
+bool SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expectedVsyncTime) {
     // calculate the expected present time once and use the cached
     // value throughout this frame to make sure all layers are
     // seeing this same value.
-    if (expectedVSyncTime >= frameStart) {
-        mExpectedPresentTime = expectedVSyncTime;
+    if (expectedVsyncTime >= frameTime) {
+        mExpectedPresentTime = expectedVsyncTime;
     } else {
-        const DisplayStatInfo stats = mScheduler->getDisplayStatInfo(frameStart);
+        const DisplayStatInfo stats = mScheduler->getDisplayStatInfo(frameTime);
         mExpectedPresentTime = calculateExpectedPresentTime(stats);
     }
 
     const nsecs_t lastScheduledPresentTime = mScheduledPresentTime;
-    mScheduledPresentTime = expectedVSyncTime;
+    mScheduledPresentTime = expectedVsyncTime;
 
     const auto vsyncIn = [&] {
         if (!ATRACE_ENABLED()) return 0.f;
         return (mExpectedPresentTime - systemTime()) / 1e6f;
     }();
-    ATRACE_FORMAT("onMessageInvalidate %" PRId64 " vsyncIn %.2fms%s", vsyncId, vsyncIn,
-                  mExpectedPresentTime == expectedVSyncTime ? "" : " (adjusted)");
+    ATRACE_FORMAT("%s %" PRId64 " vsyncIn %.2fms%s", __func__, vsyncId, vsyncIn,
+                  mExpectedPresentTime == expectedVsyncTime ? "" : " (adjusted)");
 
     // When Backpressure propagation is enabled we want to give a small grace period
     // for the present fence to fire instead of just giving up on this frame to handle cases
@@ -1969,11 +1946,11 @@
     }
 
     // If we are in the middle of a mode change and the fence hasn't
-    // fired yet just wait for the next invalidate
+    // fired yet just wait for the next commit.
     if (mSetActiveModePending) {
         if (framePending) {
-            mEventQueue->invalidate();
-            return;
+            mEventQueue->scheduleCommit();
+            return false;
         }
 
         // We received the present fence from the HWC, so we assume it successfully updated
@@ -1984,8 +1961,8 @@
 
     if (framePending) {
         if ((hwcFrameMissed && !gpuFrameMissed) || mPropagateBackpressureClientComposition) {
-            signalLayerUpdate();
-            return;
+            scheduleCommit(FrameHint::kNone);
+            return false;
         }
     }
 
@@ -1997,11 +1974,12 @@
     if (mRefreshRateOverlaySpinner) {
         Mutex::Autolock lock(mStateLock);
         if (const auto display = getDefaultDisplayDeviceLocked()) {
-            display->onInvalidate();
+            display->animateRefreshRateOverlay();
         }
     }
 
-    bool refreshNeeded = mForceRefresh.exchange(false);
+    // Composite if transactions were committed, or if requested by HWC.
+    bool mustComposite = mMustComposite.exchange(false);
     {
         mTracePostComposition = mTracing.flagIsSet(SurfaceTracing::TRACE_COMPOSITION) ||
                 mTracing.flagIsSet(SurfaceTracing::TRACE_SYNC) ||
@@ -2009,10 +1987,12 @@
         const bool tracePreComposition = mTracingEnabled && !mTracePostComposition;
         ConditionalLockGuard<std::mutex> lock(mTracingLock, tracePreComposition);
 
-        mFrameTimeline->setSfWakeUp(vsyncId, frameStart, Fps::fromPeriodNsecs(stats.vsyncPeriod));
+        mFrameTimeline->setSfWakeUp(vsyncId, frameTime, Fps::fromPeriodNsecs(stats.vsyncPeriod));
 
-        refreshNeeded |= flushAndCommitTransactions();
-        refreshNeeded |= handleMessageInvalidate();
+        mustComposite |= flushAndCommitTransactions();
+        mustComposite |= latchBuffers();
+
+        updateLayerGeometry();
 
         if (tracePreComposition) {
             if (mVisibleRegionsDirty) {
@@ -2035,25 +2015,7 @@
     updateCursorAsync();
     updateInputFlinger();
 
-    if (refreshNeeded && CC_LIKELY(mBootStage != BootStage::BOOTLOADER)) {
-        // Signal a refresh if a transaction modified the window state,
-        // a new buffer was latched, or if HWC has requested a full
-        // repaint
-        if (mFrameStartTime <= 0) {
-            // We should only use the time of the first invalidate
-            // message that signals a refresh as the beginning of the
-            // frame. Otherwise the real frame time will be
-            // underestimated.
-            mFrameStartTime = frameStart;
-        }
-
-        // Run the refresh immediately after invalidate as there is no point going thru the message
-        // queue again, and to ensure that we actually refresh the screen instead of handling
-        // other messages that were queued us already in the MessageQueue.
-        mRefreshPending = true;
-        onMessageRefresh();
-    }
-    notifyRegionSamplingThread();
+    return mustComposite && CC_LIKELY(mBootStage != BootStage::BOOTLOADER);
 }
 
 bool SurfaceFlinger::flushAndCommitTransactions() {
@@ -2068,6 +2030,9 @@
         commitTransactions();
     }
 
+    // Invoke OnCommit callbacks.
+    mTransactionCallbackInvoker.sendCallbacks();
+
     if (transactionFlushNeeded()) {
         setTransactionFlags(eTransactionFlushNeeded);
     }
@@ -2075,11 +2040,9 @@
     return shouldCommit;
 }
 
-void SurfaceFlinger::onMessageRefresh() {
+void SurfaceFlinger::composite(nsecs_t frameTime) {
     ATRACE_CALL();
 
-    mRefreshPending = false;
-
     compositionengine::CompositionRefreshArgs refreshArgs;
     const auto& displays = ON_MAIN_THREAD(mDisplays);
     refreshArgs.outputs.reserve(displays.size());
@@ -2123,18 +2086,16 @@
     const auto hwcMinWorkDuration = mVsyncConfiguration->getCurrentConfigs().hwcMinWorkDuration;
     refreshArgs.earliestPresentTime = prevVsyncTime - hwcMinWorkDuration;
     refreshArgs.previousPresentFence = mPreviousPresentFences[0].fenceTime;
-    refreshArgs.nextInvalidateTime = mEventQueue->nextExpectedInvalidate();
+    refreshArgs.scheduledFrameTime = mEventQueue->getScheduledFrameTime();
 
     // Store the present time just before calling to the composition engine so we could notify
     // the scheduler.
     const auto presentTime = systemTime();
 
     mCompositionEngine->present(refreshArgs);
-    mTimeStats->recordFrameDuration(mFrameStartTime, systemTime());
-    // Reset the frame start time now that we've recorded this frame.
-    mFrameStartTime = 0;
+    mTimeStats->recordFrameDuration(frameTime, systemTime());
 
-    mScheduler->onDisplayRefreshed(presentTime);
+    mScheduler->onPostComposition(presentTime);
 
     postFrame();
     postComposition();
@@ -2177,17 +2138,12 @@
     mVisibleRegionsDirty = false;
 
     if (mCompositionEngine->needsAnotherUpdate()) {
-        signalLayerUpdate();
+        scheduleCommit(FrameHint::kNone);
     }
 }
 
-bool SurfaceFlinger::handleMessageInvalidate() {
+void SurfaceFlinger::updateLayerGeometry() {
     ATRACE_CALL();
-        // Send on commit callbacks
-    mTransactionCallbackInvoker.sendCallbacks();
-
-    bool refreshNeeded = handlePageFlip();
-
 
     if (mVisibleRegionsDirty) {
         computeLayerBounds();
@@ -2199,7 +2155,6 @@
         invalidateLayerStack(layer, visibleReg);
     }
     mLayersPendingRefresh.clear();
-    return refreshNeeded;
 }
 
 void SurfaceFlinger::updateCompositorTiming(const DisplayStatInfo& stats, nsecs_t compositeTime,
@@ -3301,11 +3256,10 @@
     }
 }
 
-bool SurfaceFlinger::handlePageFlip() {
+bool SurfaceFlinger::latchBuffers() {
     ATRACE_CALL();
-    ALOGV("handlePageFlip");
 
-    nsecs_t latchTime = systemTime();
+    const nsecs_t latchTime = systemTime();
 
     bool visibleRegions = false;
     bool frameQueued = false;
@@ -3374,7 +3328,7 @@
     // queued frame that shouldn't be displayed during this vsync period, wake
     // up during the next vsync period to check again.
     if (frameQueued && (mLayersWithQueuedFrames.empty() || !newDataLatched)) {
-        signalLayerUpdate();
+        scheduleCommit(FrameHint::kNone);
     }
 
     // enter boot animation on first buffer latch
@@ -3453,7 +3407,7 @@
                                              const sp<IBinder>& applyToken) {
     const uint32_t old = mTransactionFlags.fetch_or(mask);
     modulateVsync(&VsyncModulator::setTransactionSchedule, schedule, applyToken);
-    if ((old & mask) == 0) scheduleInvalidate(FrameHint::kActive);
+    if ((old & mask) == 0) scheduleCommit(FrameHint::kActive);
     return old;
 }
 
@@ -4572,7 +4526,7 @@
 
         mVisibleRegionsDirty = true;
         mHasPoweredOff = true;
-        scheduleRefresh(FrameHint::kActive);
+        scheduleComposite(FrameHint::kActive);
     } else if (mode == hal::PowerMode::OFF) {
         // Turn off the display
         if (SurfaceFlinger::setSchedFifo(false) != NO_ERROR) {
@@ -5430,8 +5384,8 @@
                 }
                 scheduleRepaint();
                 return NO_ERROR;
-            case 1004: // Force refresh ahead of next VSYNC.
-                scheduleRefresh(FrameHint::kActive);
+            case 1004: // Force composite ahead of next VSYNC.
+                scheduleComposite(FrameHint::kActive);
                 return NO_ERROR;
             case 1005: { // Force commit ahead of next VSYNC.
                 Mutex::Autolock lock(mStateLock);
@@ -5439,8 +5393,8 @@
                                     eTraversalNeeded);
                 return NO_ERROR;
             }
-            case 1006: // Force refresh immediately.
-                signalRefresh();
+            case 1006: // Force composite immediately.
+                mEventQueue->scheduleComposite();
                 return NO_ERROR;
             case 1007: // Unused.
                 return NAME_NOT_FOUND;
@@ -5834,7 +5788,7 @@
         const bool timerExpired = mKernelIdleTimerEnabled && expired;
 
         if (display->onKernelTimerChanged(desiredModeId, timerExpired)) {
-            mEventQueue->invalidate();
+            mEventQueue->scheduleCommit();
         }
     }));
 }
@@ -6265,12 +6219,6 @@
     bool canCaptureBlackoutContent = hasCaptureBlackoutContentPermission();
 
     static_cast<void>(schedule([=, renderAreaFuture = std::move(renderAreaFuture)]() mutable {
-        if (mRefreshPending) {
-            ALOGW("Skipping screenshot for now");
-            captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer, regionSampling,
-                                grayscale, captureListener);
-            return;
-        }
         ScreenCaptureResults captureResults;
         std::unique_ptr<RenderArea> renderArea = renderAreaFuture.get();
         if (!renderArea) {
@@ -6617,6 +6565,10 @@
     }
 }
 
+void SurfaceFlinger::onLayerUpdate() {
+    scheduleCommit(FrameHint::kActive);
+}
+
 // WARNING: ONLY CALL THIS FROM LAYER DTOR
 // Here we add children in the current state to offscreen layers and remove the
 // layer itself from the offscreen layer list.  Since
@@ -6941,16 +6893,12 @@
     return layer;
 }
 
-void SurfaceFlinger::scheduleRegionSamplingThread() {
-    static_cast<void>(schedule([&] { notifyRegionSamplingThread(); }));
-}
-
-void SurfaceFlinger::notifyRegionSamplingThread() {
+void SurfaceFlinger::sample() {
     if (!mLumaSampling || !mRegionSamplingThread) {
         return;
     }
 
-    mRegionSamplingThread->onCompositionComplete(mEventQueue->nextExpectedInvalidate());
+    mRegionSamplingThread->onCompositionComplete(mEventQueue->getScheduledFrameTime());
 }
 
 void SurfaceFlinger::onActiveDisplaySizeChanged(const sp<DisplayDevice>& activeDisplay) {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 1217d63..43f7b36 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -57,6 +57,7 @@
 #include "Fps.h"
 #include "FrameTracker.h"
 #include "LayerVector.h"
+#include "Scheduler/MessageQueue.h"
 #include "Scheduler/RefreshRateConfigs.h"
 #include "Scheduler/RefreshRateStats.h"
 #include "Scheduler/Scheduler.h"
@@ -177,6 +178,7 @@
                        public PriorityDumper,
                        private IBinder::DeathRecipient,
                        private HWC2::ComposerCallback,
+                       private ICompositor,
                        private ISchedulerCallback {
 public:
     struct SkipInitializationTag {};
@@ -287,11 +289,13 @@
     [[nodiscard]] std::future<T> schedule(F&&);
 
     // Schedule commit of transactions on the main thread ahead of the next VSYNC.
-    void scheduleInvalidate(FrameHint);
-    // As above, but also force refresh regardless if transactions were committed.
-    void scheduleRefresh(FrameHint) override;
+    void scheduleCommit(FrameHint);
+    // As above, but also force composite regardless if transactions were committed.
+    void scheduleComposite(FrameHint) override;
     // As above, but also force dirty geometry to repaint.
     void scheduleRepaint();
+    // Schedule sampling independently from commit or composite.
+    void scheduleSample();
 
     surfaceflinger::Factory& getFactory() { return mFactory; }
 
@@ -305,11 +309,6 @@
     // utility function to delete a texture on the main thread
     void deleteTextureAsync(uint32_t texture);
 
-    // called on the main thread by MessageQueue when an internal message
-    // is received
-    // TODO: this should be made accessible only to MessageQueue
-    void onMessageReceived(int32_t what, int64_t vsyncId, nsecs_t expectedVSyncTime);
-
     renderengine::RenderEngine& getRenderEngine() const;
 
     bool authenticateSurfaceTextureLocked(
@@ -317,6 +316,7 @@
 
     void onLayerFirstRef(Layer*);
     void onLayerDestroyed(Layer*);
+    void onLayerUpdate();
 
     void removeHierarchyFromOffscreenLayers(Layer* layer);
     void removeFromOffscreenLayers(Layer* layer);
@@ -734,9 +734,6 @@
     // Implements IBinder::DeathRecipient.
     void binderDied(const wp<IBinder>& who) override;
 
-    // Implements RefBase.
-    void onFirstRef() override;
-
     // HWC2::ComposerCallback overrides:
     void onComposerHalVsync(hal::HWDisplayId, int64_t timestamp,
                             std::optional<hal::VsyncPeriodNanos>) override;
@@ -746,6 +743,19 @@
                                                const hal::VsyncPeriodChangeTimeline&) override;
     void onComposerHalSeamlessPossible(hal::HWDisplayId) override;
 
+    // ICompositor overrides:
+
+    // Commits transactions for layers and displays. Returns whether any state has been invalidated,
+    // i.e. whether a frame should be composited for each display.
+    bool commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expectedVsyncTime) override;
+
+    // Composites a frame for each display. CompositionEngine performs GPU and/or HAL composition
+    // via RenderEngine and the Composer HAL, respectively.
+    void composite(nsecs_t frameTime) override;
+
+    // Samples the composited frame via RegionSamplingThread.
+    void sample() override;
+
     /*
      * ISchedulerCallback
      */
@@ -766,13 +776,6 @@
     // Show spinner with refresh rate overlay
     bool mRefreshRateOverlaySpinner = false;
 
-    /*
-     * Message handling
-     */
-    // Can only be called from the main thread or with mStateLock held
-    void signalLayerUpdate();
-    void signalRefresh();
-
     // Called on the main thread in response to initializeDisplays()
     void onInitializeDisplays() REQUIRES(mStateLock);
     // Sets the desired active mode bit. It obtains the lock, and sets mDesiredActiveMode.
@@ -797,10 +800,6 @@
             const std::optional<scheduler::RefreshRateConfigs::Policy>& policy, bool overridePolicy)
             EXCLUDES(mStateLock);
 
-    // Handle the INVALIDATE message queue event, latching new buffers and applying
-    // incoming transactions
-    void onMessageInvalidate(int64_t vsyncId, nsecs_t expectedVSyncTime);
-
     // Returns whether transactions were committed.
     bool flushAndCommitTransactions() EXCLUDES(mStateLock);
 
@@ -808,12 +807,10 @@
     void commitTransactionsLocked(uint32_t transactionFlags) REQUIRES(mStateLock);
     void doCommitTransactions() REQUIRES(mStateLock);
 
-    // Handle the REFRESH message queue event, sending the current frame down to RenderEngine and
-    // the Composer HAL for presentation
-    void onMessageRefresh();
+    // Returns whether a new buffer has been latched.
+    bool latchBuffers();
 
-    // Returns whether a new buffer has been latched (see handlePageFlip())
-    bool handleMessageInvalidate();
+    void updateLayerGeometry();
 
     void updateInputFlinger();
     void notifyWindowInfos();
@@ -824,11 +821,6 @@
     void updatePhaseConfiguration(const Fps&) REQUIRES(mStateLock);
     void setVsyncConfig(const VsyncModulator::VsyncConfig&, nsecs_t vsyncPeriod);
 
-    /* handlePageFlip - latch a new buffer if available and compute the dirty
-     * region. Returns whether a new buffer has been latched, i.e., whether it
-     * is necessary to perform a refresh during this vsync.
-     */
-    bool handlePageFlip();
 
     /*
      * Transactions
@@ -1250,7 +1242,7 @@
     bool mLayersRemoved = false;
     bool mLayersAdded = false;
 
-    std::atomic_bool mForceRefresh = false;
+    std::atomic_bool mMustComposite = false;
     std::atomic_bool mGeometryDirty = false;
 
     // constant members (no synchronization needed for access)
@@ -1350,10 +1342,6 @@
     mutable Mutex mDestroyedLayerLock;
     Vector<Layer const *> mDestroyedLayers;
 
-    nsecs_t mRefreshStartTime = 0;
-
-    std::atomic<bool> mRefreshPending = false;
-
     // We maintain a pool of pre-generated texture names to hand out to avoid
     // layer creation needing to run on the main thread (which it would
     // otherwise need to do to access RenderEngine).
@@ -1446,9 +1434,6 @@
 
     Hwc2::impl::PowerAdvisor mPowerAdvisor;
 
-    // This should only be accessed on the main thread.
-    nsecs_t mFrameStartTime = 0;
-
     void enableRefreshRateOverlay(bool enable) REQUIRES(mStateLock);
 
     // Flag used to set override desired display mode from backdoor
@@ -1502,9 +1487,6 @@
 
     std::atomic<ui::Transform::RotationFlags> mActiveDisplayTransformHint;
 
-    void scheduleRegionSamplingThread();
-    void notifyRegionSamplingThread();
-
     bool isRefreshRateOverlayEnabled() const REQUIRES(mStateLock) {
         return std::any_of(mDisplays.begin(), mDisplays.end(),
                            [](std::pair<wp<IBinder>, sp<DisplayDevice>> display) {
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
index 89d1c4d..9a2f910 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
@@ -51,8 +51,8 @@
     return std::make_unique<android::impl::HWComposer>(serviceName);
 }
 
-std::unique_ptr<MessageQueue> DefaultFactory::createMessageQueue() {
-    return std::make_unique<android::impl::MessageQueue>();
+std::unique_ptr<MessageQueue> DefaultFactory::createMessageQueue(ICompositor& compositor) {
+    return std::make_unique<android::impl::MessageQueue>(compositor);
 }
 
 std::unique_ptr<scheduler::VsyncConfiguration> DefaultFactory::createVsyncConfiguration(
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
index b8bf2ba..2be09ee 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
@@ -27,7 +27,7 @@
     virtual ~DefaultFactory();
 
     std::unique_ptr<HWComposer> createHWComposer(const std::string& serviceName) override;
-    std::unique_ptr<MessageQueue> createMessageQueue() override;
+    std::unique_ptr<MessageQueue> createMessageQueue(ICompositor&) override;
     std::unique_ptr<scheduler::VsyncConfiguration> createVsyncConfiguration(
             Fps currentRefreshRate) override;
     std::unique_ptr<Scheduler> createScheduler(
diff --git a/services/surfaceflinger/SurfaceFlingerFactory.h b/services/surfaceflinger/SurfaceFlingerFactory.h
index 13c95dd..bca533b 100644
--- a/services/surfaceflinger/SurfaceFlingerFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerFactory.h
@@ -31,11 +31,11 @@
 typedef int32_t PixelFormat;
 
 class BufferQueueLayer;
-class BufferStateLayer;
 class BufferLayerConsumer;
-class EffectLayer;
+class BufferStateLayer;
 class ContainerLayer;
 class DisplayDevice;
+class EffectLayer;
 class FrameTracer;
 class GraphicBuffer;
 class HWComposer;
@@ -50,6 +50,7 @@
 class TimeStats;
 
 struct DisplayDeviceCreationArgs;
+struct ICompositor;
 struct ISchedulerCallback;
 struct LayerCreationArgs;
 
@@ -76,7 +77,7 @@
 class Factory {
 public:
     virtual std::unique_ptr<HWComposer> createHWComposer(const std::string& serviceName) = 0;
-    virtual std::unique_ptr<MessageQueue> createMessageQueue() = 0;
+    virtual std::unique_ptr<MessageQueue> createMessageQueue(ICompositor&) = 0;
     virtual std::unique_ptr<scheduler::VsyncConfiguration> createVsyncConfiguration(
             Fps currentRefreshRate) = 0;
     virtual std::unique_ptr<Scheduler> createScheduler(
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 5135ff9..a081291 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -202,8 +202,7 @@
     // --------------------------------------------------------------------
     // Invocation
 
-    mFlinger.onMessageReceived(MessageQueue::INVALIDATE);
-    mFlinger.onMessageReceived(MessageQueue::REFRESH);
+    mFlinger.commitAndComposite();
 
     LayerCase::cleanup(this);
 }
@@ -215,8 +214,7 @@
     // --------------------------------------------------------------------
     // Invocation
 
-    mFlinger.onMessageReceived(MessageQueue::INVALIDATE);
-    mFlinger.onMessageReceived(MessageQueue::REFRESH);
+    mFlinger.commitAndComposite();
 
     LayerCase::cleanup(this);
 }
@@ -537,7 +535,7 @@
         ASSERT_EQ(NO_ERROR, err);
         Mock::VerifyAndClear(test->mRenderEngine);
 
-        EXPECT_CALL(*test->mMessageQueue, invalidate()).Times(1);
+        EXPECT_CALL(*test->mMessageQueue, scheduleCommit()).Times(1);
         enqueueBuffer(test, layer);
         Mock::VerifyAndClearExpectations(test->mMessageQueue);
 
@@ -883,7 +881,7 @@
         test->mFlinger.mutableDrawingState().layersSortedByZ.clear();
 
         // Layer should be unregistered with scheduler.
-        test->mFlinger.onMessageReceived(MessageQueue::INVALIDATE);
+        test->mFlinger.commit();
         EXPECT_EQ(0, test->mFlinger.scheduler()->layerHistorySize());
     }
 };
diff --git a/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp
index dbd51fe..17d1dd6 100644
--- a/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp
+++ b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp
@@ -31,62 +31,51 @@
 
 using CallbackToken = scheduler::VSyncDispatch::CallbackToken;
 
+struct NoOpCompositor final : ICompositor {
+    bool commit(nsecs_t, int64_t, nsecs_t) override { return false; }
+    void composite(nsecs_t) override {}
+    void sample() override {}
+} gNoOpCompositor;
+
 class TestableMessageQueue : public impl::MessageQueue {
-public:
-    class MockHandler : public MessageQueue::Handler {
-    public:
-        explicit MockHandler(MessageQueue& queue) : MessageQueue::Handler(queue) {}
-        ~MockHandler() override = default;
-        MOCK_METHOD2(dispatchInvalidate, void(int64_t vsyncId, nsecs_t expectedVSyncTimestamp));
+    struct MockHandler : MessageQueue::Handler {
+        using MessageQueue::Handler::Handler;
+
+        MOCK_METHOD(void, dispatchCommit, (int64_t, nsecs_t), (override));
     };
 
-    TestableMessageQueue() = default;
-    ~TestableMessageQueue() override = default;
+    explicit TestableMessageQueue(sp<MockHandler> handler)
+          : impl::MessageQueue(gNoOpCompositor, handler), mHandler(std::move(handler)) {}
 
-    void initHandler(const sp<MockHandler>& handler) { mHandler = handler; }
+public:
+    TestableMessageQueue() : TestableMessageQueue(sp<MockHandler>::make(*this)) {}
 
-    void triggerVsyncCallback(nsecs_t vsyncTime, nsecs_t targetWakeupTime, nsecs_t readyTime) {
-        vsyncCallback(vsyncTime, targetWakeupTime, readyTime);
-    }
+    using impl::MessageQueue::vsyncCallback;
+
+    const sp<MockHandler> mHandler;
 };
 
-class MockVSyncDispatch : public scheduler::VSyncDispatch {
-public:
-    MockVSyncDispatch() = default;
-    ~MockVSyncDispatch() override = default;
-
+struct MockVSyncDispatch : scheduler::VSyncDispatch {
     MOCK_METHOD2(registerCallback,
-                 CallbackToken(std::function<void(nsecs_t, nsecs_t, nsecs_t)> const&, std::string));
+                 CallbackToken(const std::function<void(nsecs_t, nsecs_t, nsecs_t)>&, std::string));
     MOCK_METHOD1(unregisterCallback, void(CallbackToken));
     MOCK_METHOD2(schedule, scheduler::ScheduleResult(CallbackToken, ScheduleTiming));
     MOCK_METHOD1(cancel, scheduler::CancelResult(CallbackToken token));
     MOCK_CONST_METHOD1(dump, void(std::string&));
 };
 
-class MockTokenManager : public frametimeline::TokenManager {
-public:
-    MockTokenManager() = default;
-    ~MockTokenManager() override = default;
-
+struct MockTokenManager : frametimeline::TokenManager {
     MOCK_METHOD1(generateTokenForPredictions, int64_t(frametimeline::TimelineItem&& prediction));
     MOCK_CONST_METHOD1(getPredictionsForToken, std::optional<frametimeline::TimelineItem>(int64_t));
 };
 
-class MessageQueueTest : public testing::Test {
-public:
-    MessageQueueTest() = default;
-    ~MessageQueueTest() override = default;
-
+struct MessageQueueTest : testing::Test {
     void SetUp() override {
-        EXPECT_NO_FATAL_FAILURE(mEventQueue.initHandler(mHandler));
-
         EXPECT_CALL(mVSyncDispatch, registerCallback(_, "sf")).WillOnce(Return(mCallbackToken));
         EXPECT_NO_FATAL_FAILURE(mEventQueue.initVsync(mVSyncDispatch, mTokenManager, mDuration));
         EXPECT_CALL(mVSyncDispatch, unregisterCallback(mCallbackToken)).Times(1);
     }
 
-    sp<TestableMessageQueue::MockHandler> mHandler =
-            new TestableMessageQueue::MockHandler(mEventQueue);
     MockVSyncDispatch mVSyncDispatch;
     MockTokenManager mTokenManager;
     TestableMessageQueue mEventQueue;
@@ -100,45 +89,49 @@
 /* ------------------------------------------------------------------------
  * Test cases
  */
-TEST_F(MessageQueueTest, invalidate) {
+TEST_F(MessageQueueTest, commit) {
     const auto timing = scheduler::VSyncDispatch::ScheduleTiming{.workDuration = mDuration.count(),
                                                                  .readyDuration = 0,
                                                                  .earliestVsync = 0};
-    EXPECT_FALSE(mEventQueue.nextExpectedInvalidate().has_value());
+    EXPECT_FALSE(mEventQueue.getScheduledFrameTime());
 
     EXPECT_CALL(mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(1234));
-    EXPECT_NO_FATAL_FAILURE(mEventQueue.invalidate());
-    EXPECT_TRUE(mEventQueue.nextExpectedInvalidate().has_value());
-    EXPECT_EQ(1234, mEventQueue.nextExpectedInvalidate().value().time_since_epoch().count());
+    EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleCommit());
+
+    ASSERT_TRUE(mEventQueue.getScheduledFrameTime());
+    EXPECT_EQ(1234, mEventQueue.getScheduledFrameTime()->time_since_epoch().count());
 }
 
-TEST_F(MessageQueueTest, invalidateTwice) {
+TEST_F(MessageQueueTest, commitTwice) {
     InSequence s;
     const auto timing = scheduler::VSyncDispatch::ScheduleTiming{.workDuration = mDuration.count(),
                                                                  .readyDuration = 0,
                                                                  .earliestVsync = 0};
 
     EXPECT_CALL(mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(1234));
-    EXPECT_NO_FATAL_FAILURE(mEventQueue.invalidate());
-    EXPECT_TRUE(mEventQueue.nextExpectedInvalidate().has_value());
-    EXPECT_EQ(1234, mEventQueue.nextExpectedInvalidate().value().time_since_epoch().count());
+    EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleCommit());
+
+    ASSERT_TRUE(mEventQueue.getScheduledFrameTime());
+    EXPECT_EQ(1234, mEventQueue.getScheduledFrameTime()->time_since_epoch().count());
 
     EXPECT_CALL(mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(4567));
-    EXPECT_NO_FATAL_FAILURE(mEventQueue.invalidate());
-    EXPECT_TRUE(mEventQueue.nextExpectedInvalidate().has_value());
-    EXPECT_EQ(4567, mEventQueue.nextExpectedInvalidate().value().time_since_epoch().count());
+    EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleCommit());
+
+    ASSERT_TRUE(mEventQueue.getScheduledFrameTime());
+    EXPECT_EQ(4567, mEventQueue.getScheduledFrameTime()->time_since_epoch().count());
 }
 
-TEST_F(MessageQueueTest, invalidateTwiceWithCallback) {
+TEST_F(MessageQueueTest, commitTwiceWithCallback) {
     InSequence s;
     const auto timing = scheduler::VSyncDispatch::ScheduleTiming{.workDuration = mDuration.count(),
                                                                  .readyDuration = 0,
                                                                  .earliestVsync = 0};
 
     EXPECT_CALL(mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(1234));
-    EXPECT_NO_FATAL_FAILURE(mEventQueue.invalidate());
-    EXPECT_TRUE(mEventQueue.nextExpectedInvalidate().has_value());
-    EXPECT_EQ(1234, mEventQueue.nextExpectedInvalidate().value().time_since_epoch().count());
+    EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleCommit());
+
+    ASSERT_TRUE(mEventQueue.getScheduledFrameTime());
+    EXPECT_EQ(1234, mEventQueue.getScheduledFrameTime()->time_since_epoch().count());
 
     const auto startTime = 100;
     const auto endTime = startTime + mDuration.count();
@@ -148,10 +141,10 @@
                 generateTokenForPredictions(
                         frametimeline::TimelineItem(startTime, endTime, presentTime)))
             .WillOnce(Return(vsyncId));
-    EXPECT_CALL(*mHandler, dispatchInvalidate(vsyncId, presentTime)).Times(1);
-    EXPECT_NO_FATAL_FAILURE(mEventQueue.triggerVsyncCallback(presentTime, startTime, endTime));
+    EXPECT_CALL(*mEventQueue.mHandler, dispatchCommit(vsyncId, presentTime)).Times(1);
+    EXPECT_NO_FATAL_FAILURE(mEventQueue.vsyncCallback(presentTime, startTime, endTime));
 
-    EXPECT_FALSE(mEventQueue.nextExpectedInvalidate().has_value());
+    EXPECT_FALSE(mEventQueue.getScheduledFrameTime());
 
     const auto timingAfterCallback =
             scheduler::VSyncDispatch::ScheduleTiming{.workDuration = mDuration.count(),
@@ -159,10 +152,10 @@
                                                      .earliestVsync = presentTime};
 
     EXPECT_CALL(mVSyncDispatch, schedule(mCallbackToken, timingAfterCallback)).WillOnce(Return(0));
-    EXPECT_NO_FATAL_FAILURE(mEventQueue.invalidate());
+    EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleCommit());
 }
 
-TEST_F(MessageQueueTest, invalidateWithDurationChange) {
+TEST_F(MessageQueueTest, commitWithDurationChange) {
     EXPECT_NO_FATAL_FAILURE(mEventQueue.setDuration(mDifferentDuration));
 
     const auto timing =
@@ -171,7 +164,7 @@
                                                      .earliestVsync = 0};
 
     EXPECT_CALL(mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(0));
-    EXPECT_NO_FATAL_FAILURE(mEventQueue.invalidate());
+    EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleCommit());
 }
 
 } // namespace
diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
index 84fa1e2..6c3b2fd 100644
--- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
@@ -176,7 +176,7 @@
  * Test cases
  */
 TEST_P(SetFrameRateTest, SetAndGet) {
-    EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+    EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1);
 
     const auto& layerFactory = GetParam();
 
@@ -187,7 +187,7 @@
 }
 
 TEST_P(SetFrameRateTest, SetAndGetParent) {
-    EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+    EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1);
 
     const auto& layerFactory = GetParam();
 
@@ -212,7 +212,7 @@
 }
 
 TEST_P(SetFrameRateTest, SetAndGetParentAllVote) {
-    EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+    EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1);
 
     const auto& layerFactory = GetParam();
 
@@ -251,7 +251,7 @@
 }
 
 TEST_P(SetFrameRateTest, SetAndGetChild) {
-    EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+    EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1);
 
     const auto& layerFactory = GetParam();
 
@@ -276,7 +276,7 @@
 }
 
 TEST_P(SetFrameRateTest, SetAndGetChildAllVote) {
-    EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+    EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1);
 
     const auto& layerFactory = GetParam();
 
@@ -315,7 +315,7 @@
 }
 
 TEST_P(SetFrameRateTest, SetAndGetChildAddAfterVote) {
-    EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+    EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1);
 
     const auto& layerFactory = GetParam();
 
@@ -345,7 +345,7 @@
 }
 
 TEST_P(SetFrameRateTest, SetAndGetChildRemoveAfterVote) {
-    EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+    EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1);
 
     const auto& layerFactory = GetParam();
 
@@ -376,7 +376,7 @@
 }
 
 TEST_P(SetFrameRateTest, SetAndGetParentNotInTree) {
-    EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+    EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1);
 
     const auto& layerFactory = GetParam();
 
@@ -475,7 +475,7 @@
 }
 
 TEST_P(SetFrameRateTest, addChildForParentWithTreeVote) {
-    EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+    EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1);
 
     const auto& layerFactory = GetParam();
 
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp
index 2362a31..8c30341 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp
@@ -51,8 +51,8 @@
     // --------------------------------------------------------------------
     // Cleanup conditions
 
-    // Destroying the display invalidates the display state.
-    EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+    // Creating the display commits a display transaction.
+    EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1);
 }
 
 TEST_F(CreateDisplayTest, createDisplaySetsCurrentStateForSecureDisplay) {
@@ -86,9 +86,9 @@
     // --------------------------------------------------------------------
     // Cleanup conditions
 
-    // Destroying the display invalidates the display state.
-    EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+    // Creating the display commits a display transaction.
+    EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1);
 }
 
 } // namespace
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DestroyDisplayTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DestroyDisplayTest.cpp
index e2be074..7087fb6 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DestroyDisplayTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DestroyDisplayTest.cpp
@@ -40,8 +40,8 @@
     // The call should notify the interceptor that a display was created.
     EXPECT_CALL(*mSurfaceInterceptor, saveDisplayDeletion(_)).Times(1);
 
-    // Destroying the display invalidates the display state.
-    EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+    // Destroying the display commits a display transaction.
+    EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1);
 
     // --------------------------------------------------------------------
     // Invocation
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp
index bd89397..29ff0cd 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp
@@ -38,9 +38,8 @@
     // --------------------------------------------------------------------
     // Call Expectations
 
-    // We expect invalidate() to be invoked once to trigger display transaction
-    // processing.
-    EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+    // We expect a scheduled commit for the display transaction.
+    EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1);
 
     // --------------------------------------------------------------------
     // Invocation
@@ -86,9 +85,8 @@
     // --------------------------------------------------------------------
     // Call Expectations
 
-    // We expect invalidate() to be invoked once to trigger display transaction
-    // processing.
-    EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+    // We expect a scheduled commit for the display transaction.
+    EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1);
 
     // --------------------------------------------------------------------
     // Invocation
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp
index bafa910..e1b44cf 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp
@@ -46,9 +46,8 @@
     // We expect a call to get the active display config.
     Case::Display::setupHwcGetActiveConfigCallExpectations(this);
 
-    // We expect invalidate() to be invoked once to trigger display transaction
-    // processing.
-    EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+    // We expect a scheduled commit for the display transaction.
+    EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1);
 
     EXPECT_CALL(*mVSyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
 
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp
index 6502420..e55721d 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp
@@ -268,7 +268,7 @@
     }
 
     static void setupRepaintEverythingCallExpectations(DisplayTransactionTest* test) {
-        EXPECT_CALL(*test->mMessageQueue, invalidate()).Times(1);
+        EXPECT_CALL(*test->mMessageQueue, scheduleCommit()).Times(1);
     }
 
     static void setupSurfaceInterceptorCallExpectations(DisplayTransactionTest* test,
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 7072439..de1cade 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -73,8 +73,8 @@
         return nullptr;
     }
 
-    std::unique_ptr<MessageQueue> createMessageQueue() override {
-        return std::make_unique<android::impl::MessageQueue>();
+    std::unique_ptr<MessageQueue> createMessageQueue(ICompositor& compositor) override {
+        return std::make_unique<android::impl::MessageQueue>(compositor);
     }
 
     std::unique_ptr<scheduler::VsyncConfiguration> createVsyncConfiguration(
@@ -296,6 +296,16 @@
      * Forwarding for functions being tested
      */
 
+    nsecs_t commit() {
+        constexpr int64_t kVsyncId = 123;
+        const nsecs_t now = systemTime();
+        const nsecs_t expectedVsyncTime = now + 10'000'000;
+        mFlinger->commit(now, kVsyncId, expectedVsyncTime);
+        return now;
+    }
+
+    void commitAndComposite() { mFlinger->composite(commit()); }
+
     auto createDisplay(const String8& displayName, bool secure) {
         return mFlinger->createDisplay(displayName, secure);
     }
@@ -343,10 +353,6 @@
         return mFlinger->setPowerModeInternal(display, mode);
     }
 
-    auto onMessageReceived(int32_t what) {
-        return mFlinger->onMessageReceived(what, /*vsyncId=*/0, systemTime());
-    }
-
     auto renderScreenImplLocked(const RenderArea& renderArea,
                                 SurfaceFlinger::TraverseLayersFunction traverseLayers,
                                 const std::shared_ptr<renderengine::ExternalTexture>& buffer,
@@ -761,7 +767,7 @@
     };
 
 private:
-    void scheduleRefresh(FrameHint) override {}
+    void scheduleComposite(FrameHint) override {}
     void setVsyncEnabled(bool) override {}
     void changeRefreshRate(const Scheduler::RefreshRate&, Scheduler::ModeEvent) override {}
     void kernelTimerChanged(bool) override {}
diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
index 1a50427..d8e68b8 100644
--- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
@@ -126,8 +126,7 @@
 
     void NotPlacedOnTransactionQueue(uint32_t flags, bool syncInputWindows) {
         ASSERT_EQ(0u, mFlinger.getTransactionQueue().size());
-        // called in SurfaceFlinger::signalTransaction
-        EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+        EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1);
         TransactionInfo transaction;
         setupSingle(transaction, flags, syncInputWindows,
                     /*desiredPresentTime*/ systemTime(), /*isAutoTimestamp*/ true,
@@ -157,8 +156,7 @@
 
     void PlaceOnTransactionQueue(uint32_t flags, bool syncInputWindows) {
         ASSERT_EQ(0u, mFlinger.getTransactionQueue().size());
-        // called in SurfaceFlinger::signalTransaction
-        EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+        EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1);
 
         // first check will see desired present time has not passed,
         // but afterwards it will look like the desired present time has passed
@@ -187,12 +185,11 @@
 
     void BlockedByPriorTransaction(uint32_t flags, bool syncInputWindows) {
         ASSERT_EQ(0u, mFlinger.getTransactionQueue().size());
-        // called in SurfaceFlinger::signalTransaction
         nsecs_t time = systemTime();
         if (!syncInputWindows) {
-            EXPECT_CALL(*mMessageQueue, invalidate()).Times(2);
+            EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(2);
         } else {
-            EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+            EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1);
         }
         // transaction that should go on the pending thread
         TransactionInfo transactionA;
@@ -255,8 +252,7 @@
 
 TEST_F(TransactionApplicationTest, Flush_RemovesFromQueue) {
     ASSERT_EQ(0u, mFlinger.getTransactionQueue().size());
-    // called in SurfaceFlinger::signalTransaction
-    EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+    EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1);
 
     TransactionInfo transactionA; // transaction to go on pending queue
     setupSingle(transactionA, /*flags*/ 0, /*syncInputWindows*/ false,
diff --git a/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h b/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h
index 0e7b320..d684337 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h
@@ -29,17 +29,18 @@
     MessageQueue();
     ~MessageQueue() override;
 
-    MOCK_METHOD1(init, void(const sp<SurfaceFlinger>&));
     MOCK_METHOD1(setInjector, void(sp<EventThreadConnection>));
     MOCK_METHOD0(waitMessage, void());
     MOCK_METHOD1(postMessage, void(sp<MessageHandler>&&));
-    MOCK_METHOD0(invalidate, void());
-    MOCK_METHOD0(refresh, void());
     MOCK_METHOD3(initVsync,
                  void(scheduler::VSyncDispatch&, frametimeline::TokenManager&,
                       std::chrono::nanoseconds));
     MOCK_METHOD1(setDuration, void(std::chrono::nanoseconds workDuration));
-    MOCK_METHOD0(nextExpectedInvalidate, std::optional<std::chrono::steady_clock::time_point>());
+
+    MOCK_METHOD(void, scheduleCommit, (), (override));
+    MOCK_METHOD(void, scheduleComposite, (), (override));
+
+    MOCK_METHOD(std::optional<Clock::time_point>, getScheduledFrameTime, (), (const, override));
 };
 
 } // namespace android::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h b/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h
index 291559f..e241dc9 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h
@@ -23,7 +23,7 @@
 namespace android::mock {
 
 struct SchedulerCallback final : ISchedulerCallback {
-    MOCK_METHOD(void, scheduleRefresh, (FrameHint), (override));
+    MOCK_METHOD(void, scheduleComposite, (FrameHint), (override));
     MOCK_METHOD1(setVsyncEnabled, void(bool));
     MOCK_METHOD2(changeRefreshRate,
                  void(const scheduler::RefreshRateConfigs::RefreshRate&,
@@ -33,7 +33,7 @@
 };
 
 struct NoOpSchedulerCallback final : ISchedulerCallback {
-    void scheduleRefresh(FrameHint) override {}
+    void scheduleComposite(FrameHint) override {}
     void setVsyncEnabled(bool) override {}
     void changeRefreshRate(const scheduler::RefreshRateConfigs::RefreshRate&,
                            scheduler::RefreshRateConfigEvent) override {}