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/Android.bp b/services/surfaceflinger/Android.bp
index e0dcab5..5647b73 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -176,7 +176,6 @@
"RefreshRateOverlay.cpp",
"RegionSamplingThread.cpp",
"RenderArea.cpp",
- "Scheduler/DispSyncSource.cpp",
"Scheduler/EventThread.cpp",
"Scheduler/FrameRateOverrideMappings.cpp",
"Scheduler/OneShotTimer.cpp",
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>;
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
index 7959e52..0af3efa 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
@@ -21,13 +21,15 @@
#include <scheduler/PresentLatencyTracker.h>
-#include "Scheduler/DispSyncSource.h"
#include "Scheduler/OneShotTimer.h"
#include "Scheduler/RefreshRateSelector.h"
#include "Scheduler/VSyncDispatchTimerQueue.h"
#include "Scheduler/VSyncPredictor.h"
#include "Scheduler/VSyncReactor.h"
+#include "mock/MockVSyncDispatch.h"
+#include "mock/MockVSyncTracker.h"
+
#include "surfaceflinger_fuzzers_utils.h"
#include "surfaceflinger_scheduler_fuzzer.h"
@@ -53,7 +55,7 @@
component->dump(res);
}
-class SchedulerFuzzer : private VSyncSource::Callback {
+class SchedulerFuzzer {
public:
SchedulerFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){};
void process();
@@ -66,7 +68,6 @@
void fuzzVSyncPredictor();
void fuzzVSyncReactor();
void fuzzLayerHistory();
- void fuzzDispSyncSource();
void fuzzCallbackToken(scheduler::VSyncDispatchTimerQueue* dispatch);
void fuzzVSyncDispatchTimerQueue();
void fuzzOneShotTimer();
@@ -75,8 +76,7 @@
FuzzedDataProvider mFdp;
-protected:
- void onVSyncEvent(nsecs_t /* when */, VSyncSource::VSyncData) {}
+ std::optional<scheduler::VsyncSchedule> mVsyncSchedule;
};
PhysicalDisplayId SchedulerFuzzer::getPhysicalDisplayId() {
@@ -90,10 +90,14 @@
}
void SchedulerFuzzer::fuzzEventThread() {
+ mVsyncSchedule.emplace(scheduler::VsyncSchedule(std::make_unique<mock::VSyncTracker>(),
+ std::make_unique<mock::VSyncDispatch>(),
+ nullptr));
const auto getVsyncPeriod = [](uid_t /* uid */) { return kSyncPeriod.count(); };
std::unique_ptr<android::impl::EventThread> thread = std::make_unique<
- android::impl::EventThread>(std::move(std::make_unique<FuzzImplVSyncSource>()), nullptr,
- nullptr, getVsyncPeriod);
+ android::impl::EventThread>("fuzzer", *mVsyncSchedule, nullptr, nullptr, getVsyncPeriod,
+ (std::chrono::nanoseconds)mFdp.ConsumeIntegral<uint64_t>(),
+ (std::chrono::nanoseconds)mFdp.ConsumeIntegral<uint64_t>());
thread->onHotplugReceived(getPhysicalDisplayId(), mFdp.ConsumeBool());
sp<EventThreadConnection> connection =
@@ -110,24 +114,6 @@
dump<android::impl::EventThread>(thread.get(), &mFdp);
}
-void SchedulerFuzzer::fuzzDispSyncSource() {
- std::unique_ptr<FuzzImplVSyncDispatch> vSyncDispatch =
- std::make_unique<FuzzImplVSyncDispatch>();
- std::unique_ptr<FuzzImplVSyncTracker> vSyncTracker = std::make_unique<FuzzImplVSyncTracker>();
- std::unique_ptr<scheduler::DispSyncSource> dispSyncSource = std::make_unique<
- scheduler::DispSyncSource>(*vSyncDispatch, *vSyncTracker,
- (std::chrono::nanoseconds)
- mFdp.ConsumeIntegral<uint64_t>() /*workDuration*/,
- (std::chrono::nanoseconds)mFdp.ConsumeIntegral<uint64_t>()
- /*readyDuration*/,
- mFdp.ConsumeBool(),
- mFdp.ConsumeRandomLengthString(kRandomStringLength).c_str());
- dispSyncSource->setVSyncEnabled(true);
- dispSyncSource->setCallback(this);
- dispSyncSource->setDuration((std::chrono::nanoseconds)mFdp.ConsumeIntegral<uint64_t>(), 0ns);
- dump<scheduler::DispSyncSource>(dispSyncSource.get(), &mFdp);
-}
-
void SchedulerFuzzer::fuzzCallbackToken(scheduler::VSyncDispatchTimerQueue* dispatch) {
scheduler::VSyncDispatch::CallbackToken tmp = dispatch->registerCallback(
[&](auto, auto, auto) {
@@ -417,7 +403,6 @@
fuzzVSyncPredictor();
fuzzVSyncReactor();
fuzzLayerHistory();
- fuzzDispSyncSource();
fuzzEventThread();
fuzzVSyncDispatchTimerQueue();
fuzzOneShotTimer();
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.h b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.h
index 2bc5b46..713b710 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.h
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.h
@@ -78,22 +78,6 @@
sp<Layer> createClone() override { return nullptr; }
};
-class FuzzImplVSyncSource : public VSyncSource {
-public:
- const char* getName() const override { return "fuzz"; }
-
- void setVSyncEnabled(bool /* enable */) override {}
-
- void setCallback(Callback* /* callback */) override {}
-
- void setDuration(std::chrono::nanoseconds /* workDuration */,
- std::chrono::nanoseconds /* readyDuration */) override {}
-
- VSyncData getLatestVSyncData() const override { return {}; }
-
- void dump(std::string& /* result */) const override {}
-};
-
class FuzzImplVSyncTracker : public scheduler::VSyncTracker {
public:
FuzzImplVSyncTracker(nsecs_t period) { mPeriod = period; }
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 6d1b3fe..824899b 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -36,6 +36,7 @@
"mock/MockNativeWindowSurface.cpp",
"mock/MockTimeStats.cpp",
"mock/MockVsyncController.cpp",
+ "mock/MockVSyncDispatch.cpp",
"mock/MockVSyncTracker.cpp",
"mock/system/window/MockNativeWindow.cpp",
],
@@ -71,7 +72,6 @@
"libsurfaceflinger_unittest_main.cpp",
"AidlPowerHalWrapperTest.cpp",
"CompositionTest.cpp",
- "DispSyncSourceTest.cpp",
"DisplayIdGeneratorTest.cpp",
"DisplayTransactionTest.cpp",
"DisplayDevice_GetBestColorModeTest.cpp",
diff --git a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
deleted file mode 100644
index 67ace1a..0000000
--- a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
+++ /dev/null
@@ -1,315 +0,0 @@
-/*
- * Copyright 2019 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.
- */
-
-#undef LOG_TAG
-#define LOG_TAG "LibSurfaceFlingerUnittests"
-#define LOG_NDEBUG 0
-
-#include <inttypes.h>
-
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-
-#include <log/log.h>
-
-#include "AsyncCallRecorder.h"
-#include "Scheduler/DispSyncSource.h"
-#include "Scheduler/VSyncDispatch.h"
-#include "mock/MockVSyncTracker.h"
-
-namespace android {
-namespace {
-
-using namespace std::chrono_literals;
-using namespace testing;
-
-class MockVSyncDispatch : public scheduler::VSyncDispatch {
-public:
- MOCK_METHOD(CallbackToken, registerCallback, (Callback, std::string), (override));
- MOCK_METHOD(void, unregisterCallback, (CallbackToken), (override));
- MOCK_METHOD(scheduler::ScheduleResult, schedule, (CallbackToken, ScheduleTiming), (override));
- MOCK_METHOD(scheduler::CancelResult, cancel, (CallbackToken), (override));
- MOCK_METHOD(void, dump, (std::string&), (const, override));
-
- MockVSyncDispatch() {
- ON_CALL(*this, registerCallback)
- .WillByDefault(
- [this](std::function<void(nsecs_t, nsecs_t, nsecs_t)> const& callback,
- std::string) {
- CallbackToken token(mNextToken);
- mNextToken++;
-
- mCallbacks.emplace(token, CallbackData(callback));
- ALOGD("registerCallback: %zu", token.value());
- return token;
- });
-
- ON_CALL(*this, unregisterCallback).WillByDefault([this](CallbackToken token) {
- ALOGD("unregisterCallback: %zu", token.value());
- mCallbacks.erase(token);
- });
-
- ON_CALL(*this, schedule).WillByDefault([this](CallbackToken token, ScheduleTiming timing) {
- ALOGD("schedule: %zu", token.value());
- if (mCallbacks.count(token) == 0) {
- ALOGD("schedule: callback %zu not registered", token.value());
- return scheduler::ScheduleResult{};
- }
-
- auto& callback = mCallbacks.at(token);
- callback.scheduled = true;
- callback.vsyncTime = timing.earliestVsync;
- callback.targetWakeupTime =
- timing.earliestVsync - timing.workDuration - timing.readyDuration;
- ALOGD("schedule: callback %zu scheduled", token.value());
- return scheduler::ScheduleResult{callback.targetWakeupTime};
- });
-
- ON_CALL(*this, cancel).WillByDefault([this](CallbackToken token) {
- ALOGD("cancel: %zu", token.value());
- if (mCallbacks.count(token) == 0) {
- ALOGD("cancel: callback %zu is not registered", token.value());
- return scheduler::CancelResult::Error;
- }
-
- auto& callback = mCallbacks.at(token);
- callback.scheduled = false;
- ALOGD("cancel: callback %zu cancelled", token.value());
- return scheduler::CancelResult::Cancelled;
- });
- }
-
- void triggerCallbacks() {
- ALOGD("triggerCallbacks");
- for (auto& [token, callback] : mCallbacks) {
- if (callback.scheduled) {
- ALOGD("triggerCallbacks: callback %zu", token.value());
- callback.scheduled = false;
- callback.func(callback.vsyncTime, callback.targetWakeupTime, callback.readyTime);
- } else {
- ALOGD("triggerCallbacks: callback %zu is not scheduled", token.value());
- }
- }
- }
-
-private:
- struct CallbackData {
- explicit CallbackData(std::function<void(nsecs_t, nsecs_t, nsecs_t)> func)
- : func(std::move(func)) {}
-
- std::function<void(nsecs_t, nsecs_t, nsecs_t)> func;
- bool scheduled = false;
- nsecs_t vsyncTime = 0;
- nsecs_t targetWakeupTime = 0;
- nsecs_t readyTime = 0;
- };
-
- std::unordered_map<CallbackToken, CallbackData> mCallbacks;
- size_t mNextToken;
-};
-
-class DispSyncSourceTest : public testing::Test, private VSyncSource::Callback {
-protected:
- DispSyncSourceTest();
- ~DispSyncSourceTest() override;
-
- void SetUp() override;
- void createDispSyncSource();
-
- void onVSyncEvent(nsecs_t when, VSyncSource::VSyncData) override;
-
- std::unique_ptr<MockVSyncDispatch> mVSyncDispatch;
- std::unique_ptr<mock::VSyncTracker> mVSyncTracker;
- std::unique_ptr<scheduler::DispSyncSource> mDispSyncSource;
-
- AsyncCallRecorder<void (*)(nsecs_t, VSyncSource::VSyncData)> mVSyncEventCallRecorder;
-
- static constexpr std::chrono::nanoseconds mWorkDuration = 20ms;
- static constexpr std::chrono::nanoseconds mReadyDuration = 10ms;
- static constexpr int mIterations = 100;
- const scheduler::VSyncDispatch::CallbackToken mFakeToken{2398};
- const std::string mName = "DispSyncSourceTest";
-};
-
-DispSyncSourceTest::DispSyncSourceTest() {
- const ::testing::TestInfo* const test_info =
- ::testing::UnitTest::GetInstance()->current_test_info();
- ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
-}
-
-DispSyncSourceTest::~DispSyncSourceTest() {
- const ::testing::TestInfo* const test_info =
- ::testing::UnitTest::GetInstance()->current_test_info();
- ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
-}
-
-void DispSyncSourceTest::SetUp() {
- mVSyncDispatch = std::make_unique<MockVSyncDispatch>();
- mVSyncTracker = std::make_unique<mock::VSyncTracker>();
-}
-
-void DispSyncSourceTest::onVSyncEvent(nsecs_t when, VSyncSource::VSyncData vsyncData) {
- ALOGD("onVSyncEvent: %" PRId64, when);
-
- mVSyncEventCallRecorder.recordCall(when, vsyncData);
-}
-
-void DispSyncSourceTest::createDispSyncSource() {
- mDispSyncSource = std::make_unique<scheduler::DispSyncSource>(*mVSyncDispatch, *mVSyncTracker,
- mWorkDuration, mReadyDuration,
- true, mName.c_str());
- mDispSyncSource->setCallback(this);
-}
-
-/* ------------------------------------------------------------------------
- * Test cases
- */
-
-TEST_F(DispSyncSourceTest, createDispSync) {
- EXPECT_TRUE(mVSyncDispatch);
-}
-
-TEST_F(DispSyncSourceTest, createDispSyncSource) {
- InSequence seq;
- EXPECT_CALL(*mVSyncDispatch, registerCallback(_, mName)).WillOnce(Return(mFakeToken));
- EXPECT_CALL(*mVSyncDispatch, cancel(mFakeToken))
- .WillOnce(Return(scheduler::CancelResult::Cancelled));
- EXPECT_CALL(*mVSyncDispatch, unregisterCallback(mFakeToken)).WillOnce(Return());
- createDispSyncSource();
-
- EXPECT_TRUE(mDispSyncSource);
-}
-
-TEST_F(DispSyncSourceTest, noCallbackAfterInit) {
- InSequence seq;
- EXPECT_CALL(*mVSyncDispatch, registerCallback(_, mName)).Times(1);
- EXPECT_CALL(*mVSyncDispatch, cancel(_)).Times(1);
- EXPECT_CALL(*mVSyncDispatch, unregisterCallback(_)).Times(1);
- createDispSyncSource();
-
- EXPECT_TRUE(mDispSyncSource);
-
- // DispSyncSource starts with Vsync disabled
- mVSyncDispatch->triggerCallbacks();
- EXPECT_FALSE(mVSyncEventCallRecorder.waitForUnexpectedCall().has_value());
-}
-
-TEST_F(DispSyncSourceTest, waitForCallbacks) {
- InSequence seq;
- EXPECT_CALL(*mVSyncDispatch, registerCallback(_, mName)).Times(1);
- EXPECT_CALL(*mVSyncDispatch,
- schedule(_, Truly([&](auto timings) {
- return timings.workDuration == mWorkDuration.count() &&
- timings.readyDuration == mReadyDuration.count();
- })))
- .Times(mIterations + 1);
- EXPECT_CALL(*mVSyncDispatch, cancel(_)).Times(1);
- EXPECT_CALL(*mVSyncDispatch, unregisterCallback(_)).Times(1);
- createDispSyncSource();
-
- EXPECT_TRUE(mDispSyncSource);
-
- mDispSyncSource->setVSyncEnabled(true);
- for (int i = 0; i < mIterations; i++) {
- mVSyncDispatch->triggerCallbacks();
- const auto callbackData = mVSyncEventCallRecorder.waitForCall();
- ASSERT_TRUE(callbackData.has_value());
- const auto [when, vsyncData] = callbackData.value();
- EXPECT_EQ(when,
- vsyncData.expectedPresentationTime - mWorkDuration.count() -
- mReadyDuration.count());
- }
-}
-
-TEST_F(DispSyncSourceTest, waitForCallbacksWithDurationChange) {
- InSequence seq;
- EXPECT_CALL(*mVSyncDispatch, registerCallback(_, mName)).Times(1);
- EXPECT_CALL(*mVSyncDispatch,
- schedule(_, Truly([&](auto timings) {
- return timings.workDuration == mWorkDuration.count() &&
- timings.readyDuration == mReadyDuration.count();
- })))
- .Times(1);
-
- createDispSyncSource();
-
- EXPECT_TRUE(mDispSyncSource);
-
- mDispSyncSource->setVSyncEnabled(true);
- EXPECT_CALL(*mVSyncDispatch,
- schedule(_, Truly([&](auto timings) {
- return timings.workDuration == mWorkDuration.count() &&
- timings.readyDuration == mReadyDuration.count();
- })))
- .Times(mIterations);
- for (int i = 0; i < mIterations; i++) {
- mVSyncDispatch->triggerCallbacks();
- const auto callbackData = mVSyncEventCallRecorder.waitForCall();
- ASSERT_TRUE(callbackData.has_value());
- const auto [when, vsyncData] = callbackData.value();
- EXPECT_EQ(when,
- vsyncData.expectedPresentationTime - mWorkDuration.count() -
- mReadyDuration.count());
- }
-
- const auto newDuration = mWorkDuration / 2;
- EXPECT_CALL(*mVSyncDispatch, schedule(_, Truly([&](auto timings) {
- return timings.workDuration == newDuration.count() &&
- timings.readyDuration == 0;
- })))
- .Times(1);
- mDispSyncSource->setDuration(newDuration, 0ns);
-
- EXPECT_CALL(*mVSyncDispatch, schedule(_, Truly([&](auto timings) {
- return timings.workDuration == newDuration.count() &&
- timings.readyDuration == 0;
- })))
- .Times(mIterations);
- for (int i = 0; i < mIterations; i++) {
- mVSyncDispatch->triggerCallbacks();
- const auto callbackData = mVSyncEventCallRecorder.waitForCall();
- ASSERT_TRUE(callbackData.has_value());
- const auto [when, vsyncData] = callbackData.value();
- EXPECT_EQ(when, vsyncData.expectedPresentationTime - newDuration.count());
- }
-
- EXPECT_CALL(*mVSyncDispatch, cancel(_)).Times(1);
- EXPECT_CALL(*mVSyncDispatch, unregisterCallback(_)).Times(1);
-}
-
-TEST_F(DispSyncSourceTest, getLatestVsyncData) {
- const nsecs_t now = systemTime();
- const nsecs_t expectedPresentationTime =
- now + mWorkDuration.count() + mReadyDuration.count() + 1;
- EXPECT_CALL(*mVSyncTracker, nextAnticipatedVSyncTimeFrom(_))
- .WillOnce(Return(expectedPresentationTime));
- {
- InSequence seq;
- EXPECT_CALL(*mVSyncDispatch, registerCallback(_, mName)).Times(1);
- EXPECT_CALL(*mVSyncDispatch, cancel(_)).Times(1);
- EXPECT_CALL(*mVSyncDispatch, unregisterCallback(_)).Times(1);
- }
-
- createDispSyncSource();
- EXPECT_TRUE(mDispSyncSource);
-
- const auto vsyncData = mDispSyncSource->getLatestVSyncData();
- ASSERT_EQ(vsyncData.expectedPresentationTime, expectedPresentationTime);
- EXPECT_EQ(vsyncData.deadlineTimestamp, expectedPresentationTime - mReadyDuration.count());
-}
-
-} // namespace
-} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index dd87f9d..b3aba37 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -30,12 +30,16 @@
#include "DisplayHardware/DisplayMode.h"
#include "FrameTimeline.h"
#include "Scheduler/EventThread.h"
+#include "mock/MockVSyncDispatch.h"
+#include "mock/MockVSyncTracker.h"
+#include "mock/MockVsyncController.h"
using namespace std::chrono_literals;
using namespace std::placeholders;
using testing::_;
using testing::Invoke;
+using testing::Return;
namespace android {
@@ -50,24 +54,13 @@
constexpr std::chrono::duration VSYNC_PERIOD(16ms);
-class MockVSyncSource : public VSyncSource {
-public:
- const char* getName() const override { return "test"; }
-
- MOCK_METHOD1(setVSyncEnabled, void(bool));
- MOCK_METHOD1(setCallback, void(VSyncSource::Callback*));
- MOCK_METHOD2(setDuration,
- void(std::chrono::nanoseconds workDuration,
- std::chrono::nanoseconds readyDuration));
- MOCK_METHOD1(pauseVsyncCallback, void(bool));
- MOCK_METHOD(VSyncSource::VSyncData, getLatestVSyncData, (), (const, override));
- MOCK_CONST_METHOD1(dump, void(std::string&));
-};
-
} // namespace
class EventThreadTest : public testing::Test {
protected:
+ static constexpr std::chrono::nanoseconds kWorkDuration = 0ms;
+ static constexpr std::chrono::nanoseconds kReadyDuration = 3ms;
+
class MockEventThreadConnection : public EventThreadConnection {
public:
MockEventThreadConnection(impl::EventThread* eventThread, uid_t callingUid,
@@ -84,21 +77,21 @@
EventThreadTest();
~EventThreadTest() override;
- void createThread(std::unique_ptr<VSyncSource>);
+ void createThread();
sp<MockEventThreadConnection> createConnection(ConnectionEventRecorder& recorder,
EventRegistrationFlags eventRegistration = {},
uid_t ownerUid = mConnectionUid);
- void expectVSyncSetEnabledCallReceived(bool expectedState);
+ void expectVSyncCallbackScheduleReceived(bool expectState);
void expectVSyncSetDurationCallReceived(std::chrono::nanoseconds expectedDuration,
std::chrono::nanoseconds expectedReadyDuration);
- VSyncSource::Callback* expectVSyncSetCallbackCallReceived();
void expectVsyncEventReceivedByConnection(const char* name,
ConnectionEventRecorder& connectionEventRecorder,
nsecs_t expectedTimestamp, unsigned expectedCount);
void expectVsyncEventReceivedByConnection(nsecs_t expectedTimestamp, unsigned expectedCount);
- void expectVsyncEventFrameTimelinesCorrect(nsecs_t expectedTimestamp,
- VSyncSource::VSyncData preferredVsyncData);
+ void expectVsyncEventFrameTimelinesCorrect(
+ nsecs_t expectedTimestamp,
+ /*VSyncSource::VSyncData*/ gui::VsyncEventData::FrameTimeline preferredVsyncData);
void expectHotplugEventReceivedByConnection(PhysicalDisplayId expectedDisplayId,
bool expectedConnected);
void expectConfigChangedEventReceivedByConnection(PhysicalDisplayId expectedDisplayId,
@@ -108,17 +101,31 @@
void expectUidFrameRateMappingEventReceivedByConnection(PhysicalDisplayId expectedDisplayId,
std::vector<FrameRateOverride>);
- AsyncCallRecorder<void (*)(bool)> mVSyncSetEnabledCallRecorder;
- AsyncCallRecorder<void (*)(VSyncSource::Callback*)> mVSyncSetCallbackCallRecorder;
- AsyncCallRecorder<void (*)(std::chrono::nanoseconds, std::chrono::nanoseconds)>
- mVSyncSetDurationCallRecorder;
+ void onVSyncEvent(nsecs_t timestamp, nsecs_t expectedPresentationTime,
+ nsecs_t deadlineTimestamp) {
+ mThread->onVsync(expectedPresentationTime, timestamp, deadlineTimestamp);
+ }
+
+ AsyncCallRecorderWithCannedReturn<
+ scheduler::ScheduleResult (*)(scheduler::VSyncDispatch::CallbackToken,
+ scheduler::VSyncDispatch::ScheduleTiming)>
+ mVSyncCallbackScheduleRecorder{0};
+ AsyncCallRecorderWithCannedReturn<
+ scheduler::ScheduleResult (*)(scheduler::VSyncDispatch::CallbackToken,
+ scheduler::VSyncDispatch::ScheduleTiming)>
+ mVSyncCallbackUpdateRecorder{0};
+ AsyncCallRecorderWithCannedReturn<
+ scheduler::VSyncDispatch::CallbackToken (*)(scheduler::VSyncDispatch::Callback,
+ std::string)>
+ mVSyncCallbackRegisterRecorder{scheduler::VSyncDispatch::CallbackToken(0)};
+ AsyncCallRecorder<void (*)(scheduler::VSyncDispatch::CallbackToken)>
+ mVSyncCallbackUnregisterRecorder;
AsyncCallRecorder<void (*)()> mResyncCallRecorder;
AsyncCallRecorder<void (*)(nsecs_t, uid_t)> mThrottleVsyncCallRecorder;
ConnectionEventRecorder mConnectionEventCallRecorder{0};
ConnectionEventRecorder mThrottledConnectionEventCallRecorder{0};
- MockVSyncSource* mVSyncSource;
- VSyncSource::Callback* mCallback = nullptr;
+ std::optional<scheduler::VsyncSchedule> mVsyncSchedule;
std::unique_ptr<impl::EventThread> mThread;
sp<MockEventThreadConnection> mConnection;
sp<MockEventThreadConnection> mThrottledConnection;
@@ -133,19 +140,22 @@
::testing::UnitTest::GetInstance()->current_test_info();
ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
- auto vsyncSource = std::make_unique<MockVSyncSource>();
- mVSyncSource = vsyncSource.get();
+ mVsyncSchedule.emplace(scheduler::VsyncSchedule(std::make_unique<mock::VSyncTracker>(),
+ std::make_unique<mock::VSyncDispatch>(),
+ nullptr));
- EXPECT_CALL(*mVSyncSource, setVSyncEnabled(_))
- .WillRepeatedly(Invoke(mVSyncSetEnabledCallRecorder.getInvocable()));
+ mock::VSyncDispatch& mockDispatch =
+ *static_cast<mock::VSyncDispatch*>(&mVsyncSchedule->getDispatch());
+ EXPECT_CALL(mockDispatch, registerCallback(_, _))
+ .WillRepeatedly(Invoke(mVSyncCallbackRegisterRecorder.getInvocable()));
+ EXPECT_CALL(mockDispatch, schedule(_, _))
+ .WillRepeatedly(Invoke(mVSyncCallbackScheduleRecorder.getInvocable()));
+ EXPECT_CALL(mockDispatch, update(_, _))
+ .WillRepeatedly(Invoke(mVSyncCallbackUpdateRecorder.getInvocable()));
+ EXPECT_CALL(mockDispatch, unregisterCallback(_))
+ .WillRepeatedly(Invoke(mVSyncCallbackUnregisterRecorder.getInvocable()));
- EXPECT_CALL(*mVSyncSource, setCallback(_))
- .WillRepeatedly(Invoke(mVSyncSetCallbackCallRecorder.getInvocable()));
-
- EXPECT_CALL(*mVSyncSource, setDuration(_, _))
- .WillRepeatedly(Invoke(mVSyncSetDurationCallRecorder.getInvocable()));
-
- createThread(std::move(vsyncSource));
+ createThread();
mConnection =
createConnection(mConnectionEventCallRecorder,
gui::ISurfaceComposer::EventRegistration::modeChanged |
@@ -164,11 +174,12 @@
::testing::UnitTest::GetInstance()->current_test_info();
ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+ mThread.reset();
// EventThread should unregister itself as VSyncSource callback.
- EXPECT_TRUE(!mVSyncSetCallbackCallRecorder.waitForUnexpectedCall().has_value());
+ EXPECT_TRUE(mVSyncCallbackUnregisterRecorder.waitForCall().has_value());
}
-void EventThreadTest::createThread(std::unique_ptr<VSyncSource> source) {
+void EventThreadTest::createThread() {
const auto throttleVsync = [&](nsecs_t expectedVsyncTimestamp, uid_t uid) {
mThrottleVsyncCallRecorder.getInvocable()(expectedVsyncTimestamp, uid);
return (uid == mThrottledConnectionUid);
@@ -178,12 +189,13 @@
};
mTokenManager = std::make_unique<frametimeline::impl::TokenManager>();
- mThread = std::make_unique<impl::EventThread>(std::move(source), mTokenManager.get(),
- throttleVsync, getVsyncPeriod);
+ mThread =
+ std::make_unique<impl::EventThread>(/*std::move(source), */ "EventThreadTest",
+ *mVsyncSchedule, mTokenManager.get(), throttleVsync,
+ getVsyncPeriod, kWorkDuration, kReadyDuration);
// EventThread should register itself as VSyncSource callback.
- mCallback = expectVSyncSetCallbackCallReceived();
- ASSERT_TRUE(mCallback);
+ EXPECT_TRUE(mVSyncCallbackRegisterRecorder.waitForCall().has_value());
}
sp<EventThreadTest::MockEventThreadConnection> EventThreadTest::createConnection(
@@ -197,23 +209,20 @@
return connection;
}
-void EventThreadTest::expectVSyncSetEnabledCallReceived(bool expectedState) {
- auto args = mVSyncSetEnabledCallRecorder.waitForCall();
- ASSERT_TRUE(args.has_value());
- EXPECT_EQ(expectedState, std::get<0>(args.value()));
+void EventThreadTest::expectVSyncCallbackScheduleReceived(bool expectState) {
+ if (expectState) {
+ ASSERT_TRUE(mVSyncCallbackScheduleRecorder.waitForCall().has_value());
+ } else {
+ ASSERT_FALSE(mVSyncCallbackScheduleRecorder.waitForUnexpectedCall().has_value());
+ }
}
void EventThreadTest::expectVSyncSetDurationCallReceived(
std::chrono::nanoseconds expectedDuration, std::chrono::nanoseconds expectedReadyDuration) {
- auto args = mVSyncSetDurationCallRecorder.waitForCall();
+ auto args = mVSyncCallbackUpdateRecorder.waitForCall();
ASSERT_TRUE(args.has_value());
- EXPECT_EQ(expectedDuration, std::get<0>(args.value()));
- EXPECT_EQ(expectedReadyDuration, std::get<1>(args.value()));
-}
-
-VSyncSource::Callback* EventThreadTest::expectVSyncSetCallbackCallReceived() {
- auto callbackSet = mVSyncSetCallbackCallRecorder.waitForCall();
- return callbackSet.has_value() ? std::get<0>(callbackSet.value()) : nullptr;
+ EXPECT_EQ(expectedDuration.count(), std::get<1>(args.value()).workDuration);
+ EXPECT_EQ(expectedReadyDuration.count(), std::get<1>(args.value()).readyDuration);
}
void EventThreadTest::expectThrottleVsyncReceived(nsecs_t expectedTimestamp, uid_t uid) {
@@ -246,7 +255,7 @@
}
void EventThreadTest::expectVsyncEventFrameTimelinesCorrect(
- nsecs_t expectedTimestamp, VSyncSource::VSyncData preferredVsyncData) {
+ nsecs_t expectedTimestamp, VsyncEventData::FrameTimeline preferredVsyncData) {
auto args = mConnectionEventCallRecorder.waitForCall();
ASSERT_TRUE(args.has_value()) << " did not receive an event for timestamp "
<< expectedTimestamp;
@@ -335,9 +344,10 @@
*/
TEST_F(EventThreadTest, canCreateAndDestroyThreadWithNoEventsSent) {
- EXPECT_FALSE(mVSyncSetEnabledCallRecorder.waitForUnexpectedCall().has_value());
- EXPECT_FALSE(mVSyncSetCallbackCallRecorder.waitForCall(0us).has_value());
- EXPECT_FALSE(mVSyncSetDurationCallRecorder.waitForCall(0us).has_value());
+ EXPECT_FALSE(mVSyncCallbackRegisterRecorder.waitForCall(0us).has_value());
+ EXPECT_FALSE(mVSyncCallbackScheduleRecorder.waitForCall(0us).has_value());
+ EXPECT_FALSE(mVSyncCallbackUpdateRecorder.waitForCall(0us).has_value());
+ EXPECT_FALSE(mVSyncCallbackUnregisterRecorder.waitForCall(0us).has_value());
EXPECT_FALSE(mResyncCallRecorder.waitForCall(0us).has_value());
EXPECT_FALSE(mConnectionEventCallRecorder.waitForCall(0us).has_value());
}
@@ -350,7 +360,7 @@
mThread->requestNextVsync(mConnection);
// EventThread should not enable vsync callbacks.
- EXPECT_FALSE(mVSyncSetEnabledCallRecorder.waitForUnexpectedCall().has_value());
+ expectVSyncCallbackScheduleReceived(false);
}
TEST_F(EventThreadTest, requestNextVsyncPostsASingleVSyncEventToTheConnection) {
@@ -360,47 +370,51 @@
// EventThread should immediately request a resync.
EXPECT_TRUE(mResyncCallRecorder.waitForCall().has_value());
- // EventThread should enable vsync callbacks.
- expectVSyncSetEnabledCallReceived(true);
+ // EventThread should enable schedule a vsync callback
+ expectVSyncCallbackScheduleReceived(true);
// Use the received callback to signal a first vsync event.
// The throttler should receive the event, as well as the connection.
- mCallback->onVSyncEvent(123, {456, 789});
+ onVSyncEvent(123, 456, 789);
expectThrottleVsyncReceived(456, mConnectionUid);
expectVsyncEventReceivedByConnection(123, 1u);
+ // EventThread is requesting one more callback due to VsyncRequest::SingleSuppressCallback
+ expectVSyncCallbackScheduleReceived(true);
+
// Use the received callback to signal a second vsync event.
// The throttler should receive the event, but the connection should
// not as it was only interested in the first.
- mCallback->onVSyncEvent(456, {123, 0});
+ onVSyncEvent(456, 123, 0);
EXPECT_FALSE(mThrottleVsyncCallRecorder.waitForUnexpectedCall().has_value());
EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value());
// EventThread should also detect that at this point that it does not need
// any more vsync events, and should disable their generation.
- expectVSyncSetEnabledCallReceived(false);
+ expectVSyncCallbackScheduleReceived(false);
}
TEST_F(EventThreadTest, requestNextVsyncEventFrameTimelinesCorrect) {
// Signal that we want the next vsync event to be posted to the connection
mThread->requestNextVsync(mConnection);
- expectVSyncSetEnabledCallReceived(true);
+ expectVSyncCallbackScheduleReceived(true);
// Use the received callback to signal a vsync event.
// The throttler should receive the event, as well as the connection.
- VSyncSource::VSyncData vsyncData = {456, 789};
- mCallback->onVSyncEvent(123, vsyncData);
- expectVsyncEventFrameTimelinesCorrect(123, vsyncData);
+ onVSyncEvent(123, 456, 789);
+ expectVsyncEventFrameTimelinesCorrect(123, {-1, 789, 456});
}
TEST_F(EventThreadTest, getLatestVsyncEventData) {
const nsecs_t now = systemTime();
- const nsecs_t preferredDeadline = now + 10000000;
const nsecs_t preferredExpectedPresentationTime = now + 20000000;
- const VSyncSource::VSyncData preferredData = {preferredExpectedPresentationTime,
- preferredDeadline};
- EXPECT_CALL(*mVSyncSource, getLatestVSyncData()).WillOnce(Return(preferredData));
+ const nsecs_t preferredDeadline = preferredExpectedPresentationTime - kReadyDuration.count();
+
+ mock::VSyncTracker& mockTracker =
+ *static_cast<mock::VSyncTracker*>(&mVsyncSchedule->getTracker());
+ EXPECT_CALL(mockTracker, nextAnticipatedVSyncTimeFrom(_))
+ .WillOnce(Return(preferredExpectedPresentationTime));
VsyncEventData vsyncEventData = mThread->getLatestVsyncEventData(mConnection);
@@ -451,8 +465,7 @@
mThread->setVsyncRate(0, firstConnection);
// By itself, this should not enable vsync events
- EXPECT_FALSE(mVSyncSetEnabledCallRecorder.waitForUnexpectedCall().has_value());
- EXPECT_FALSE(mVSyncSetCallbackCallRecorder.waitForCall(0us).has_value());
+ expectVSyncCallbackScheduleReceived(false);
// However if there is another connection which wants events at a nonzero rate.....
ConnectionEventRecorder secondConnectionEventRecorder{0};
@@ -461,12 +474,12 @@
mThread->setVsyncRate(1, secondConnection);
// EventThread should enable vsync callbacks.
- expectVSyncSetEnabledCallReceived(true);
+ expectVSyncCallbackScheduleReceived(true);
// Send a vsync event. EventThread should then make a call to the
// the second connection. The first connection should not
// get the event.
- mCallback->onVSyncEvent(123, {456, 0});
+ onVSyncEvent(123, 0456, 0);
EXPECT_FALSE(firstConnectionEventRecorder.waitForUnexpectedCall().has_value());
expectVsyncEventReceivedByConnection("secondConnection", secondConnectionEventRecorder, 123,
1u);
@@ -476,21 +489,21 @@
mThread->setVsyncRate(1, mConnection);
// EventThread should enable vsync callbacks.
- expectVSyncSetEnabledCallReceived(true);
+ expectVSyncCallbackScheduleReceived(true);
// Send a vsync event. EventThread should then make a call to the
// throttler, and the connection.
- mCallback->onVSyncEvent(123, {456, 789});
+ onVSyncEvent(123, 456, 789);
expectThrottleVsyncReceived(456, mConnectionUid);
expectVsyncEventReceivedByConnection(123, 1u);
// A second event should go to the same places.
- mCallback->onVSyncEvent(456, {123, 0});
+ onVSyncEvent(456, 123, 0);
expectThrottleVsyncReceived(123, mConnectionUid);
expectVsyncEventReceivedByConnection(456, 2u);
// A third event should go to the same places.
- mCallback->onVSyncEvent(789, {777, 111});
+ onVSyncEvent(789, 777, 111);
expectThrottleVsyncReceived(777, mConnectionUid);
expectVsyncEventReceivedByConnection(789, 3u);
}
@@ -499,25 +512,25 @@
mThread->setVsyncRate(2, mConnection);
// EventThread should enable vsync callbacks.
- expectVSyncSetEnabledCallReceived(true);
+ expectVSyncCallbackScheduleReceived(true);
// The first event will not be seen by the connection.
- mCallback->onVSyncEvent(123, {456, 789});
+ onVSyncEvent(123, 456, 789);
EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value());
EXPECT_FALSE(mThrottleVsyncCallRecorder.waitForUnexpectedCall().has_value());
// The second event will be seen by the connection.
- mCallback->onVSyncEvent(456, {123, 0});
+ onVSyncEvent(456, 123, 0);
expectVsyncEventReceivedByConnection(456, 2u);
EXPECT_FALSE(mThrottleVsyncCallRecorder.waitForUnexpectedCall().has_value());
// The third event will not be seen by the connection.
- mCallback->onVSyncEvent(789, {777, 744});
+ onVSyncEvent(789, 777, 744);
EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value());
EXPECT_FALSE(mThrottleVsyncCallRecorder.waitForUnexpectedCall().has_value());
// The fourth event will be seen by the connection.
- mCallback->onVSyncEvent(101112, {7847, 86});
+ onVSyncEvent(101112, 7847, 86);
expectVsyncEventReceivedByConnection(101112, 4u);
}
@@ -525,17 +538,17 @@
mThread->setVsyncRate(1, mConnection);
// EventThread should enable vsync callbacks.
- expectVSyncSetEnabledCallReceived(true);
+ expectVSyncCallbackScheduleReceived(true);
// Destroy the only (strong) reference to the connection.
mConnection = nullptr;
// The first event will not be seen by the connection.
- mCallback->onVSyncEvent(123, {456, 789});
+ onVSyncEvent(123, 56, 789);
EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value());
// EventThread should disable vsync callbacks
- expectVSyncSetEnabledCallReceived(false);
+ expectVSyncCallbackScheduleReceived(false);
}
TEST_F(EventThreadTest, connectionsRemovedIfEventDeliveryError) {
@@ -544,18 +557,22 @@
mThread->setVsyncRate(1, errorConnection);
// EventThread should enable vsync callbacks.
- expectVSyncSetEnabledCallReceived(true);
+ expectVSyncCallbackScheduleReceived(true);
// The first event will be seen by the connection, which then returns an error.
- mCallback->onVSyncEvent(123, {456, 789});
+ onVSyncEvent(123, 456, 789);
expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 123, 1u);
+ // Another schedule is expected, since the connection is removed only after
+ // the next vsync is requested.
+ expectVSyncCallbackScheduleReceived(true);
+
// A subsequent event will not be seen by the connection.
- mCallback->onVSyncEvent(456, {123, 0});
+ onVSyncEvent(456, 123, 0);
EXPECT_FALSE(errorConnectionEventRecorder.waitForUnexpectedCall().has_value());
// EventThread should disable vsync callbacks with the second event
- expectVSyncSetEnabledCallReceived(false);
+ expectVSyncCallbackScheduleReceived(false);
}
TEST_F(EventThreadTest, tracksEventConnections) {
@@ -571,10 +588,10 @@
EXPECT_EQ(4, mThread->getEventThreadConnectionCount());
// EventThread should enable vsync callbacks.
- expectVSyncSetEnabledCallReceived(true);
+ expectVSyncCallbackScheduleReceived(true);
// The first event will be seen by the connection, which then returns an error.
- mCallback->onVSyncEvent(123, {456, 789});
+ onVSyncEvent(123, 456, 789);
expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 123, 1u);
expectVsyncEventReceivedByConnection("successConnection", secondConnectionEventRecorder, 123,
1u);
@@ -587,19 +604,22 @@
mThread->setVsyncRate(1, errorConnection);
// EventThread should enable vsync callbacks.
- expectVSyncSetEnabledCallReceived(true);
+ expectVSyncCallbackScheduleReceived(true);
// The first event will be seen by the connection, which then returns a non-fatal error.
- mCallback->onVSyncEvent(123, {456, 789});
+ onVSyncEvent(123, 456, 789);
expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 123, 1u);
+ expectVSyncCallbackScheduleReceived(true);
// A subsequent event will be seen by the connection, which still then returns a non-fatal
// error.
- mCallback->onVSyncEvent(456, {123, 0});
+ onVSyncEvent(456, 123, 0);
expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 456, 2u);
+ expectVSyncCallbackScheduleReceived(true);
// EventThread will not disable vsync callbacks as the errors are non-fatal.
- EXPECT_FALSE(mVSyncSetEnabledCallRecorder.waitForUnexpectedCall().has_value());
+ onVSyncEvent(456, 123, 0);
+ expectVSyncCallbackScheduleReceived(true);
}
TEST_F(EventThreadTest, setPhaseOffsetForwardsToVSyncSource) {
@@ -718,24 +738,27 @@
EXPECT_TRUE(mResyncCallRecorder.waitForCall().has_value());
// EventThread should enable vsync callbacks.
- expectVSyncSetEnabledCallReceived(true);
+ expectVSyncCallbackScheduleReceived(true);
// Use the received callback to signal a first vsync event.
// The throttler should receive the event, but not the connection.
- mCallback->onVSyncEvent(123, {456, 789});
+ onVSyncEvent(123, 456, 789);
expectThrottleVsyncReceived(456, mThrottledConnectionUid);
mThrottledConnectionEventCallRecorder.waitForUnexpectedCall();
+ expectVSyncCallbackScheduleReceived(true);
// Use the received callback to signal a second vsync event.
// The throttler should receive the event, but the connection should
// not as it was only interested in the first.
- mCallback->onVSyncEvent(456, {123, 0});
+ onVSyncEvent(456, 123, 0);
expectThrottleVsyncReceived(123, mThrottledConnectionUid);
EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value());
+ expectVSyncCallbackScheduleReceived(true);
// EventThread should not change the vsync state as it didn't send the event
// yet
- EXPECT_FALSE(mVSyncSetEnabledCallRecorder.waitForUnexpectedCall().has_value());
+ onVSyncEvent(456, 123, 0);
+ expectVSyncCallbackScheduleReceived(true);
}
} // namespace
diff --git a/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp
index 5e1042e..7aa5201 100644
--- a/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp
+++ b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp
@@ -23,6 +23,7 @@
#include "FrameTimeline.h"
#include "Scheduler/MessageQueue.h"
#include "SurfaceFlinger.h"
+#include "mock/MockVSyncDispatch.h"
namespace android {
@@ -59,14 +60,6 @@
const sp<MockHandler> mHandler;
};
-struct MockVSyncDispatch : scheduler::VSyncDispatch {
- MOCK_METHOD(CallbackToken, registerCallback, (Callback, std::string), (override));
- MOCK_METHOD(void, unregisterCallback, (CallbackToken), (override));
- MOCK_METHOD(scheduler::ScheduleResult, schedule, (CallbackToken, ScheduleTiming), (override));
- MOCK_METHOD(scheduler::CancelResult, cancel, (CallbackToken token), (override));
- MOCK_METHOD(void, dump, (std::string&), (const, override));
-};
-
struct MockTokenManager : frametimeline::TokenManager {
MOCK_METHOD1(generateTokenForPredictions, int64_t(frametimeline::TimelineItem&& prediction));
MOCK_CONST_METHOD1(getPredictionsForToken, std::optional<frametimeline::TimelineItem>(int64_t));
@@ -79,7 +72,7 @@
EXPECT_CALL(mVSyncDispatch, unregisterCallback(mCallbackToken)).Times(1);
}
- MockVSyncDispatch mVSyncDispatch;
+ mock::VSyncDispatch mVSyncDispatch;
MockTokenManager mTokenManager;
TestableMessageQueue mEventQueue;
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
index b8a6063..0f53eb6 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -26,6 +26,7 @@
#include "Scheduler/Scheduler.h"
#include "Scheduler/VSyncTracker.h"
#include "Scheduler/VsyncController.h"
+#include "mock/MockVSyncDispatch.h"
#include "mock/MockVSyncTracker.h"
#include "mock/MockVsyncController.h"
@@ -42,7 +43,9 @@
std::unique_ptr<VSyncTracker> tracker, RefreshRateSelectorPtr selectorPtr,
ISchedulerCallback& callback)
: Scheduler(*this, callback, Feature::kContentDetection) {
- mVsyncSchedule.emplace(VsyncSchedule(std::move(tracker), nullptr, std::move(controller)));
+ mVsyncSchedule.emplace(VsyncSchedule(std::move(tracker),
+ std::make_unique<mock::VSyncDispatch>(),
+ std::move(controller)));
const auto displayId = selectorPtr->getActiveMode().modePtr->getPhysicalDisplayId();
registerDisplay(displayId, std::move(selectorPtr));
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 113c518..584d52c 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -231,6 +231,8 @@
std::make_unique<scheduler::RefreshRateStats>(*mFlinger->mTimeStats, fps,
hal::PowerMode::OFF);
+ mTokenManager = std::make_unique<frametimeline::impl::TokenManager>();
+
using Callback = scheduler::ISchedulerCallback;
Callback& callback = callbackImpl == SchedulerCallbackImpl::kNoOp
? static_cast<Callback&>(mNoOpSchedulerCallback)
@@ -248,6 +250,8 @@
std::move(selectorPtr), callback);
}
+ mScheduler->initVsync(mScheduler->getVsyncSchedule().getDispatch(), *mTokenManager, 0ms);
+
mFlinger->mAppConnectionHandle = mScheduler->createConnection(std::move(appEventThread));
mFlinger->mSfConnectionHandle = mScheduler->createConnection(std::move(sfEventThread));
resetScheduler(mScheduler);
@@ -911,6 +915,7 @@
sp<SurfaceFlinger> mFlinger;
scheduler::mock::SchedulerCallback mSchedulerCallback;
scheduler::mock::NoOpSchedulerCallback mNoOpSchedulerCallback;
+ std::unique_ptr<frametimeline::impl::TokenManager> mTokenManager;
scheduler::TestableScheduler* mScheduler = nullptr;
};
diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
index 2b86e94..14a2860 100644
--- a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
@@ -270,6 +270,43 @@
EXPECT_THAT(cb.mCalls[0], Eq(mPeriod));
}
+TEST_F(VSyncDispatchTimerQueueTest, updateAlarmSettingFuture) {
+ auto intended = mPeriod - 230;
+ Sequence seq;
+ EXPECT_CALL(mMockClock, alarmAt(_, 900)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmAt(_, 700)).InSequence(seq);
+
+ CountingCallback cb(mDispatch);
+ auto result = mDispatch.schedule(cb,
+ {.workDuration = 100,
+ .readyDuration = 0,
+ .earliestVsync = intended});
+ EXPECT_TRUE(result.has_value());
+ EXPECT_EQ(900, *result);
+
+ result = mDispatch.update(cb,
+ {.workDuration = 300, .readyDuration = 0, .earliestVsync = intended});
+ EXPECT_TRUE(result.has_value());
+ EXPECT_EQ(700, *result);
+
+ advanceToNextCallback();
+
+ ASSERT_THAT(cb.mCalls.size(), Eq(1));
+ EXPECT_THAT(cb.mCalls[0], Eq(mPeriod));
+ EXPECT_THAT(cb.mWakeupTime[0], Eq(700));
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, updateDoesntSchedule) {
+ auto intended = mPeriod - 230;
+ EXPECT_CALL(mMockClock, alarmAt(_, _)).Times(0);
+
+ CountingCallback cb(mDispatch);
+ const auto result =
+ mDispatch.update(cb,
+ {.workDuration = 300, .readyDuration = 0, .earliestVsync = intended});
+ EXPECT_FALSE(result.has_value());
+}
+
TEST_F(VSyncDispatchTimerQueueTest, basicAlarmSettingFutureWithAdjustmentToTrueVsync) {
EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(1000)).WillOnce(Return(1150));
EXPECT_CALL(mMockClock, alarmAt(_, 1050));
diff --git a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
index 8bd689a..1fb2709 100644
--- a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
@@ -69,14 +69,6 @@
std::shared_ptr<Clock> const mClock;
};
-struct MockVSyncDispatch : VSyncDispatch {
- MOCK_METHOD(CallbackToken, registerCallback, (Callback, std::string), (override));
- MOCK_METHOD(void, unregisterCallback, (CallbackToken), (override));
- MOCK_METHOD(ScheduleResult, schedule, (CallbackToken, ScheduleTiming), (override));
- MOCK_METHOD(CancelResult, cancel, (CallbackToken), (override));
- MOCK_METHOD(void, dump, (std::string&), (const, override));
-};
-
std::shared_ptr<android::FenceTime> generateInvalidFence() {
sp<Fence> fence = sp<Fence>::make();
return std::make_shared<android::FenceTime>(fence);
diff --git a/services/surfaceflinger/tests/unittests/mock/MockVSyncDispatch.cpp b/services/surfaceflinger/tests/unittests/mock/MockVSyncDispatch.cpp
new file mode 100644
index 0000000..2817514
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/mock/MockVSyncDispatch.cpp
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mock/MockVSyncDispatch.h"
+
+namespace android::mock {
+
+// Explicit default instantiation is recommended.
+VSyncDispatch::VSyncDispatch() = default;
+VSyncDispatch::~VSyncDispatch() = default;
+
+} // namespace android::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/MockVSyncDispatch.h b/services/surfaceflinger/tests/unittests/mock/MockVSyncDispatch.h
new file mode 100644
index 0000000..dc32ff9
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/mock/MockVSyncDispatch.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2023 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 <gmock/gmock.h>
+
+#include "Scheduler/VSyncDispatch.h"
+
+namespace android::mock {
+
+class VSyncDispatch : public android::scheduler::VSyncDispatch {
+public:
+ VSyncDispatch();
+ ~VSyncDispatch() override;
+
+ MOCK_METHOD(CallbackToken, registerCallback, (Callback, std::string), (override));
+ MOCK_METHOD(void, unregisterCallback, (CallbackToken), (override));
+ MOCK_METHOD(scheduler::ScheduleResult, schedule, (CallbackToken, ScheduleTiming), (override));
+ MOCK_METHOD(scheduler::ScheduleResult, update, (CallbackToken, ScheduleTiming), (override));
+ MOCK_METHOD(scheduler::CancelResult, cancel, (CallbackToken token), (override));
+ MOCK_METHOD(void, dump, (std::string&), (const, override));
+};
+
+} // namespace android::mock