diff options
author | Midas Chien <midaschieh@google.com> | 2020-06-19 05:31:09 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2020-06-19 05:31:09 +0000 |
commit | 6cd3197b007927b3d053587aec8846aebeb6c03e (patch) | |
tree | a72522643cd1b76e20ed32c58e0dc10afe6e6895 | |
parent | bf601b04404e73071ec872745a8826afb587ea4c (diff) | |
parent | b9afd79e014b1adc987f5bad7608a52077707bc8 (diff) | |
download | native-6cd3197b007927b3d053587aec8846aebeb6c03e.tar.gz |
Merge "Move toggling of kernel idle timer to SF" into rvc-dev
5 files changed, 109 insertions, 5 deletions
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp index 6dbff14244..a6036c6b37 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp @@ -595,4 +595,28 @@ float RefreshRateConfigs::findClosestKnownFrameRate(float frameRate) const { return distance1 < distance2 ? *lowerBound : *std::prev(lowerBound); } +RefreshRateConfigs::KernelIdleTimerAction RefreshRateConfigs::getIdleTimerAction() const { + std::lock_guard lock(mLock); + const auto& deviceMin = getMinRefreshRate(); + const auto& minByPolicy = getMinRefreshRateByPolicyLocked(); + const auto& maxByPolicy = getMaxRefreshRateByPolicyLocked(); + + // Kernel idle timer will set the refresh rate to the device min. If DisplayManager says that + // the min allowed refresh rate is higher than the device min, we do not want to enable the + // timer. + if (deviceMin < minByPolicy) { + return RefreshRateConfigs::KernelIdleTimerAction::TurnOff; + } + if (minByPolicy == maxByPolicy) { + // Do not sent the call to toggle off kernel idle timer if the device min and policy min and + // max are all the same. This saves us extra unnecessary calls to sysprop. + if (deviceMin == minByPolicy) { + return RefreshRateConfigs::KernelIdleTimerAction::NoChange; + } + return RefreshRateConfigs::KernelIdleTimerAction::TurnOff; + } + // Turn on the timer in all other cases. + return RefreshRateConfigs::KernelIdleTimerAction::TurnOn; +} + } // namespace android::scheduler diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h index 584a5e7c72..8a51b85207 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h @@ -82,6 +82,8 @@ public: return configId != other.configId || hwcConfig != other.hwcConfig; } + bool operator<(const RefreshRate& other) const { return getFps() < other.getFps(); } + bool operator==(const RefreshRate& other) const { return !(*this != other); } private: @@ -271,6 +273,17 @@ public: RefreshRateConfigs(const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs, HwcConfigIndexType currentConfigId); + // Class to enumerate options around toggling the kernel timer on and off. We have an option + // for no change to avoid extra calls to kernel. + enum class KernelIdleTimerAction { + NoChange, // Do not change the idle timer. + TurnOff, // Turn off the idle timer. + TurnOn // Turn on the idle timer. + }; + // Checks whether kernel idle timer should be active depending the policy decisions around + // refresh rates. + KernelIdleTimerAction getIdleTimerAction() const; + private: friend class RefreshRateConfigsTest; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index ef315e24c6..2e019039f8 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -23,6 +23,7 @@ #include "SurfaceFlinger.h" +#include <android-base/properties.h> #include <android/configuration.h> #include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h> #include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h> @@ -444,6 +445,9 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI } useFrameRateApi = use_frame_rate_api(true); + + mKernelIdleTimerEnabled = mSupportKernelIdleTimer = sysprop::support_kernel_idle_timer(false); + base::SetProperty(KERNEL_IDLE_TIMER_PROP, mKernelIdleTimerEnabled ? "true" : "false"); } SurfaceFlinger::~SurfaceFlinger() = default; @@ -5355,8 +5359,7 @@ void SurfaceFlinger::kernelTimerChanged(bool expired) { const auto& min = mRefreshRateConfigs->getMinRefreshRate(); if (current != min) { - const auto kernelTimerEnabled = property_get_bool(KERNEL_IDLE_TIMER_PROP, false); - const bool timerExpired = kernelTimerEnabled && expired; + const bool timerExpired = mKernelIdleTimerEnabled && expired; if (Mutex::Autolock lock(mStateLock); mRefreshRateOverlay) { mRefreshRateOverlay->changeRefreshRate(timerExpired ? min : current); @@ -5366,6 +5369,35 @@ void SurfaceFlinger::kernelTimerChanged(bool expired) { })); } +void SurfaceFlinger::toggleKernelIdleTimer() { + using KernelIdleTimerAction = scheduler::RefreshRateConfigs::KernelIdleTimerAction; + + // If the support for kernel idle timer is disabled in SF code, don't do anything. + if (!mSupportKernelIdleTimer) { + return; + } + const KernelIdleTimerAction action = mRefreshRateConfigs->getIdleTimerAction(); + + switch (action) { + case KernelIdleTimerAction::TurnOff: + if (mKernelIdleTimerEnabled) { + ATRACE_INT("KernelIdleTimer", 0); + base::SetProperty(KERNEL_IDLE_TIMER_PROP, "false"); + mKernelIdleTimerEnabled = false; + } + break; + case KernelIdleTimerAction::TurnOn: + if (!mKernelIdleTimerEnabled) { + ATRACE_INT("KernelIdleTimer", 1); + base::SetProperty(KERNEL_IDLE_TIMER_PROP, "true"); + mKernelIdleTimerEnabled = true; + } + break; + case KernelIdleTimerAction::NoChange: + break; + } +} + // A simple RAII class to disconnect from an ANativeWindow* when it goes out of scope class WindowDisconnector { public: @@ -5992,14 +6024,14 @@ status_t SurfaceFlinger::setDesiredDisplayConfigSpecsInternal( currentPolicy.primaryRange.max, currentPolicy.appRequestRange.min, currentPolicy.appRequestRange.max); - // TODO(b/140204874): This hack triggers a notification that something has changed, so - // that listeners that care about a change in allowed configs can get the notification. - // Giving current ActiveConfig so that most other listeners would just drop the event + // TODO(b/140204874): Leave the event in until we do proper testing with all apps that might + // be depending in this callback. const nsecs_t vsyncPeriod = mRefreshRateConfigs->getRefreshRateFromConfigId(display->getActiveConfig()) .getVsyncPeriod(); mScheduler->onPrimaryDisplayConfigChanged(mAppConnectionHandle, display->getId()->value, display->getActiveConfig(), vsyncPeriod); + toggleKernelIdleTimer(); auto configId = mScheduler->getPreferredConfigId(); auto& preferredRefreshRate = configId diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 38db62be1d..ccaeb2d858 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -535,6 +535,13 @@ private: void repaintEverythingForHWC() override; // Called when kernel idle timer has expired. Used to update the refresh rate overlay. void kernelTimerChanged(bool expired) override; + // Toggles the kernel idle timer on or off depending the policy decisions around refresh rates. + void toggleKernelIdleTimer(); + // Keeps track of whether the kernel idle timer is currently enabled, so we don't have to + // make calls to sys prop each time. + bool mKernelIdleTimerEnabled = false; + // Keeps track of whether the kernel timer is supported on the SF side. + bool mSupportKernelIdleTimer = false; /* ------------------------------------------------------------------------ * Message handling */ diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp index f24575e351..fed591cb19 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp @@ -1420,6 +1420,34 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_KnownFrameRate) { } } +TEST_F(RefreshRateConfigsTest, testComparisonOperator) { + EXPECT_TRUE(mExpected60Config < mExpected90Config); + EXPECT_FALSE(mExpected60Config < mExpected60Config); + EXPECT_FALSE(mExpected90Config < mExpected90Config); +} + +TEST_F(RefreshRateConfigsTest, testKernelIdleTimerAction) { + using KernelIdleTimerAction = scheduler::RefreshRateConfigs::KernelIdleTimerAction; + + auto refreshRateConfigs = + std::make_unique<RefreshRateConfigs>(m60_90Device, + /*currentConfigId=*/HWC_CONFIG_ID_90); + // SetPolicy(60, 90), current 90Hz => TurnOn. + EXPECT_EQ(KernelIdleTimerAction::TurnOn, refreshRateConfigs->getIdleTimerAction()); + + // SetPolicy(60, 90), current 60Hz => TurnOn. + ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {60, 90}}), 0); + EXPECT_EQ(KernelIdleTimerAction::TurnOn, refreshRateConfigs->getIdleTimerAction()); + + // SetPolicy(60, 60), current 60Hz => NoChange, avoid extra calls. + ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {60, 60}}), 0); + EXPECT_EQ(KernelIdleTimerAction::NoChange, refreshRateConfigs->getIdleTimerAction()); + + // SetPolicy(90, 90), current 90Hz => TurnOff. + ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {90, 90}}), 0); + EXPECT_EQ(KernelIdleTimerAction::TurnOff, refreshRateConfigs->getIdleTimerAction()); +} + } // namespace } // namespace scheduler } // namespace android |