diff options
author | 2019-08-01 18:35:59 -0700 | |
---|---|---|
committer | 2019-08-16 16:27:58 -0700 | |
commit | 980418350b15d595ebe17ec9ae895dac374c6ee0 (patch) | |
tree | f451791885e6a6d6dadea3d78f0a52fe70f89a44 | |
parent | 13db07b6bcccb58ce51a385399e7288aaab0e077 (diff) |
SF: Clean up Scheduler
Remove dynamic allocation for Scheduler::{Connection,ConnectionHandle},
as well as ref-counting for the latter. Also, remove dead code and make
members private.
Bug: 130554049
Test: libsurfaceflinger_unittest
Change-Id: Ibb9dc8d4cb66451a4172c852a36032bbc0a54411
22 files changed, 360 insertions, 504 deletions
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index 07fdead310..1c1367c916 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -21,15 +21,18 @@ #include "RegionSamplingThread.h" +#include <compositionengine/Display.h> +#include <compositionengine/impl/OutputCompositionState.h> #include <cutils/properties.h> #include <gui/IRegionSamplingListener.h> +#include <ui/DisplayStatInfo.h> #include <utils/Trace.h> + #include <string> -#include <compositionengine/Display.h> -#include <compositionengine/impl/OutputCompositionState.h> #include "DisplayDevice.h" #include "Layer.h" +#include "Scheduler/DispSync.h" #include "SurfaceFlinger.h" namespace android { @@ -105,9 +108,8 @@ struct SamplingOffsetCallback : DispSync::Callback { if (mVsyncListening) return; mPhaseIntervalSetting = Phase::ZERO; - mScheduler.withPrimaryDispSync([this](android::DispSync& sync) { - sync.addEventListener("SamplingThreadDispSyncListener", 0, this, mLastCallbackTime); - }); + mScheduler.getPrimaryDispSync().addEventListener("SamplingThreadDispSyncListener", 0, this, + mLastCallbackTime); mVsyncListening = true; } @@ -120,9 +122,7 @@ private: void stopVsyncListenerLocked() /*REQUIRES(mMutex)*/ { if (!mVsyncListening) return; - mScheduler.withPrimaryDispSync([this](android::DispSync& sync) { - sync.removeEventListener(this, &mLastCallbackTime); - }); + mScheduler.getPrimaryDispSync().removeEventListener(this, &mLastCallbackTime); mVsyncListening = false; } @@ -132,16 +132,13 @@ private: if (mPhaseIntervalSetting == Phase::ZERO) { ATRACE_INT(lumaSamplingStepTag, static_cast<int>(samplingStep::waitForSamplePhase)); mPhaseIntervalSetting = Phase::SAMPLING; - mScheduler.withPrimaryDispSync([this](android::DispSync& sync) { - sync.changePhaseOffset(this, mTargetSamplingOffset.count()); - }); + mScheduler.getPrimaryDispSync().changePhaseOffset(this, mTargetSamplingOffset.count()); return; } if (mPhaseIntervalSetting == Phase::SAMPLING) { mPhaseIntervalSetting = Phase::ZERO; - mScheduler.withPrimaryDispSync( - [this](android::DispSync& sync) { sync.changePhaseOffset(this, 0); }); + mScheduler.getPrimaryDispSync().changePhaseOffset(this, 0); stopVsyncListenerLocked(); lock.unlock(); mRegionSamplingThread.notifySamplingOffset(); diff --git a/services/surfaceflinger/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp index ad5eb332c5..ae776a012a 100644 --- a/services/surfaceflinger/Scheduler/DispSync.cpp +++ b/services/surfaceflinger/Scheduler/DispSync.cpp @@ -462,22 +462,14 @@ private: TracedOrdinal<bool> mParity; }; -DispSync::DispSync(const char* name) : mName(name), mRefreshSkipCount(0) { +DispSync::DispSync(const char* name, bool hasSyncFramework) + : mName(name), mIgnorePresentFences(!hasSyncFramework) { // This flag offers the ability to turn on systrace logging from the shell. char value[PROPERTY_VALUE_MAX]; property_get("debug.sf.dispsync_trace_detailed_info", value, "0"); mTraceDetailedInfo = atoi(value); - mThread = new DispSyncThread(name, mTraceDetailedInfo); -} - -DispSync::~DispSync() { - mThread->stop(); - mThread->requestExitAndWait(); -} -void DispSync::init(bool hasSyncFramework, int64_t dispSyncPresentTimeOffset) { - mIgnorePresentFences = !hasSyncFramework; - mPresentTimeOffset = dispSyncPresentTimeOffset; + mThread = new DispSyncThread(name, mTraceDetailedInfo); mThread->run("DispSync", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE); // set DispSync to SCHED_FIFO to minimize jitter @@ -495,6 +487,11 @@ void DispSync::init(bool hasSyncFramework, int64_t dispSyncPresentTimeOffset) { } } +DispSync::~DispSync() { + mThread->stop(); + mThread->requestExitAndWait(); +} + void DispSync::reset() { Mutex::Autolock lock(mMutex); resetLocked(); diff --git a/services/surfaceflinger/Scheduler/DispSync.h b/services/surfaceflinger/Scheduler/DispSync.h index 3e33c7edc0..f5175ba0bd 100644 --- a/services/surfaceflinger/Scheduler/DispSync.h +++ b/services/surfaceflinger/Scheduler/DispSync.h @@ -88,11 +88,10 @@ class DispSyncThread; // needed. class DispSync : public android::DispSync { public: - explicit DispSync(const char* name); + // hasSyncFramework specifies whether the platform supports present fences. + DispSync(const char* name, bool hasSyncFramework); ~DispSync() override; - void init(bool hasSyncFramework, int64_t dispSyncPresentTimeOffset); - // reset clears the resync samples and error value. void reset() override; @@ -252,7 +251,7 @@ private: std::shared_ptr<FenceTime> mPresentFences[NUM_PRESENT_SAMPLES]{FenceTime::NO_FENCE}; size_t mPresentSampleOffset; - int mRefreshSkipCount; + int mRefreshSkipCount = 0; // mThread is the thread from which all the callbacks are called. sp<DispSyncThread> mThread; @@ -260,10 +259,6 @@ private: // mMutex is used to protect access to all member variables. mutable Mutex mMutex; - // This is the offset from the present fence timestamps to the corresponding - // vsync event. - int64_t mPresentTimeOffset; - // Ignore present (retire) fences if the device doesn't have support for the // sync framework bool mIgnorePresentFences; diff --git a/services/surfaceflinger/Scheduler/EventControlThread.cpp b/services/surfaceflinger/Scheduler/EventControlThread.cpp index fb6cff5705..85a7f82a3c 100644 --- a/services/surfaceflinger/Scheduler/EventControlThread.cpp +++ b/services/surfaceflinger/Scheduler/EventControlThread.cpp @@ -31,7 +31,7 @@ EventControlThread::~EventControlThread() = default; namespace impl { EventControlThread::EventControlThread(EventControlThread::SetVSyncEnabledFunction function) - : mSetVSyncEnabled(function) { + : mSetVSyncEnabled(std::move(function)) { pthread_setname_np(mThread.native_handle(), "EventControlThread"); pid_t tid = pthread_gettid_np(mThread.native_handle()); diff --git a/services/surfaceflinger/Scheduler/OneShotTimer.h b/services/surfaceflinger/Scheduler/OneShotTimer.h index fd1aa02226..921631e009 100644 --- a/services/surfaceflinger/Scheduler/OneShotTimer.h +++ b/services/surfaceflinger/Scheduler/OneShotTimer.h @@ -39,6 +39,8 @@ public: const TimeoutCallback& timeoutCallback); ~OneShotTimer(); + const Interval& interval() const { return mInterval; } + // Initializes and turns on the idle timer. void start(); // Stops the idle timer and any held resources. diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp index 9f8567d0ec..bd25a320db 100644 --- a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp +++ b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp @@ -63,12 +63,13 @@ PhaseOffsets::Offsets PhaseOffsets::getOffsetsForRefreshRate( void PhaseOffsets::dump(std::string& result) const { const auto [early, earlyGl, late, threshold] = getCurrentOffsets(); - base::StringAppendF(&result, - " app phase: %9" PRId64 " ns\t SF phase: %9" PRId64 " ns\n" - " early app phase: %9" PRId64 " ns\t early SF phase: %9" PRId64 " ns\n" - "GL early app phase: %9" PRId64 " ns\tGL early SF phase: %9" PRId64 " ns\n" - "threshold for next VSYNC: %" PRId64 " ns\n", - late.app, late.sf, early.app, early.sf, earlyGl.app, earlyGl.sf, threshold); + using base::StringAppendF; + StringAppendF(&result, + " app phase: %9" PRId64 " ns\t SF phase: %9" PRId64 " ns\n" + " early app phase: %9" PRId64 " ns\t early SF phase: %9" PRId64 " ns\n" + " GL early app phase: %9" PRId64 " ns\tGL early SF phase: %9" PRId64 " ns\n" + "next VSYNC threshold: %9" PRId64 " ns\n", + late.app, late.sf, early.app, early.sf, earlyGl.app, earlyGl.sf, threshold); } PhaseOffsets::Offsets PhaseOffsets::getDefaultOffsets(nsecs_t thresholdForNextVsync) { diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h index d7300583c3..9d4774962a 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h @@ -16,16 +16,23 @@ #pragma once +#include <android-base/stringprintf.h> + #include <algorithm> #include <numeric> - -#include "android-base/stringprintf.h" +#include <type_traits> #include "DisplayHardware/HWComposer.h" #include "Scheduler/SchedulerUtils.h" -namespace android { -namespace scheduler { +namespace android::scheduler { + +enum class RefreshRateConfigEvent : unsigned { None = 0b0, Changed = 0b1 }; + +inline RefreshRateConfigEvent operator|(RefreshRateConfigEvent lhs, RefreshRateConfigEvent rhs) { + using T = std::underlying_type_t<RefreshRateConfigEvent>; + return static_cast<RefreshRateConfigEvent>(static_cast<T>(lhs) | static_cast<T>(rhs)); +} /** * This class is used to encapsulate configuration for refresh rates. It holds information @@ -134,5 +141,4 @@ private: std::map<RefreshRateType, std::shared_ptr<RefreshRate>> mRefreshRates; }; -} // namespace scheduler -} // namespace android +} // namespace android::scheduler diff --git a/services/surfaceflinger/Scheduler/RefreshRateStats.h b/services/surfaceflinger/Scheduler/RefreshRateStats.h index 7e7c6307a4..1f097db08d 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateStats.h +++ b/services/surfaceflinger/Scheduler/RefreshRateStats.h @@ -94,13 +94,13 @@ public: // Traverses through the map of config modes and returns how long they've been running in easy // to read format. - std::string doDump() const { - std::ostringstream stream; - stream << "+ Refresh rate: running time in seconds\n"; + void dump(std::string& result) const { + std::ostringstream stream("+ Refresh rate: running time in seconds\n"); + for (const auto& [name, time] : const_cast<RefreshRateStats*>(this)->getTotalTimes()) { stream << name << ": " << getDateFormatFromMs(time) << '\n'; } - return stream.str(); + result.append(stream.str()); } private: diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 38834273a4..7f1fb3bcd4 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#undef LOG_TAG +#define LOG_TAG "Scheduler" #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include "Scheduler.h" @@ -21,6 +23,7 @@ #include <algorithm> #include <cinttypes> #include <cstdint> +#include <functional> #include <memory> #include <numeric> @@ -38,80 +41,56 @@ #include "DispSyncSource.h" #include "EventControlThread.h" #include "EventThread.h" -#include "InjectVSyncSource.h" -#include "LayerInfo.h" #include "OneShotTimer.h" #include "SchedulerUtils.h" #include "SurfaceFlingerProperties.h" -namespace android { - -using namespace android::hardware::configstore; -using namespace android::hardware::configstore::V1_0; -using namespace android::sysprop; +#define RETURN_IF_INVALID_HANDLE(handle, ...) \ + do { \ + if (mConnections.count(handle) == 0) { \ + ALOGE("Invalid connection handle %" PRIuPTR, handle.id); \ + return __VA_ARGS__; \ + } \ + } while (false) -#define RETURN_VALUE_IF_INVALID(value) \ - if (handle == nullptr || mConnections.count(handle->id) == 0) return value -#define RETURN_IF_INVALID() \ - if (handle == nullptr || mConnections.count(handle->id) == 0) return - -std::atomic<int64_t> Scheduler::sNextId = 0; +namespace android { Scheduler::Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function, const scheduler::RefreshRateConfigs& refreshRateConfig) - : mHasSyncFramework(running_without_sync_framework(true)), - mDispSyncPresentTimeOffset(present_time_offset_from_vsync_ns(0)), - mPrimaryHWVsyncEnabled(false), - mHWVsyncAvailable(false), + : mPrimaryDispSync(new impl::DispSync("SchedulerDispSync", + sysprop::running_without_sync_framework(true))), + mEventControlThread(new impl::EventControlThread(std::move(function))), + mSupportKernelTimer(sysprop::support_kernel_idle_timer(false)), mRefreshRateConfigs(refreshRateConfig) { - // Note: We create a local temporary with the real DispSync implementation - // type temporarily so we can initialize it with the configured values, - // before storing it for more generic use using the interface type. - auto primaryDispSync = std::make_unique<impl::DispSync>("SchedulerDispSync"); - primaryDispSync->init(mHasSyncFramework, mDispSyncPresentTimeOffset); - mPrimaryDispSync = std::move(primaryDispSync); - mEventControlThread = std::make_unique<impl::EventControlThread>(function); - - mSetIdleTimerMs = set_idle_timer_ms(0); - mSupportKernelTimer = support_kernel_idle_timer(false); - - mSetTouchTimerMs = set_touch_timer_ms(0); - mSetDisplayPowerTimerMs = set_display_power_timer_ms(0); + using namespace sysprop; char value[PROPERTY_VALUE_MAX]; property_get("debug.sf.set_idle_timer_ms", value, "0"); - int int_value = atoi(value); - if (int_value) { - mSetIdleTimerMs = atoi(value); - } + const int setIdleTimerMs = atoi(value); - if (mSetIdleTimerMs > 0) { - if (mSupportKernelTimer) { - mIdleTimer = std::make_unique<scheduler::OneShotTimer>( - std::chrono::milliseconds(mSetIdleTimerMs), - [this] { kernelIdleTimerCallback(TimerState::Reset); }, - [this] { kernelIdleTimerCallback(TimerState::Expired); }); - } else { - mIdleTimer = std::make_unique<scheduler::OneShotTimer>( - std::chrono::milliseconds(mSetIdleTimerMs), - [this] { idleTimerCallback(TimerState::Reset); }, - [this] { idleTimerCallback(TimerState::Expired); }); - } + if (const auto millis = setIdleTimerMs ? setIdleTimerMs : set_idle_timer_ms(0); millis > 0) { + const auto callback = mSupportKernelTimer ? &Scheduler::kernelIdleTimerCallback + : &Scheduler::idleTimerCallback; + + mIdleTimer.emplace( + std::chrono::milliseconds(millis), + [this, callback] { std::invoke(callback, this, TimerState::Reset); }, + [this, callback] { std::invoke(callback, this, TimerState::Expired); }); mIdleTimer->start(); } - if (mSetTouchTimerMs > 0) { + if (const int64_t millis = set_touch_timer_ms(0); millis > 0) { // Touch events are coming to SF every 100ms, so the timer needs to be higher than that - mTouchTimer = std::make_unique<scheduler::OneShotTimer>( - std::chrono::milliseconds(mSetTouchTimerMs), + mTouchTimer.emplace( + std::chrono::milliseconds(millis), [this] { touchTimerCallback(TimerState::Reset); }, [this] { touchTimerCallback(TimerState::Expired); }); mTouchTimer->start(); } - if (mSetDisplayPowerTimerMs > 0) { - mDisplayPowerTimer = std::make_unique<scheduler::OneShotTimer>( - std::chrono::milliseconds(mSetDisplayPowerTimerMs), + if (const int64_t millis = set_display_power_timer_ms(0); millis > 0) { + mDisplayPowerTimer.emplace( + std::chrono::milliseconds(millis), [this] { displayPowerTimerCallback(TimerState::Reset); }, [this] { displayPowerTimerCallback(TimerState::Expired); }); mDisplayPowerTimer->start(); @@ -121,9 +100,9 @@ Scheduler::Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function, Scheduler::Scheduler(std::unique_ptr<DispSync> primaryDispSync, std::unique_ptr<EventControlThread> eventControlThread, const scheduler::RefreshRateConfigs& configs) - : mHasSyncFramework(false), - mPrimaryDispSync(std::move(primaryDispSync)), + : mPrimaryDispSync(std::move(primaryDispSync)), mEventControlThread(std::move(eventControlThread)), + mSupportKernelTimer(false), mRefreshRateConfigs(configs) {} Scheduler::~Scheduler() { @@ -133,36 +112,39 @@ Scheduler::~Scheduler() { mIdleTimer.reset(); } -sp<Scheduler::ConnectionHandle> Scheduler::createConnection( +DispSync& Scheduler::getPrimaryDispSync() { + return *mPrimaryDispSync; +} + +Scheduler::ConnectionHandle Scheduler::createConnection( const char* connectionName, nsecs_t phaseOffsetNs, nsecs_t offsetThresholdForNextVsync, ResyncCallback resyncCallback, impl::EventThread::InterceptVSyncsCallback interceptCallback) { - const int64_t id = sNextId++; - ALOGV("Creating a connection handle with ID: %" PRId64 "\n", id); + auto eventThread = makeEventThread(connectionName, phaseOffsetNs, offsetThresholdForNextVsync, + std::move(interceptCallback)); + return createConnection(std::move(eventThread), std::move(resyncCallback)); +} + +Scheduler::ConnectionHandle Scheduler::createConnection(std::unique_ptr<EventThread> eventThread, + ResyncCallback&& resyncCallback) { + const ConnectionHandle handle = ConnectionHandle{mNextConnectionHandleId++}; + ALOGV("Creating a connection handle with ID %" PRIuPTR, handle.id); - std::unique_ptr<EventThread> eventThread = - makeEventThread(connectionName, mPrimaryDispSync.get(), phaseOffsetNs, - offsetThresholdForNextVsync, std::move(interceptCallback)); + auto connection = createConnectionInternal(eventThread.get(), std::move(resyncCallback), + ISurfaceComposer::eConfigChangedSuppress); - auto eventThreadConnection = - createConnectionInternal(eventThread.get(), std::move(resyncCallback), - ISurfaceComposer::eConfigChangedSuppress); - mConnections.emplace(id, - std::make_unique<Connection>(new ConnectionHandle(id), - eventThreadConnection, - std::move(eventThread))); - return mConnections[id]->handle; + mConnections.emplace(handle, Connection{connection, std::move(eventThread)}); + return handle; } std::unique_ptr<EventThread> Scheduler::makeEventThread( - const char* connectionName, DispSync* dispSync, nsecs_t phaseOffsetNs, - nsecs_t offsetThresholdForNextVsync, - impl::EventThread::InterceptVSyncsCallback interceptCallback) { - std::unique_ptr<VSyncSource> eventThreadSource = - std::make_unique<DispSyncSource>(dispSync, phaseOffsetNs, offsetThresholdForNextVsync, - true, connectionName); - return std::make_unique<impl::EventThread>(std::move(eventThreadSource), - std::move(interceptCallback), connectionName); + const char* connectionName, nsecs_t phaseOffsetNs, nsecs_t offsetThresholdForNextVsync, + impl::EventThread::InterceptVSyncsCallback&& interceptCallback) { + auto source = std::make_unique<DispSyncSource>(mPrimaryDispSync.get(), phaseOffsetNs, + offsetThresholdForNextVsync, + true /* traceVsync */, connectionName); + return std::make_unique<impl::EventThread>(std::move(source), std::move(interceptCallback), + connectionName); } sp<EventThreadConnection> Scheduler::createConnectionInternal( @@ -172,53 +154,53 @@ sp<EventThreadConnection> Scheduler::createConnectionInternal( } sp<IDisplayEventConnection> Scheduler::createDisplayEventConnection( - const sp<Scheduler::ConnectionHandle>& handle, ResyncCallback resyncCallback, + ConnectionHandle handle, ResyncCallback resyncCallback, ISurfaceComposer::ConfigChanged configChanged) { - RETURN_VALUE_IF_INVALID(nullptr); - return createConnectionInternal(mConnections[handle->id]->thread.get(), - std::move(resyncCallback), configChanged); + RETURN_IF_INVALID_HANDLE(handle, nullptr); + return createConnectionInternal(mConnections[handle].thread.get(), std::move(resyncCallback), + configChanged); } -EventThread* Scheduler::getEventThread(const sp<Scheduler::ConnectionHandle>& handle) { - RETURN_VALUE_IF_INVALID(nullptr); - return mConnections[handle->id]->thread.get(); +EventThread* Scheduler::getEventThread(ConnectionHandle handle) { + RETURN_IF_INVALID_HANDLE(handle, nullptr); + return mConnections[handle].thread.get(); } -sp<EventThreadConnection> Scheduler::getEventConnection(const sp<ConnectionHandle>& handle) { - RETURN_VALUE_IF_INVALID(nullptr); - return mConnections[handle->id]->eventConnection; +sp<EventThreadConnection> Scheduler::getEventConnection(ConnectionHandle handle) { + RETURN_IF_INVALID_HANDLE(handle, nullptr); + return mConnections[handle].connection; } -void Scheduler::hotplugReceived(const sp<Scheduler::ConnectionHandle>& handle, - PhysicalDisplayId displayId, bool connected) { - RETURN_IF_INVALID(); - mConnections[handle->id]->thread->onHotplugReceived(displayId, connected); +void Scheduler::onHotplugReceived(ConnectionHandle handle, PhysicalDisplayId displayId, + bool connected) { + RETURN_IF_INVALID_HANDLE(handle); + mConnections[handle].thread->onHotplugReceived(displayId, connected); } -void Scheduler::onScreenAcquired(const sp<Scheduler::ConnectionHandle>& handle) { - RETURN_IF_INVALID(); - mConnections[handle->id]->thread->onScreenAcquired(); +void Scheduler::onScreenAcquired(ConnectionHandle handle) { + RETURN_IF_INVALID_HANDLE(handle); + mConnections[handle].thread->onScreenAcquired(); } -void Scheduler::onScreenReleased(const sp<Scheduler::ConnectionHandle>& handle) { - RETURN_IF_INVALID(); - mConnections[handle->id]->thread->onScreenReleased(); +void Scheduler::onScreenReleased(ConnectionHandle handle) { + RETURN_IF_INVALID_HANDLE(handle); + mConnections[handle].thread->onScreenReleased(); } -void Scheduler::onConfigChanged(const sp<ConnectionHandle>& handle, PhysicalDisplayId displayId, +void Scheduler::onConfigChanged(ConnectionHandle handle, PhysicalDisplayId displayId, int32_t configId) { - RETURN_IF_INVALID(); - mConnections[handle->id]->thread->onConfigChanged(displayId, configId); + RETURN_IF_INVALID_HANDLE(handle); + mConnections[handle].thread->onConfigChanged(displayId, configId); } -void Scheduler::dump(const sp<Scheduler::ConnectionHandle>& handle, std::string& result) const { - RETURN_IF_INVALID(); - mConnections.at(handle->id)->thread->dump(result); +void Scheduler::dump(ConnectionHandle handle, std::string& result) const { + RETURN_IF_INVALID_HANDLE(handle); + mConnections.at(handle).thread->dump(result); } -void Scheduler::setPhaseOffset(const sp<Scheduler::ConnectionHandle>& handle, nsecs_t phaseOffset) { - RETURN_IF_INVALID(); - mConnections[handle->id]->thread->setPhaseOffset(phaseOffset); +void Scheduler::setPhaseOffset(ConnectionHandle handle, nsecs_t phaseOffset) { + RETURN_IF_INVALID_HANDLE(handle); + mConnections[handle].thread->setPhaseOffset(phaseOffset); } void Scheduler::getDisplayStatInfo(DisplayStatInfo* stats) { @@ -290,7 +272,7 @@ void Scheduler::setRefreshSkipCount(int count) { mPrimaryDispSync->setRefreshSkipCount(count); } -void Scheduler::setVsyncPeriod(const nsecs_t period) { +void Scheduler::setVsyncPeriod(nsecs_t period) { std::lock_guard<std::mutex> lock(mHWVsyncLock); mPrimaryDispSync->setPeriod(period); @@ -301,7 +283,7 @@ void Scheduler::setVsyncPeriod(const nsecs_t period) { } } -void Scheduler::addResyncSample(const nsecs_t timestamp, bool* periodFlushed) { +void Scheduler::addResyncSample(nsecs_t timestamp, bool* periodFlushed) { bool needsHwVsync = false; *periodFlushed = false; { // Scope for the lock @@ -334,10 +316,6 @@ nsecs_t Scheduler::getDispSyncExpectedPresentTime() { return mPrimaryDispSync->expectedPresentTime(); } -void Scheduler::dumpPrimaryDispSync(std::string& result) const { - mPrimaryDispSync->dump(result); -} - std::unique_ptr<scheduler::LayerHistory::LayerHandle> Scheduler::registerLayer( std::string const& name, int windowType) { RefreshRateType refreshRateType = (windowType == InputWindowInfo::TYPE_WALLPAPER) @@ -363,10 +341,6 @@ void Scheduler::setLayerVisibility( mLayerHistory.setVisibility(layerHandle, visible); } -void Scheduler::withPrimaryDispSync(std::function<void(DispSync&)> const& fn) { - fn(*mPrimaryDispSync); -} - void Scheduler::updateFpsBasedOnContent() { auto [refreshRate, isHDR] = mLayerHistory.getDesiredRefreshRateAndHDR(); const uint32_t refreshRateRound = std::round(refreshRate); @@ -393,30 +367,19 @@ void Scheduler::updateFpsBasedOnContent() { changeRefreshRate(newRefreshRateType, ConfigEvent::Changed); } -void Scheduler::setChangeRefreshRateCallback( - const ChangeRefreshRateCallback&& changeRefreshRateCallback) { +void Scheduler::setChangeRefreshRateCallback(ChangeRefreshRateCallback&& callback) { std::lock_guard<std::mutex> lock(mCallbackLock); - mChangeRefreshRateCallback = changeRefreshRateCallback; + mChangeRefreshRateCallback = std::move(callback); } -void Scheduler::setGetCurrentRefreshRateTypeCallback( - const GetCurrentRefreshRateTypeCallback&& getCurrentRefreshRateTypeCallback) { +void Scheduler::setGetCurrentRefreshRateTypeCallback(GetCurrentRefreshRateTypeCallback&& callback) { std::lock_guard<std::mutex> lock(mCallbackLock); - mGetCurrentRefreshRateTypeCallback = getCurrentRefreshRateTypeCallback; + mGetCurrentRefreshRateTypeCallback = std::move(callback); } -void Scheduler::setGetVsyncPeriodCallback(const GetVsyncPeriod&& getVsyncPeriod) { +void Scheduler::setGetVsyncPeriodCallback(GetVsyncPeriod&& callback) { std::lock_guard<std::mutex> lock(mCallbackLock); - mGetVsyncPeriod = getVsyncPeriod; -} - -void Scheduler::updateFrameSkipping(const int64_t skipCount) { - ATRACE_INT("FrameSkipCount", skipCount); - if (mSkipCount != skipCount) { - // Only update DispSync if it hasn't been updated yet. - mPrimaryDispSync->setRefreshSkipCount(skipCount); - mSkipCount = skipCount; - } + mGetVsyncPeriod = std::move(callback); } void Scheduler::resetIdleTimer() { @@ -430,8 +393,8 @@ void Scheduler::notifyTouchEvent() { mTouchTimer->reset(); } - if (mSupportKernelTimer) { - resetIdleTimer(); + if (mSupportKernelTimer && mIdleTimer) { + mIdleTimer->reset(); } // Touch event will boost the refresh rate to performance. @@ -491,11 +454,16 @@ void Scheduler::displayPowerTimerCallback(TimerState state) { ATRACE_INT("ExpiredDisplayPowerTimer", static_cast<int>(state)); } -std::string Scheduler::doDump() { +void Scheduler::dump(std::string& result) const { std::ostringstream stream; - stream << "+ Idle timer interval: " << mSetIdleTimerMs << " ms" << std::endl; - stream << "+ Touch timer interval: " << mSetTouchTimerMs << " ms" << std::endl; - return stream.str(); + if (mIdleTimer) { + stream << "+ Idle timer interval: " << mIdleTimer->interval().count() << " ms\n"; + } + if (mTouchTimer) { + stream << "+ Touch timer interval: " << mTouchTimer->interval().count() << " ms\n"; + } + + result.append(stream.str()); } template <class T> diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 5905ff6eb9..f733317641 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -16,17 +16,17 @@ #pragma once -#include <cstdint> +#include <atomic> #include <functional> #include <memory> +#include <mutex> +#include <optional> +#include <unordered_map> -#include <ui/DisplayStatInfo.h> #include <ui/GraphicTypes.h> -#include "DispSync.h" #include "EventControlThread.h" #include "EventThread.h" -#include "InjectVSyncSource.h" #include "LayerHistory.h" #include "OneShotTimer.h" #include "RefreshRateConfigs.h" @@ -34,122 +34,67 @@ namespace android { -class EventControlThread; +class DispSync; +class FenceTime; +struct DisplayStateInfo; class Scheduler { public: - // Enum to keep track of whether we trigger event to notify choreographer of config changes. - enum class ConfigEvent { None, Changed }; - - // logical or operator with the semantics of at least one of the events is Changed - friend ConfigEvent operator|(const ConfigEvent& first, const ConfigEvent& second) { - if (first == ConfigEvent::Changed) return ConfigEvent::Changed; - if (second == ConfigEvent::Changed) return ConfigEvent::Changed; - return ConfigEvent::None; - } - using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType; + using ConfigEvent = scheduler::RefreshRateConfigEvent; + using GetCurrentRefreshRateTypeCallback = std::function<RefreshRateType()>; using ChangeRefreshRateCallback = std::function<void(RefreshRateType, ConfigEvent)>; using GetVsyncPeriod = std::function<nsecs_t()>; - // Enum to indicate whether to start the transaction early, or at vsync time. + // Indicates whether to start the transaction early, or at vsync time. enum class TransactionStart { EARLY, NORMAL }; - /* The scheduler handle is a BBinder object passed to the client from which we can extract - * an ID for subsequent operations. - */ - class ConnectionHandle : public BBinder { - public: - ConnectionHandle(int64_t id) : id(id) {} - - ~ConnectionHandle() = default; - - const int64_t id; - }; - - class Connection { - public: - Connection(sp<ConnectionHandle> handle, sp<EventThreadConnection> eventConnection, - std::unique_ptr<EventThread> eventThread) - : handle(handle), eventConnection(eventConnection), thread(std::move(eventThread)) {} - - ~Connection() = default; - - sp<ConnectionHandle> handle; - sp<EventThreadConnection> eventConnection; - const std::unique_ptr<EventThread> thread; - }; - - // Stores per-display state about VSYNC. - struct VsyncState { - explicit VsyncState(Scheduler& scheduler) : scheduler(scheduler) {} - - void resync(const GetVsyncPeriod&); - - Scheduler& scheduler; - std::atomic<nsecs_t> lastResyncTime = 0; - }; - - explicit Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function, - const scheduler::RefreshRateConfigs& refreshRateConfig); + Scheduler(impl::EventControlThread::SetVSyncEnabledFunction, + const scheduler::RefreshRateConfigs&); virtual ~Scheduler(); - /** Creates an EventThread connection. */ - sp<ConnectionHandle> createConnection(const char* connectionName, nsecs_t phaseOffsetNs, - nsecs_t offsetThresholdForNextVsync, ResyncCallback, - impl::EventThread::InterceptVSyncsCallback); - - sp<IDisplayEventConnection> createDisplayEventConnection( - const sp<ConnectionHandle>& handle, ResyncCallback, - ISurfaceComposer::ConfigChanged configChanged); - - // Getter methods. - EventThread* getEventThread(const sp<ConnectionHandle>& handle); - - // Provides access to the DispSync object for the primary display. - void withPrimaryDispSync(std::function<void(DispSync&)> const& fn); + DispSync& getPrimaryDispSync(); - sp<EventThreadConnection> getEventConnection(const sp<ConnectionHandle>& handle); + using ConnectionHandle = scheduler::ConnectionHandle; + ConnectionHandle createConnection(const char* connectionName, nsecs_t phaseOffsetNs, + nsecs_t offsetThresholdForNextVsync, ResyncCallback, + impl::EventThread::InterceptVSyncsCallback); - // Should be called when receiving a hotplug event. - void hotplugReceived(const sp<ConnectionHandle>& handle, PhysicalDisplayId displayId, - bool connected); + sp<IDisplayEventConnection> createDisplayEventConnection(ConnectionHandle, ResyncCallback, + ISurfaceComposer::ConfigChanged); - // Should be called after the screen is turned on. - void onScreenAcquired(const sp<ConnectionHandle>& handle); + EventThread* getEventThread(ConnectionHandle); + sp<EventThreadConnection> getEventConnection(ConnectionHandle); - // Should be called before the screen is turned off. - void onScreenReleased(const sp<ConnectionHandle>& handle); + void onHotplugReceived(ConnectionHandle, PhysicalDisplayId, bool connected); + void onConfigChanged(ConnectionHandle, PhysicalDisplayId, int32_t configId); - // Should be called when display config changed - void onConfigChanged(const sp<ConnectionHandle>& handle, PhysicalDisplayId displayId, - int32_t configId); + void onScreenAcquired(ConnectionHandle); + void onScreenReleased(ConnectionHandle); - // Should be called when dumpsys command is received. - void dump(const sp<ConnectionHandle>& handle, std::string& result) const; - - // Offers ability to modify phase offset in the event thread. - void setPhaseOffset(const sp<ConnectionHandle>& handle, nsecs_t phaseOffset); + // Modifies phase offset in the event thread. + void setPhaseOffset(ConnectionHandle, nsecs_t phaseOffset); void getDisplayStatInfo(DisplayStatInfo* stats); void enableHardwareVsync(); void disableHardwareVsync(bool makeUnavailable); + // Resyncs the scheduler to hardware vsync. // If makeAvailable is true, then hardware vsync will be turned on. // Otherwise, if hardware vsync is not already enabled then this method will // no-op. // The period is the vsync period from the current display configuration. void resyncToHardwareVsync(bool makeAvailable, nsecs_t period); - // Creates a callback for resyncing. - ResyncCallback makeResyncCallback(GetVsyncPeriod&& getVsyncPeriod); - void setRefreshSkipCount(int count); + ResyncCallback makeResyncCallback(GetVsyncPeriod&&); + // Passes a vsync sample to DispSync. periodFlushed will be true if // DispSync detected that the vsync period changed, and false otherwise. - void addResyncSample(const nsecs_t timestamp, bool* periodFlushed); - void addPresentFence(const std::shared_ptr<FenceTime>& fenceTime); + void addResyncSample(nsecs_t timestamp, bool* periodFlushed); + void addPresentFence(const std::shared_ptr<FenceTime>&); + void setRefreshSkipCount(int count); void setIgnorePresentFences(bool ignore); nsecs_t getDispSyncExpectedPresentTime(); // Registers the layer in the scheduler, and returns the handle for future references. @@ -165,35 +110,23 @@ public: const std::unique_ptr<scheduler::LayerHistory::LayerHandle>& layerHandle, bool visible); // Updates FPS based on the most content presented. void updateFpsBasedOnContent(); - // Callback that gets invoked when Scheduler wants to change the refresh rate. - void setChangeRefreshRateCallback(const ChangeRefreshRateCallback&& changeRefreshRateCallback); - void setGetCurrentRefreshRateTypeCallback( - const GetCurrentRefreshRateTypeCallback&& getCurrentRefreshRateType); - void setGetVsyncPeriodCallback(const GetVsyncPeriod&& getVsyncPeriod); - // Returns whether idle timer is enabled or not - bool isIdleTimerEnabled() { return mSetIdleTimerMs > 0; } + // Called by Scheduler to change refresh rate. + void setChangeRefreshRateCallback(ChangeRefreshRateCallback&&); + + void setGetCurrentRefreshRateTypeCallback(GetCurrentRefreshRateTypeCallback&&); + void setGetVsyncPeriodCallback(GetVsyncPeriod&&); - // Function that resets the idle timer. + bool isIdleTimerEnabled() const { return mIdleTimer.has_value(); } void resetIdleTimer(); // Function that resets the touch timer. void notifyTouchEvent(); - // Function that sets whether display power mode is normal or not. void setDisplayPowerState(bool normal); - // Returns relevant information about Scheduler for dumpsys purposes. - std::string doDump(); - - // calls DispSync::dump() on primary disp sync - void dumpPrimaryDispSync(std::string& result) const; - -protected: - virtual std::unique_ptr<EventThread> makeEventThread( - const char* connectionName, DispSync* dispSync, nsecs_t phaseOffsetNs, - nsecs_t offsetThresholdForNextVsync, - impl::EventThread::InterceptVSyncsCallback interceptCallback); + void dump(std::string&) const; + void dump(ConnectionHandle, std::string&) const; private: friend class TestableScheduler; @@ -209,81 +142,71 @@ private: const scheduler::RefreshRateConfigs&); // Creates a connection on the given EventThread and forwards the given callbacks. + std::unique_ptr<EventThread> makeEventThread(const char* connectionName, nsecs_t phaseOffsetNs, + nsecs_t offsetThresholdForNextVsync, + impl::EventThread::InterceptVSyncsCallback&&); + + // Create a connection on the given EventThread and forward the resync callback. + ConnectionHandle createConnection(std::unique_ptr<EventThread>, ResyncCallback&&); sp<EventThreadConnection> createConnectionInternal(EventThread*, ResyncCallback&&, ISurfaceComposer::ConfigChanged); - nsecs_t calculateAverage() const; - void updateFrameSkipping(const int64_t skipCount); - // Update feature state machine to given state when corresponding timer resets or expires. void kernelIdleTimerCallback(TimerState); void idleTimerCallback(TimerState); void touchTimerCallback(TimerState); void displayPowerTimerCallback(TimerState); - // Sets vsync period. - void setVsyncPeriod(const nsecs_t period); // handles various timer features to change the refresh rate. template <class T> void handleTimerStateChanged(T* currentState, T newState, bool eventOnContentDetection); - // Calculate the new refresh rate type + + void setVsyncPeriod(nsecs_t period); + RefreshRateType calculateRefreshRateType() REQUIRES(mFeatureStateLock); - // Acquires a lock and calls the ChangeRefreshRateCallback() with given parameters. - void changeRefreshRate(RefreshRateType refreshRateType, ConfigEvent configEvent); + // Acquires a lock and calls the ChangeRefreshRateCallback with given parameters. + void changeRefreshRate(RefreshRateType, ConfigEvent); - // Helper function to calculate error frames - float getErrorFrames(float contentFps, float configFps); + // Stores EventThread associated with a given VSyncSource, and an initial EventThreadConnection. + struct Connection { + sp<EventThreadConnection> connection; + std::unique_ptr<EventThread> thread; + }; - // If fences from sync Framework are supported. - const bool mHasSyncFramework; + ConnectionHandle::Id mNextConnectionHandleId = 0; + std::unordered_map<ConnectionHandle, Connection> mConnections; - // The offset in nanoseconds to use, when DispSync timestamps present fence - // signaling time. - nsecs_t mDispSyncPresentTimeOffset; + std::mutex mHWVsyncLock; + bool mPrimaryHWVsyncEnabled GUARDED_BY(mHWVsyncLock) = false; + bool mHWVsyncAvailable GUARDED_BY(mHWVsyncLock) = false; - // Each connection has it's own ID. This variable keeps track of the count. - static std::atomic<int64_t> sNextId; + // Stores per-display state about VSYNC. + struct VsyncState { + explicit VsyncState(Scheduler& scheduler) : scheduler(scheduler) {} - // Connections are stored in a map <connection ID, connection> for easy retrieval. - std::unordered_map<int64_t, std::unique_ptr<Connection>> mConnections; + void resync(const GetVsyncPeriod&); + + Scheduler& scheduler; + std::atomic<nsecs_t> lastResyncTime = 0; + }; - std::mutex mHWVsyncLock; - bool mPrimaryHWVsyncEnabled GUARDED_BY(mHWVsyncLock); - bool mHWVsyncAvailable GUARDED_BY(mHWVsyncLock); const std::shared_ptr<VsyncState> mPrimaryVsyncState{std::make_shared<VsyncState>(*this)}; std::unique_ptr<DispSync> mPrimaryDispSync; std::unique_ptr<EventControlThread> mEventControlThread; - // TODO(b/113612090): The following set of variables needs to be revised. For now, this is - // a proof of concept. We turn on frame skipping if the difference between the timestamps - // is between 32 and 34ms. We expect this currently for 30fps videos, so we render them at 30Hz. - nsecs_t mPreviousFrameTimestamp = 0; - // Keeping track of whether we are skipping the refresh count. If we want to - // simulate 30Hz rendering, we skip every other frame, and this variable is set - // to 1. - int64_t mSkipCount = 0; - std::array<int64_t, scheduler::ARRAY_SIZE> mTimeDifferences{}; - size_t mCounter = 0; - // Historical information about individual layers. Used for predicting the refresh rate. scheduler::LayerHistory mLayerHistory; - // Timer that records time between requests for next vsync. If the time is higher than a given - // interval, a callback is fired. Set this variable to >0 to use this feature. - int64_t mSetIdleTimerMs = 0; - std::unique_ptr<scheduler::OneShotTimer> mIdleTimer; - // Enables whether to use idle timer callbacks that support the kernel - // timer. - bool mSupportKernelTimer; + // Whether to use idle timer callbacks that support the kernel timer. + const bool mSupportKernelTimer; + // Timer that records time between requests for next vsync. + std::optional<scheduler::OneShotTimer> mIdleTimer; // Timer used to monitor touch events. - int64_t mSetTouchTimerMs = 0; - std::unique_ptr<scheduler::OneShotTimer> mTouchTimer; - + std::optional<scheduler::OneShotTimer> mTouchTimer; // Timer used to monitor display power mode. - int64_t mSetDisplayPowerTimerMs = 0; - std::unique_ptr<scheduler::OneShotTimer> mDisplayPowerTimer; + std::optional<scheduler::OneShotTimer> mDisplayPowerTimer; std::mutex mCallbackLock; GetCurrentRefreshRateTypeCallback mGetCurrentRefreshRateTypeCallback GUARDED_BY(mCallbackLock); diff --git a/services/surfaceflinger/Scheduler/SchedulerUtils.h b/services/surfaceflinger/Scheduler/SchedulerUtils.h index ced1899109..ab0c0ffedd 100644 --- a/services/surfaceflinger/Scheduler/SchedulerUtils.h +++ b/services/surfaceflinger/Scheduler/SchedulerUtils.h @@ -22,13 +22,23 @@ #include <unordered_map> #include <vector> -namespace android { -namespace scheduler { -using namespace std::chrono_literals; +namespace android::scheduler { + +// Opaque handle to scheduler connection. +struct ConnectionHandle { + using Id = std::uintptr_t; + static constexpr Id INVALID_ID = static_cast<Id>(-1); + + Id id = INVALID_ID; -// This number is used to set the size of the arrays in scheduler that hold information -// about layers. -static constexpr size_t ARRAY_SIZE = 30; + explicit operator bool() const { return id != INVALID_ID; } +}; + +inline bool operator==(ConnectionHandle lhs, ConnectionHandle rhs) { + return lhs.id == rhs.id; +} + +using namespace std::chrono_literals; // This number is used to have a place holder for when the screen is not NORMAL/ON. Currently // the config is not visible to SF, and is completely maintained by HWC. However, we would @@ -80,5 +90,15 @@ auto calculate_mode(const T& v) { return static_cast<int>(std::max_element(counts.begin(), counts.end(), compareCounts)->first); } -} // namespace scheduler -} // namespace android
\ No newline at end of file +} // namespace android::scheduler + +namespace std { + +template <> +struct hash<android::scheduler::ConnectionHandle> { + size_t operator()(android::scheduler::ConnectionHandle handle) const { + return hash<android::scheduler::ConnectionHandle::Id>()(handle.id); + } +}; + +} // namespace std diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.cpp b/services/surfaceflinger/Scheduler/VSyncModulator.cpp index f267c99e15..27fd76cba3 100644 --- a/services/surfaceflinger/Scheduler/VSyncModulator.cpp +++ b/services/surfaceflinger/Scheduler/VSyncModulator.cpp @@ -27,8 +27,8 @@ namespace android::scheduler { VSyncModulator::VSyncModulator(Scheduler& scheduler, - const sp<Scheduler::ConnectionHandle>& appConnectionHandle, - const sp<Scheduler::ConnectionHandle>& sfConnectionHandle, + Scheduler::ConnectionHandle appConnectionHandle, + Scheduler::ConnectionHandle sfConnectionHandle, const OffsetsConfig& config) : mScheduler(scheduler), mAppConnectionHandle(appConnectionHandle), diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.h b/services/surfaceflinger/Scheduler/VSyncModulator.h index 636c8c8b28..727cef26fe 100644 --- a/services/surfaceflinger/Scheduler/VSyncModulator.h +++ b/services/surfaceflinger/Scheduler/VSyncModulator.h @@ -56,8 +56,8 @@ public: nsecs_t thresholdForNextVsync; }; - VSyncModulator(Scheduler&, const sp<Scheduler::ConnectionHandle>& appConnectionHandle, - const sp<Scheduler::ConnectionHandle>& sfConnectionHandle, const OffsetsConfig&); + VSyncModulator(Scheduler&, ConnectionHandle appConnectionHandle, + ConnectionHandle sfConnectionHandle, const OffsetsConfig&); void setPhaseOffsets(const OffsetsConfig&) EXCLUDES(mMutex); @@ -92,8 +92,8 @@ private: void updateOffsetsLocked() REQUIRES(mMutex); Scheduler& mScheduler; - const sp<Scheduler::ConnectionHandle> mAppConnectionHandle; - const sp<Scheduler::ConnectionHandle> mSfConnectionHandle; + const ConnectionHandle mAppConnectionHandle; + const ConnectionHandle mSfConnectionHandle; mutable std::mutex mMutex; OffsetsConfig mOffsetsConfig GUARDED_BY(mMutex); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 7a8eb6b2da..bf03b13e77 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2444,8 +2444,8 @@ void SurfaceFlinger::processDisplayHotplugEventsLocked() { } void SurfaceFlinger::dispatchDisplayHotplugEvent(PhysicalDisplayId displayId, bool connected) { - mScheduler->hotplugReceived(mAppConnectionHandle, displayId, connected); - mScheduler->hotplugReceived(mSfConnectionHandle, displayId, connected); + mScheduler->onHotplugReceived(mAppConnectionHandle, displayId, connected); + mScheduler->onHotplugReceived(mSfConnectionHandle, displayId, connected); } sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal( @@ -4256,9 +4256,8 @@ status_t SurfaceFlinger::doDump(int fd, const DumpArgs& args, static const std::unordered_map<std::string, Dumper> dumpers = { {"--display-id"s, dumper(&SurfaceFlinger::dumpDisplayIdentificationData)}, - {"--dispsync"s, dumper([this](std::string& s) { - mScheduler->dumpPrimaryDispSync(s); - })}, + {"--dispsync"s, + dumper([this](std::string& s) { mScheduler->getPrimaryDispSync().dump(s); })}, {"--frame-events"s, dumper(&SurfaceFlinger::dumpFrameEventsLocked)}, {"--latency"s, argsDumper(&SurfaceFlinger::dumpStatsLocked)}, {"--latency-clear"s, argsDumper(&SurfaceFlinger::clearStatsLocked)}, @@ -4365,22 +4364,26 @@ void SurfaceFlinger::appendSfConfigString(std::string& result) const { } void SurfaceFlinger::dumpVSync(std::string& result) const { + mScheduler->dump(result); + StringAppendF(&result, "+ Smart video mode: %s\n\n", mUseSmart90ForVideo ? "on" : "off"); + + mRefreshRateStats.dump(result); + result.append("\n"); + mPhaseOffsets->dump(result); StringAppendF(&result, - " present offset: %9" PRId64 " ns\t VSYNC period: %9" PRId64 " ns\n\n", + " present offset: %9" PRId64 " ns\t VSYNC period: %9" PRId64 " ns\n\n", dispSyncPresentTimeOffset, getVsyncPeriod()); - StringAppendF(&result, "Scheduler enabled."); - StringAppendF(&result, "+ Smart 90 for video detection: %s\n\n", - mUseSmart90ForVideo ? "on" : "off"); StringAppendF(&result, "Allowed Display Configs: "); - for (auto refresh : mRefreshRateConfigs.getRefreshRates()) { - if (refresh.second && isDisplayConfigAllowed(refresh.second->configId)) { - StringAppendF(&result, "%dHz, ", refresh.second->fps); + for (const auto& [type, rate] : mRefreshRateConfigs.getRefreshRates()) { + if (rate && isDisplayConfigAllowed(rate->configId)) { + StringAppendF(&result, "%" PRIu32 " Hz, ", rate->fps); } } StringAppendF(&result, "(config override by backdoor: %s)\n\n", mDebugDisplayConfigSetByBackdoor ? "yes" : "no"); + mScheduler->dump(mAppConnectionHandle, result); } @@ -4583,7 +4586,7 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) co result.append("\n\n"); colorizer.bold(result); - result.append("VSYNC configuration:\n"); + result.append("Scheduler:\n"); colorizer.reset(result); dumpVSync(result); result.append("\n"); @@ -4710,14 +4713,6 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) co result.append("\n"); } - /** - * Scheduler dump state. - */ - result.append("\nScheduler state:\n"); - result.append(mScheduler->doDump() + "\n"); - StringAppendF(&result, "+ Smart video mode: %s\n\n", mUseSmart90ForVideo ? "on" : "off"); - result.append(mRefreshRateStats.doDump() + "\n"); - result.append(mTimeStats->miniDump()); result.append("\n"); } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 27a0f6bbaf..d29d0ecfe3 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -1101,8 +1101,8 @@ private: */ bool mUseSmart90ForVideo = false; std::unique_ptr<Scheduler> mScheduler; - sp<Scheduler::ConnectionHandle> mAppConnectionHandle; - sp<Scheduler::ConnectionHandle> mSfConnectionHandle; + scheduler::ConnectionHandle mAppConnectionHandle; + scheduler::ConnectionHandle mSfConnectionHandle; // Stores phase offsets configured per refresh rate. const std::unique_ptr<scheduler::PhaseOffsets> mPhaseOffsets; diff --git a/services/surfaceflinger/SurfaceFlingerFactory.cpp b/services/surfaceflinger/SurfaceFlingerFactory.cpp index e425b2a953..041ff8d722 100644 --- a/services/surfaceflinger/SurfaceFlingerFactory.cpp +++ b/services/surfaceflinger/SurfaceFlingerFactory.cpp @@ -45,19 +45,13 @@ sp<SurfaceFlinger> createSurfaceFlinger() { Factory() = default; ~Factory() = default; - std::unique_ptr<DispSync> createDispSync(const char* name, bool hasSyncFramework, - int64_t dispSyncPresentTimeOffset) override { - // Note: We create a local temporary with the real DispSync implementation - // type temporarily so we can initialize it with the configured values, - // before storing it for more generic use using the interface type. - auto primaryDispSync = std::make_unique<android::impl::DispSync>(name); - primaryDispSync->init(hasSyncFramework, dispSyncPresentTimeOffset); - return primaryDispSync; + std::unique_ptr<DispSync> createDispSync(const char* name, bool hasSyncFramework) override { + return std::make_unique<android::impl::DispSync>(name, hasSyncFramework); } std::unique_ptr<EventControlThread> createEventControlThread( - std::function<void(bool)> setVSyncEnabled) override { - return std::make_unique<android::impl::EventControlThread>(setVSyncEnabled); + SetVSyncEnabled setVSyncEnabled) override { + return std::make_unique<android::impl::EventControlThread>(std::move(setVSyncEnabled)); } std::unique_ptr<HWComposer> createHWComposer(const std::string& serviceName) override { @@ -74,9 +68,9 @@ sp<SurfaceFlinger> createSurfaceFlinger() { } std::unique_ptr<Scheduler> createScheduler( - std::function<void(bool)> callback, - const scheduler::RefreshRateConfigs& refreshRateConfig) override { - return std::make_unique<Scheduler>(callback, refreshRateConfig); + SetVSyncEnabled setVSyncEnabled, + const scheduler::RefreshRateConfigs& configs) override { + return std::make_unique<Scheduler>(std::move(setVSyncEnabled), configs); } std::unique_ptr<SurfaceInterceptor> createSurfaceInterceptor( diff --git a/services/surfaceflinger/SurfaceFlingerFactory.h b/services/surfaceflinger/SurfaceFlingerFactory.h index c2bc808c8c..5d487e6da5 100644 --- a/services/surfaceflinger/SurfaceFlingerFactory.h +++ b/services/surfaceflinger/SurfaceFlingerFactory.h @@ -64,16 +64,15 @@ class NativeWindowSurface; // of each interface. class Factory { public: - virtual std::unique_ptr<DispSync> createDispSync(const char* name, bool hasSyncFramework, - int64_t dispSyncPresentTimeOffset) = 0; - virtual std::unique_ptr<EventControlThread> createEventControlThread( - std::function<void(bool)> setVSyncEnabled) = 0; + using SetVSyncEnabled = std::function<void(bool)>; + + virtual std::unique_ptr<DispSync> createDispSync(const char* name, bool hasSyncFramework) = 0; + virtual std::unique_ptr<EventControlThread> createEventControlThread(SetVSyncEnabled) = 0; virtual std::unique_ptr<HWComposer> createHWComposer(const std::string& serviceName) = 0; virtual std::unique_ptr<MessageQueue> createMessageQueue() = 0; virtual std::unique_ptr<scheduler::PhaseOffsets> createPhaseOffsets() = 0; - virtual std::unique_ptr<Scheduler> createScheduler( - std::function<void(bool)> callback, - const scheduler::RefreshRateConfigs& refreshRateConfig) = 0; + virtual std::unique_ptr<Scheduler> createScheduler(SetVSyncEnabled, + const scheduler::RefreshRateConfigs&) = 0; virtual std::unique_ptr<SurfaceInterceptor> createSurfaceInterceptor(SurfaceFlinger*) = 0; virtual sp<StartPropertySetThread> createStartPropertySetThread( diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 82dd3c7bd8..2e64a78458 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -124,7 +124,16 @@ public: auto sfEventThread = std::make_unique<mock::EventThread>(); EXPECT_CALL(*eventThread, registerDisplayEventConnection(_)); + EXPECT_CALL(*eventThread, createEventConnection(_, _)) + .WillOnce(Return( + new EventThreadConnection(eventThread.get(), ResyncCallback(), + ISurfaceComposer::eConfigChangedSuppress))); + EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_)); + EXPECT_CALL(*sfEventThread, createEventConnection(_, _)) + .WillOnce(Return( + new EventThreadConnection(sfEventThread.get(), ResyncCallback(), + ISurfaceComposer::eConfigChangedSuppress))); auto primaryDispSync = std::make_unique<mock::DispSync>(); diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp index 8f6f3ecfe4..c858cc0b95 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp @@ -179,7 +179,14 @@ DisplayTransactionTest::~DisplayTransactionTest() { void DisplayTransactionTest::injectMockScheduler() { EXPECT_CALL(*mEventThread, registerDisplayEventConnection(_)); + EXPECT_CALL(*mEventThread, createEventConnection(_, _)) + .WillOnce(Return(new EventThreadConnection(mEventThread, ResyncCallback(), + ISurfaceComposer::eConfigChangedSuppress))); + EXPECT_CALL(*mSFEventThread, registerDisplayEventConnection(_)); + EXPECT_CALL(*mSFEventThread, createEventConnection(_, _)) + .WillOnce(Return(new EventThreadConnection(mSFEventThread, ResyncCallback(), + ISurfaceComposer::eConfigChangedSuppress))); mFlinger.setupScheduler(std::unique_ptr<DispSync>(mPrimaryDispSync), std::unique_ptr<EventControlThread>(mEventControlThread), diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp index 740115ea32..ebcb9d8736 100644 --- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp +++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp @@ -3,14 +3,13 @@ #include <gmock/gmock.h> #include <gtest/gtest.h> - #include <log/log.h> #include <mutex> #include "Scheduler/EventControlThread.h" #include "Scheduler/EventThread.h" -#include "Scheduler/Scheduler.h" +#include "TestableScheduler.h" #include "mock/MockEventThread.h" using testing::_; @@ -34,37 +33,14 @@ protected: MOCK_METHOD0(requestNextVsync, void()); }; - scheduler::RefreshRateConfigs mRefreshRateConfigs; - - /** - * This mock Scheduler class uses implementation of mock::EventThread but keeps everything else - * the same. - */ - class MockScheduler : public android::Scheduler { - public: - MockScheduler(const scheduler::RefreshRateConfigs& refreshRateConfigs, - std::unique_ptr<EventThread> eventThread) - : Scheduler([](bool) {}, refreshRateConfigs), mEventThread(std::move(eventThread)) {} - - std::unique_ptr<EventThread> makeEventThread( - const char* /* connectionName */, DispSync* /* dispSync */, - nsecs_t /* phaseOffsetNs */, nsecs_t /* offsetThresholdForNextVsync */, - impl::EventThread::InterceptVSyncsCallback /* interceptCallback */) override { - return std::move(mEventThread); - } - - MockScheduler() = default; - ~MockScheduler() override = default; - - std::unique_ptr<EventThread> mEventThread; - }; - SchedulerTest(); ~SchedulerTest() override; - sp<Scheduler::ConnectionHandle> mConnectionHandle; + scheduler::RefreshRateConfigs mRefreshRateConfigs; + TestableScheduler mScheduler{mRefreshRateConfigs}; + + Scheduler::ConnectionHandle mConnectionHandle; mock::EventThread* mEventThread; - std::unique_ptr<MockScheduler> mScheduler; sp<MockEventThreadConnection> mEventThreadConnection; }; @@ -73,9 +49,8 @@ SchedulerTest::SchedulerTest() { ::testing::UnitTest::GetInstance()->current_test_info(); ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name()); - std::unique_ptr<mock::EventThread> eventThread = std::make_unique<mock::EventThread>(); + auto eventThread = std::make_unique<mock::EventThread>(); mEventThread = eventThread.get(); - mScheduler = std::make_unique<MockScheduler>(mRefreshRateConfigs, std::move(eventThread)); EXPECT_CALL(*mEventThread, registerDisplayEventConnection(_)).WillOnce(Return(0)); mEventThreadConnection = new MockEventThreadConnection(mEventThread); @@ -85,9 +60,8 @@ SchedulerTest::SchedulerTest() { EXPECT_CALL(*mEventThread, createEventConnection(_, _)) .WillRepeatedly(Return(mEventThreadConnection)); - mConnectionHandle = mScheduler->createConnection("appConnection", 16, 16, ResyncCallback(), - impl::EventThread::InterceptVSyncsCallback()); - EXPECT_TRUE(mConnectionHandle != nullptr); + mConnectionHandle = mScheduler.createConnection(std::move(eventThread)); + EXPECT_TRUE(mConnectionHandle); } SchedulerTest::~SchedulerTest() { @@ -101,92 +75,67 @@ namespace { * Test cases */ -TEST_F(SchedulerTest, testNullPtr) { - // Passing a null pointer for ConnectionHandle is a valid argument. The code doesn't throw any - // exceptions, just gracefully continues. - sp<IDisplayEventConnection> returnedValue; - ASSERT_NO_FATAL_FAILURE( - returnedValue = - mScheduler->createDisplayEventConnection(nullptr, ResyncCallback(), - ISurfaceComposer:: - eConfigChangedSuppress)); - EXPECT_TRUE(returnedValue == nullptr); - EXPECT_TRUE(mScheduler->getEventThread(nullptr) == nullptr); - EXPECT_TRUE(mScheduler->getEventConnection(nullptr) == nullptr); - ASSERT_NO_FATAL_FAILURE(mScheduler->hotplugReceived(nullptr, PHYSICAL_DISPLAY_ID, false)); - ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenAcquired(nullptr)); - ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenReleased(nullptr)); - std::string testString; - ASSERT_NO_FATAL_FAILURE(mScheduler->dump(nullptr, testString)); - EXPECT_TRUE(testString == ""); - ASSERT_NO_FATAL_FAILURE(mScheduler->setPhaseOffset(nullptr, 10)); -} - TEST_F(SchedulerTest, invalidConnectionHandle) { - // Passing an invalid ConnectionHandle is a valid argument. The code doesn't throw any - // exceptions, just gracefully continues. - sp<Scheduler::ConnectionHandle> connectionHandle = new Scheduler::ConnectionHandle(20); + Scheduler::ConnectionHandle handle; - sp<IDisplayEventConnection> returnedValue; + sp<IDisplayEventConnection> connection; ASSERT_NO_FATAL_FAILURE( - returnedValue = - mScheduler->createDisplayEventConnection(connectionHandle, ResyncCallback(), - ISurfaceComposer:: - eConfigChangedSuppress)); - EXPECT_TRUE(returnedValue == nullptr); - EXPECT_TRUE(mScheduler->getEventThread(connectionHandle) == nullptr); - EXPECT_TRUE(mScheduler->getEventConnection(connectionHandle) == nullptr); + connection = mScheduler.createDisplayEventConnection(handle, ResyncCallback(), + ISurfaceComposer:: + eConfigChangedSuppress)); + EXPECT_FALSE(connection); + EXPECT_FALSE(mScheduler.getEventThread(handle)); + EXPECT_FALSE(mScheduler.getEventConnection(handle)); // The EXPECT_CALLS make sure we don't call the functions on the subsequent event threads. EXPECT_CALL(*mEventThread, onHotplugReceived(_, _)).Times(0); - ASSERT_NO_FATAL_FAILURE( - mScheduler->hotplugReceived(connectionHandle, PHYSICAL_DISPLAY_ID, false)); + ASSERT_NO_FATAL_FAILURE(mScheduler.onHotplugReceived(handle, PHYSICAL_DISPLAY_ID, false)); EXPECT_CALL(*mEventThread, onScreenAcquired()).Times(0); - ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenAcquired(connectionHandle)); + ASSERT_NO_FATAL_FAILURE(mScheduler.onScreenAcquired(handle)); EXPECT_CALL(*mEventThread, onScreenReleased()).Times(0); - ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenReleased(connectionHandle)); + ASSERT_NO_FATAL_FAILURE(mScheduler.onScreenReleased(handle)); - std::string testString; + std::string output; EXPECT_CALL(*mEventThread, dump(_)).Times(0); - ASSERT_NO_FATAL_FAILURE(mScheduler->dump(connectionHandle, testString)); - EXPECT_TRUE(testString == ""); + ASSERT_NO_FATAL_FAILURE(mScheduler.dump(handle, output)); + EXPECT_TRUE(output.empty()); EXPECT_CALL(*mEventThread, setPhaseOffset(_)).Times(0); - ASSERT_NO_FATAL_FAILURE(mScheduler->setPhaseOffset(connectionHandle, 10)); + ASSERT_NO_FATAL_FAILURE(mScheduler.setPhaseOffset(handle, 10)); } TEST_F(SchedulerTest, validConnectionHandle) { - sp<IDisplayEventConnection> returnedValue; + sp<IDisplayEventConnection> connection; ASSERT_NO_FATAL_FAILURE( - returnedValue = - mScheduler->createDisplayEventConnection(mConnectionHandle, ResyncCallback(), - ISurfaceComposer:: - eConfigChangedSuppress)); - EXPECT_TRUE(returnedValue != nullptr); - ASSERT_EQ(returnedValue, mEventThreadConnection); + connection = + mScheduler.createDisplayEventConnection(mConnectionHandle, ResyncCallback(), + ISurfaceComposer:: + eConfigChangedSuppress)); + ASSERT_EQ(mEventThreadConnection, connection); - EXPECT_TRUE(mScheduler->getEventThread(mConnectionHandle) != nullptr); - EXPECT_TRUE(mScheduler->getEventConnection(mConnectionHandle) != nullptr); + EXPECT_TRUE(mScheduler.getEventThread(mConnectionHandle)); + EXPECT_TRUE(mScheduler.getEventConnection(mConnectionHandle)); EXPECT_CALL(*mEventThread, onHotplugReceived(PHYSICAL_DISPLAY_ID, false)).Times(1); ASSERT_NO_FATAL_FAILURE( - mScheduler->hotplugReceived(mConnectionHandle, PHYSICAL_DISPLAY_ID, false)); + mScheduler.onHotplugReceived(mConnectionHandle, PHYSICAL_DISPLAY_ID, false)); EXPECT_CALL(*mEventThread, onScreenAcquired()).Times(1); - ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenAcquired(mConnectionHandle)); + ASSERT_NO_FATAL_FAILURE(mScheduler.onScreenAcquired(mConnectionHandle)); EXPECT_CALL(*mEventThread, onScreenReleased()).Times(1); - ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenReleased(mConnectionHandle)); + ASSERT_NO_FATAL_FAILURE(mScheduler.onScreenReleased(mConnectionHandle)); - std::string testString("dump"); - EXPECT_CALL(*mEventThread, dump(testString)).Times(1); - ASSERT_NO_FATAL_FAILURE(mScheduler->dump(mConnectionHandle, testString)); - EXPECT_TRUE(testString != ""); + std::string output("dump"); + EXPECT_CALL(*mEventThread, dump(output)).Times(1); + ASSERT_NO_FATAL_FAILURE(mScheduler.dump(mConnectionHandle, output)); + EXPECT_FALSE(output.empty()); EXPECT_CALL(*mEventThread, setPhaseOffset(10)).Times(1); - ASSERT_NO_FATAL_FAILURE(mScheduler->setPhaseOffset(mConnectionHandle, 10)); + ASSERT_NO_FATAL_FAILURE(mScheduler.setPhaseOffset(mConnectionHandle, 10)); } + } // namespace } // namespace android diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h index 5157cc4e2c..780b608e59 100644 --- a/services/surfaceflinger/tests/unittests/TestableScheduler.h +++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h @@ -19,6 +19,7 @@ #include <gmock/gmock.h> #include <gui/ISurfaceComposer.h> +#include "Scheduler/DispSync.h" #include "Scheduler/EventThread.h" #include "Scheduler/Scheduler.h" @@ -26,24 +27,17 @@ namespace android { class TestableScheduler : public Scheduler { public: + explicit TestableScheduler(const scheduler::RefreshRateConfigs& configs) + : Scheduler([](bool) {}, configs) {} + TestableScheduler(std::unique_ptr<DispSync> primaryDispSync, std::unique_ptr<EventControlThread> eventControlThread, const scheduler::RefreshRateConfigs& configs) : Scheduler(std::move(primaryDispSync), std::move(eventControlThread), configs) {} - // Creates EventThreadConnection with the given eventThread. Creates Scheduler::Connection - // and adds it to the list of connectins. Returns the ConnectionHandle for the - // Scheduler::Connection. This allows plugging in mock::EventThread. - sp<Scheduler::ConnectionHandle> addConnection(std::unique_ptr<EventThread> eventThread) { - sp<EventThreadConnection> eventThreadConnection = - new EventThreadConnection(eventThread.get(), ResyncCallback(), - ISurfaceComposer::eConfigChangedSuppress); - const int64_t id = sNextId++; - mConnections.emplace(id, - std::make_unique<Scheduler::Connection>(new ConnectionHandle(id), - eventThreadConnection, - std::move(eventThread))); - return mConnections[id]->handle; + // Used to inject mock event thread. + ConnectionHandle createConnection(std::unique_ptr<EventThread> eventThread) { + return Scheduler::createConnection(std::move(eventThread), ResyncCallback()); } /* ------------------------------------------------------------------------ diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 27a119b604..9536dd13fb 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -61,7 +61,7 @@ class Factory final : public surfaceflinger::Factory { public: ~Factory() = default; - std::unique_ptr<DispSync> createDispSync(const char*, bool, int64_t) override { + std::unique_ptr<DispSync> createDispSync(const char*, bool) override { // TODO: Use test-fixture controlled factory return nullptr; } @@ -198,8 +198,8 @@ public: new TestableScheduler(std::move(primaryDispSync), std::move(eventControlThread), mFlinger->mRefreshRateConfigs); - mFlinger->mAppConnectionHandle = mScheduler->addConnection(std::move(appEventThread)); - mFlinger->mSfConnectionHandle = mScheduler->addConnection(std::move(sfEventThread)); + mFlinger->mAppConnectionHandle = mScheduler->createConnection(std::move(appEventThread)); + mFlinger->mSfConnectionHandle = mScheduler->createConnection(std::move(sfEventThread)); mFlinger->mScheduler.reset(mScheduler); mFlinger->mVSyncModulator.emplace(*mScheduler, mFlinger->mAppConnectionHandle, |