Cleanup dumpsys for refresh configs for non-90hz devices.
Also add tests exercising RefreshRateConfigs behavior.
Bug: 127846986
Test: libsurfaceflinger_unittest
Test: dumpsys SurfaceFlinger
Change-Id: Idad91cf2a0a0b9661382d1b0011306fb4e36902b
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index cbcc031..9e95f95 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -57,16 +57,23 @@
}
~RefreshRateConfigs() = default;
- const std::unordered_map<RefreshRateType, RefreshRate>& getRefreshRates() {
+ const std::unordered_map<RefreshRateType, std::shared_ptr<RefreshRate>>& getRefreshRates() {
return mRefreshRates;
}
- const RefreshRate& getRefreshRate(RefreshRateType type) { return mRefreshRates[type]; }
+ std::shared_ptr<RefreshRate> getRefreshRate(RefreshRateType type) {
+ const auto& refreshRate = mRefreshRates.find(type);
+ if (refreshRate != mRefreshRates.end()) {
+ return refreshRate->second;
+ }
+ return nullptr;
+ }
private:
void init(const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs) {
// This is the rate that HWC encapsulates right now when the device is in DOZE mode.
mRefreshRates.emplace(RefreshRateType::POWER_SAVING,
- RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0});
+ std::make_shared<RefreshRate>(
+ RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0}));
if (configs.size() < 1) {
ALOGE("Device does not have valid configs. Config size is 0.");
@@ -90,9 +97,10 @@
if (vsyncPeriod != 0) {
const float fps = 1e9 / vsyncPeriod;
mRefreshRates.emplace(RefreshRateType::DEFAULT,
- RefreshRate{configIdToVsyncPeriod[0].first,
- base::StringPrintf("%2.ffps", fps),
- static_cast<uint32_t>(fps)});
+ std::make_shared<RefreshRate>(
+ RefreshRate{configIdToVsyncPeriod[0].first,
+ base::StringPrintf("%2.ffps", fps),
+ static_cast<uint32_t>(fps)}));
}
if (configs.size() < 2) {
@@ -105,13 +113,14 @@
if (vsyncPeriod != 0) {
const float fps = 1e9 / vsyncPeriod;
mRefreshRates.emplace(RefreshRateType::PERFORMANCE,
- RefreshRate{configIdToVsyncPeriod[1].first,
- base::StringPrintf("%2.ffps", fps),
- static_cast<uint32_t>(fps)});
+ std::make_shared<RefreshRate>(
+ RefreshRate{configIdToVsyncPeriod[1].first,
+ base::StringPrintf("%2.ffps", fps),
+ static_cast<uint32_t>(fps)}));
}
}
- std::unordered_map<RefreshRateType, RefreshRate> mRefreshRates;
+ std::unordered_map<RefreshRateType, std::shared_ptr<RefreshRate>> mRefreshRates;
};
} // namespace scheduler
diff --git a/services/surfaceflinger/Scheduler/RefreshRateStats.h b/services/surfaceflinger/Scheduler/RefreshRateStats.h
index 2491081..6b78cee 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateStats.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateStats.h
@@ -85,10 +85,13 @@
std::unordered_map<std::string, int64_t> totalTime;
for (auto [type, config] : mRefreshRateConfigs->getRefreshRates()) {
int64_t totalTimeForConfig = 0;
- if (mConfigModesTotalTime.find(config.configId) != mConfigModesTotalTime.end()) {
- totalTimeForConfig = mConfigModesTotalTime.at(config.configId);
+ if (!config) {
+ continue;
}
- totalTime[config.name] = totalTimeForConfig;
+ if (mConfigModesTotalTime.find(config->configId) != mConfigModesTotalTime.end()) {
+ totalTimeForConfig = mConfigModesTotalTime.at(config->configId);
+ }
+ totalTime[config->name] = totalTimeForConfig;
}
return totalTime;
}
@@ -124,8 +127,11 @@
mConfigModesTotalTime[mode] += timeElapsedMs;
for (const auto& [type, config] : mRefreshRateConfigs->getRefreshRates()) {
- if (config.configId == mode) {
- mTimeStats->recordRefreshRate(config.fps, timeElapsed);
+ if (!config) {
+ continue;
+ }
+ if (config->configId == mode) {
+ mTimeStats->recordRefreshRate(config->fps, timeElapsed);
}
}
}
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index ca94e15..3c98349 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -570,10 +570,11 @@
const auto displayId = getInternalDisplayIdLocked();
LOG_ALWAYS_FATAL_IF(!displayId);
- const auto performanceRefreshRate =
+ const auto& performanceRefreshRate =
mRefreshRateConfigs[*displayId]->getRefreshRate(RefreshRateType::PERFORMANCE);
- if (isConfigAllowed(*displayId, performanceRefreshRate.configId)) {
+ if (performanceRefreshRate &&
+ isConfigAllowed(*displayId, performanceRefreshRate->configId)) {
setRefreshRateTo(RefreshRateType::PERFORMANCE, Scheduler::ConfigEvent::None);
} else {
setRefreshRateTo(RefreshRateType::DEFAULT, Scheduler::ConfigEvent::None);
@@ -1448,17 +1449,24 @@
LOG_ALWAYS_FATAL_IF(!displayId);
const auto displayToken = getInternalDisplayTokenLocked();
- auto desiredConfigId = mRefreshRateConfigs[*displayId]->getRefreshRate(refreshRate).configId;
- const auto display = getDisplayDeviceLocked(displayToken);
- if (desiredConfigId == display->getActiveConfig()) {
+ const auto& refreshRateConfig = mRefreshRateConfigs[*displayId]->getRefreshRate(refreshRate);
+ if (!refreshRateConfig) {
+ ALOGV("Skipping refresh rate change request for unsupported rate.");
return;
}
+ const int desiredConfigId = refreshRateConfig->configId;
+
if (!isConfigAllowed(*displayId, desiredConfigId)) {
ALOGV("Skipping config %d as it is not part of allowed configs", desiredConfigId);
return;
}
+ const auto display = getDisplayDeviceLocked(displayToken);
+ if (desiredConfigId == display->getActiveConfig()) {
+ return;
+ }
+
mPhaseOffsets->setRefreshRateType(refreshRate);
setDesiredActiveConfig(getInternalDisplayTokenLocked(), desiredConfigId, event);
}
@@ -5745,12 +5753,12 @@
int currentConfigIndex = getHwComposer().getActiveConfigIndex(*displayId);
if (!isConfigAllowed(*displayId, currentConfigIndex)) {
for (const auto& [type, config] : mRefreshRateConfigs[*displayId]->getRefreshRates()) {
- if (isConfigAllowed(*displayId, config.configId)) {
+ if (config && isConfigAllowed(*displayId, config->configId)) {
// TODO: we switch to the first allowed config. In the future
// we may want to enhance this logic to pick a similar config
// to the current one
- ALOGV("Old config is not allowed - switching to config %d", config.configId);
- setDesiredActiveConfig(displayToken, config.configId,
+ ALOGV("Old config is not allowed - switching to config %d", config->configId);
+ setDesiredActiveConfig(displayToken, config->configId,
Scheduler::ConfigEvent::Changed);
break;
}
@@ -5760,9 +5768,10 @@
// If idle timer and fps detection are disabled and we are in RefreshRateType::DEFAULT,
// there is no trigger to move to RefreshRateType::PERFORMANCE, even if it is an allowed.
if (!mScheduler->isIdleTimerEnabled() && !mUseSmart90ForVideo) {
- const auto performanceRefreshRate =
+ const auto& performanceRefreshRate =
mRefreshRateConfigs[*displayId]->getRefreshRate(RefreshRateType::PERFORMANCE);
- if (isConfigAllowed(*displayId, performanceRefreshRate.configId)) {
+ if (performanceRefreshRate &&
+ isConfigAllowed(*displayId, performanceRefreshRate->configId)) {
setRefreshRateTo(RefreshRateType::PERFORMANCE, Scheduler::ConfigEvent::Changed);
}
}
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 25ce4ac..12b41fd 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -47,6 +47,7 @@
"LayerMetadataTest.cpp",
"SchedulerTest.cpp",
"SchedulerUtilsTest.cpp",
+ "RefreshRateConfigsTest.cpp",
"RefreshRateStatsTest.cpp",
"TimeStatsTest.cpp",
"mock/DisplayHardware/MockComposer.cpp",
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
new file mode 100644
index 0000000..b218ad6
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -0,0 +1,164 @@
+/*
+ * 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 "SchedulerUnittests"
+
+#include <gmock/gmock.h>
+#include <log/log.h>
+#include <thread>
+
+#include "DisplayHardware/HWC2.h"
+#include "Scheduler/RefreshRateConfigs.h"
+#include "mock/DisplayHardware/MockDisplay.h"
+
+using namespace std::chrono_literals;
+using testing::_;
+
+namespace android {
+namespace scheduler {
+
+using RefreshRateType = RefreshRateConfigs::RefreshRateType;
+using RefreshRate = RefreshRateConfigs::RefreshRate;
+
+class RefreshRateConfigsTest : public testing::Test {
+protected:
+ static constexpr int CONFIG_ID_60 = 0;
+ static constexpr int CONFIG_ID_90 = 1;
+ static constexpr int64_t VSYNC_60 = 16666667;
+ static constexpr int64_t VSYNC_90 = 11111111;
+
+ RefreshRateConfigsTest();
+ ~RefreshRateConfigsTest();
+
+ void assertRatesEqual(const RefreshRate& left, const RefreshRate& right) {
+ ASSERT_EQ(left.configId, right.configId);
+ ASSERT_EQ(left.name, right.name);
+ ASSERT_EQ(left.fps, right.fps);
+ }
+};
+
+RefreshRateConfigsTest::RefreshRateConfigsTest() {
+ 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());
+}
+
+RefreshRateConfigsTest::~RefreshRateConfigsTest() {
+ 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());
+}
+
+namespace {
+/* ------------------------------------------------------------------------
+ * Test cases
+ */
+TEST_F(RefreshRateConfigsTest, zeroDeviceConfigs_storesPowerSavingConfig) {
+ std::vector<std::shared_ptr<const HWC2::Display::Config>> displayConfigs;
+ RefreshRateConfigs configs(displayConfigs);
+
+ // We always store a configuration for screen off.
+ const auto& rates = configs.getRefreshRates();
+ ASSERT_EQ(1, rates.size());
+ const auto& powerSavingRate = rates.find(RefreshRateType::POWER_SAVING);
+ ASSERT_NE(rates.end(), powerSavingRate);
+ ASSERT_EQ(rates.end(), rates.find(RefreshRateType::PERFORMANCE));
+ ASSERT_EQ(rates.end(), rates.find(RefreshRateType::DEFAULT));
+
+ RefreshRate expectedConfig = RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0};
+ assertRatesEqual(expectedConfig, *powerSavingRate->second);
+
+ ASSERT_TRUE(configs.getRefreshRate(RefreshRateType::POWER_SAVING));
+ assertRatesEqual(expectedConfig, *configs.getRefreshRate(RefreshRateType::POWER_SAVING));
+ ASSERT_FALSE(configs.getRefreshRate(RefreshRateType::PERFORMANCE));
+ ASSERT_FALSE(configs.getRefreshRate(RefreshRateType::DEFAULT));
+
+ // Sanity check that getRefreshRate() does not modify the underlying configs.
+ ASSERT_EQ(1, configs.getRefreshRates().size());
+}
+
+TEST_F(RefreshRateConfigsTest, oneDeviceConfig_storesDefaultConfig) {
+ auto display = new Hwc2::mock::Display();
+ std::vector<std::shared_ptr<const HWC2::Display::Config>> displayConfigs;
+ auto config60 = HWC2::Display::Config::Builder(*display, CONFIG_ID_60);
+ config60.setVsyncPeriod(VSYNC_60);
+ displayConfigs.push_back(config60.build());
+ RefreshRateConfigs configs(displayConfigs);
+
+ const auto& rates = configs.getRefreshRates();
+ ASSERT_EQ(2, rates.size());
+ const auto& powerSavingRate = rates.find(RefreshRateType::POWER_SAVING);
+ const auto& defaultRate = rates.find(RefreshRateType::DEFAULT);
+ ASSERT_NE(rates.end(), powerSavingRate);
+ ASSERT_NE(rates.end(), defaultRate);
+ ASSERT_EQ(rates.end(), rates.find(RefreshRateType::PERFORMANCE));
+
+ RefreshRate expectedPowerSavingConfig = RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0};
+ assertRatesEqual(expectedPowerSavingConfig, *powerSavingRate->second);
+ RefreshRate expectedDefaultConfig = RefreshRate{CONFIG_ID_60, "60fps", 60};
+ assertRatesEqual(expectedDefaultConfig, *defaultRate->second);
+
+ ASSERT_TRUE(configs.getRefreshRate(RefreshRateType::POWER_SAVING));
+ assertRatesEqual(expectedPowerSavingConfig,
+ *configs.getRefreshRate(RefreshRateType::POWER_SAVING));
+ ASSERT_TRUE(configs.getRefreshRate(RefreshRateType::DEFAULT));
+ assertRatesEqual(expectedDefaultConfig, *configs.getRefreshRate(RefreshRateType::DEFAULT));
+ ASSERT_FALSE(configs.getRefreshRate(RefreshRateType::PERFORMANCE));
+
+ // Sanity check that getRefreshRate() does not modify the underlying configs.
+ ASSERT_EQ(2, configs.getRefreshRates().size());
+}
+
+TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_storesPerformanceConfig) {
+ auto display = new Hwc2::mock::Display();
+ std::vector<std::shared_ptr<const HWC2::Display::Config>> displayConfigs;
+ auto config60 = HWC2::Display::Config::Builder(*display, CONFIG_ID_60);
+ config60.setVsyncPeriod(VSYNC_60);
+ displayConfigs.push_back(config60.build());
+ auto config90 = HWC2::Display::Config::Builder(*display, CONFIG_ID_90);
+ config90.setVsyncPeriod(VSYNC_90);
+ displayConfigs.push_back(config90.build());
+ RefreshRateConfigs configs(displayConfigs);
+
+ const auto& rates = configs.getRefreshRates();
+ ASSERT_EQ(3, rates.size());
+ const auto& powerSavingRate = rates.find(RefreshRateType::POWER_SAVING);
+ const auto& defaultRate = rates.find(RefreshRateType::DEFAULT);
+ const auto& performanceRate = rates.find(RefreshRateType::PERFORMANCE);
+ ASSERT_NE(rates.end(), powerSavingRate);
+ ASSERT_NE(rates.end(), defaultRate);
+ ASSERT_NE(rates.end(), performanceRate);
+
+ RefreshRate expectedPowerSavingConfig = RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0};
+ assertRatesEqual(expectedPowerSavingConfig, *powerSavingRate->second);
+ RefreshRate expectedDefaultConfig = RefreshRate{CONFIG_ID_60, "60fps", 60};
+ assertRatesEqual(expectedDefaultConfig, *defaultRate->second);
+ RefreshRate expectedPerformanceConfig = RefreshRate{CONFIG_ID_90, "90fps", 90};
+ assertRatesEqual(expectedPerformanceConfig, *performanceRate->second);
+
+ ASSERT_TRUE(configs.getRefreshRate(RefreshRateType::POWER_SAVING));
+ assertRatesEqual(expectedPowerSavingConfig,
+ *configs.getRefreshRate(RefreshRateType::POWER_SAVING));
+ ASSERT_TRUE(configs.getRefreshRate(RefreshRateType::DEFAULT));
+ assertRatesEqual(expectedDefaultConfig, *configs.getRefreshRate(RefreshRateType::DEFAULT));
+ ASSERT_TRUE(configs.getRefreshRate(RefreshRateType::PERFORMANCE));
+ assertRatesEqual(expectedPerformanceConfig,
+ *configs.getRefreshRate(RefreshRateType::PERFORMANCE));
+}
+} // namespace
+} // namespace scheduler
+} // namespace android