SF: Adding Mock Display and tests for RefreshRateStats.
Following ag/6005545.
Test: adding SF tests.
Bug: 113612090
Change-Id: Ic4d1ca622f00c4396ae19c44defac0c69fabed1d
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index ad31a40..e34e568 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -44,8 +44,10 @@
"LayerHistoryTest.cpp",
"SchedulerTest.cpp",
"SchedulerUtilsTest.cpp",
+ "RefreshRateStatsTest.cpp",
"TimeStatsTest.cpp",
"mock/DisplayHardware/MockComposer.cpp",
+ "mock/DisplayHardware/MockDisplay.cpp",
"mock/DisplayHardware/MockPowerAdvisor.cpp",
"mock/gui/MockGraphicBufferConsumer.cpp",
"mock/gui/MockGraphicBufferProducer.cpp",
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
new file mode 100644
index 0000000..0384d9d
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
@@ -0,0 +1,212 @@
+/*
+ * 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 "Scheduler/RefreshRateStats.h"
+#include "mock/DisplayHardware/MockDisplay.h"
+
+using namespace std::chrono_literals;
+
+namespace android {
+namespace scheduler {
+
+class RefreshRateStatsTest : public testing::Test {
+protected:
+ static constexpr int CONFIG_ID_90 = 0;
+ static constexpr int CONFIG_ID_60 = 1;
+ static constexpr int64_t VSYNC_90 = 11111111;
+ static constexpr int64_t VSYNC_60 = 16666667;
+
+ RefreshRateStatsTest();
+ ~RefreshRateStatsTest();
+
+ void init(std::vector<std::shared_ptr<const HWC2::Display::Config>> configs);
+
+ std::unique_ptr<RefreshRateStats> mRefreshRateStats;
+};
+
+RefreshRateStatsTest::RefreshRateStatsTest() {
+ 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());
+}
+
+RefreshRateStatsTest::~RefreshRateStatsTest() {
+ 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 RefreshRateStatsTest::init(std::vector<std::shared_ptr<const HWC2::Display::Config>> configs) {
+ mRefreshRateStats = std::make_unique<RefreshRateStats>(configs);
+}
+
+namespace {
+/* ------------------------------------------------------------------------
+ * Test cases
+ */
+TEST_F(RefreshRateStatsTest, canCreateAndDestroyTest) {
+ std::vector<std::shared_ptr<const HWC2::Display::Config>> configs;
+ init(configs);
+
+ // There is one default config, so the refresh rates should have one item.
+ ASSERT_EQ(1, mRefreshRateStats->getTotalTimes().size());
+}
+
+TEST_F(RefreshRateStatsTest, oneConfigTest) {
+ auto display = new Hwc2::mock::Display();
+
+ auto config = HWC2::Display::Config::Builder(*display, CONFIG_ID_90);
+ config.setVsyncPeriod(VSYNC_90);
+ std::vector<std::shared_ptr<const HWC2::Display::Config>> configs;
+ configs.push_back(config.build());
+
+ init(configs);
+
+ std::unordered_map<std::string, int64_t> times = mRefreshRateStats->getTotalTimes();
+ ASSERT_EQ(2, times.size());
+ ASSERT_EQ(0, times["ScreenOff"]);
+ ASSERT_EQ(0, times["90fps"]);
+ // Setting up tests on mobile harness can be flaky with time passing, so testing for
+ // exact time changes can result in flaxy numbers. To avoid that remember old
+ // numbers to make sure the correct values are increasing in the next test.
+ int screenOff = times["ScreenOff"];
+ int ninety = times["90fps"];
+
+ // Screen is off by default.
+ std::this_thread::sleep_for(std::chrono::milliseconds(2));
+ times = mRefreshRateStats->getTotalTimes();
+ ASSERT_LT(screenOff, times["ScreenOff"]);
+ ASSERT_EQ(0, times["90fps"]);
+ screenOff = times["ScreenOff"];
+
+ mRefreshRateStats->setPowerMode(HWC_POWER_MODE_NORMAL);
+ std::this_thread::sleep_for(std::chrono::milliseconds(2));
+ times = mRefreshRateStats->getTotalTimes();
+ ASSERT_EQ(screenOff, times["ScreenOff"]);
+ ASSERT_LT(ninety, times["90fps"]);
+ ninety = times["90fps"];
+
+ mRefreshRateStats->setPowerMode(HWC_POWER_MODE_DOZE);
+ std::this_thread::sleep_for(std::chrono::milliseconds(2));
+ times = mRefreshRateStats->getTotalTimes();
+ ASSERT_LT(screenOff, times["ScreenOff"]);
+ ASSERT_EQ(ninety, times["90fps"]);
+ screenOff = times["ScreenOff"];
+
+ mRefreshRateStats->setConfigMode(CONFIG_ID_90);
+ std::this_thread::sleep_for(std::chrono::milliseconds(2));
+ times = mRefreshRateStats->getTotalTimes();
+ // Because the power mode is not HWC_POWER_MODE_NORMAL, switching the config
+ // does not update refresh rates that come from the config.
+ ASSERT_LT(screenOff, times["ScreenOff"]);
+ ASSERT_EQ(ninety, times["90fps"]);
+}
+
+TEST_F(RefreshRateStatsTest, twoConfigsTest) {
+ auto display = new Hwc2::mock::Display();
+
+ auto config90 = HWC2::Display::Config::Builder(*display, CONFIG_ID_90);
+ config90.setVsyncPeriod(VSYNC_90);
+ std::vector<std::shared_ptr<const HWC2::Display::Config>> configs;
+ configs.push_back(config90.build());
+
+ auto config60 = HWC2::Display::Config::Builder(*display, CONFIG_ID_60);
+ config60.setVsyncPeriod(VSYNC_60);
+ configs.push_back(config60.build());
+
+ init(configs);
+
+ std::unordered_map<std::string, int64_t> times = mRefreshRateStats->getTotalTimes();
+ ASSERT_EQ(3, times.size());
+ ASSERT_EQ(0, times["ScreenOff"]);
+ ASSERT_EQ(0, times["60fps"]);
+ ASSERT_EQ(0, times["90fps"]);
+ // Setting up tests on mobile harness can be flaky with time passing, so testing for
+ // exact time changes can result in flaxy numbers. To avoid that remember old
+ // numbers to make sure the correct values are increasing in the next test.
+ int screenOff = times["ScreenOff"];
+ int sixty = times["60fps"];
+ int ninety = times["90fps"];
+
+ // Screen is off by default.
+ std::this_thread::sleep_for(std::chrono::milliseconds(2));
+ times = mRefreshRateStats->getTotalTimes();
+ ASSERT_LT(screenOff, times["ScreenOff"]);
+ ASSERT_EQ(sixty, times["60fps"]);
+ ASSERT_EQ(ninety, times["90fps"]);
+ screenOff = times["ScreenOff"];
+
+ mRefreshRateStats->setPowerMode(HWC_POWER_MODE_NORMAL);
+ std::this_thread::sleep_for(std::chrono::milliseconds(2));
+ times = mRefreshRateStats->getTotalTimes();
+ ASSERT_EQ(screenOff, times["ScreenOff"]);
+ ASSERT_EQ(sixty, times["60fps"]);
+ ASSERT_LT(ninety, times["90fps"]);
+ ninety = times["90fps"];
+
+ // When power mode is normal, time for configs updates.
+ mRefreshRateStats->setConfigMode(CONFIG_ID_60);
+ std::this_thread::sleep_for(std::chrono::milliseconds(2));
+ times = mRefreshRateStats->getTotalTimes();
+ ASSERT_EQ(screenOff, times["ScreenOff"]);
+ ASSERT_EQ(ninety, times["90fps"]);
+ ASSERT_LT(sixty, times["60fps"]);
+ sixty = times["60fps"];
+
+ mRefreshRateStats->setConfigMode(CONFIG_ID_90);
+ std::this_thread::sleep_for(std::chrono::milliseconds(2));
+ times = mRefreshRateStats->getTotalTimes();
+ ASSERT_EQ(screenOff, times["ScreenOff"]);
+ ASSERT_LT(ninety, times["90fps"]);
+ ASSERT_EQ(sixty, times["60fps"]);
+ ninety = times["90fps"];
+
+ mRefreshRateStats->setConfigMode(CONFIG_ID_60);
+ std::this_thread::sleep_for(std::chrono::milliseconds(2));
+ times = mRefreshRateStats->getTotalTimes();
+ ASSERT_EQ(screenOff, times["ScreenOff"]);
+ ASSERT_EQ(ninety, times["90fps"]);
+ ASSERT_LT(sixty, times["60fps"]);
+ sixty = times["60fps"];
+
+ // Because the power mode is not HWC_POWER_MODE_NORMAL, switching the config
+ // does not update refresh rates that come from the config.
+ mRefreshRateStats->setPowerMode(HWC_POWER_MODE_DOZE);
+ mRefreshRateStats->setConfigMode(CONFIG_ID_90);
+ std::this_thread::sleep_for(std::chrono::milliseconds(2));
+ times = mRefreshRateStats->getTotalTimes();
+ ASSERT_LT(screenOff, times["ScreenOff"]);
+ ASSERT_EQ(ninety, times["90fps"]);
+ ASSERT_EQ(sixty, times["60fps"]);
+ screenOff = times["ScreenOff"];
+
+ mRefreshRateStats->setConfigMode(CONFIG_ID_60);
+ std::this_thread::sleep_for(std::chrono::milliseconds(2));
+ times = mRefreshRateStats->getTotalTimes();
+ ASSERT_LT(screenOff, times["ScreenOff"]);
+ ASSERT_EQ(ninety, times["90fps"]);
+ ASSERT_EQ(sixty, times["60fps"]);
+}
+} // namespace
+} // namespace scheduler
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 687941a..2a8dda6 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -335,11 +335,11 @@
void setExpensiveRenderingExpected(hwc2_display_t, bool) override {}
};
- struct HWC2Display : public HWC2::Display {
+ struct HWC2Display : public HWC2::impl::Display {
HWC2Display(Hwc2::Composer& composer, Hwc2::PowerAdvisor& advisor,
const std::unordered_set<HWC2::Capability>& capabilities, hwc2_display_t id,
HWC2::DisplayType type)
- : HWC2::Display(composer, advisor, capabilities, id, type) {}
+ : HWC2::impl::Display(composer, advisor, capabilities, id, type) {}
~HWC2Display() {
// Prevents a call to disable vsyncs.
mType = HWC2::DisplayType::Invalid;
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplay.cpp b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplay.cpp
new file mode 100644
index 0000000..2ec37c1
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplay.cpp
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+#include "mock/DisplayHardware/MockDisplay.h"
+
+namespace android {
+namespace Hwc2 {
+namespace mock {
+
+// Explicit default instantiation is recommended.
+Display::Display() = default;
+Display::~Display() = default;
+
+} // namespace mock
+} // namespace Hwc2
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplay.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplay.h
new file mode 100644
index 0000000..d7e20c4
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplay.h
@@ -0,0 +1,86 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <gmock/gmock.h>
+
+#include "DisplayHardware/HWC2.h"
+
+using HWC2::Error;
+using HWC2::Layer;
+
+namespace android {
+namespace Hwc2 {
+namespace mock {
+
+class Display : public HWC2::Display {
+public:
+ Display();
+ ~Display();
+
+ MOCK_CONST_METHOD0(getId, hwc2_layer_t());
+ MOCK_CONST_METHOD0(isConnected, bool());
+ MOCK_METHOD1(setConnected, void(bool));
+ MOCK_CONST_METHOD0(getCapabilities, const std::unordered_set<HWC2::DisplayCapability>&());
+
+ MOCK_METHOD0(acceptChanges, Error());
+ MOCK_METHOD1(createLayer, Error(Layer**));
+ MOCK_METHOD1(destroyLayer, Error(Layer*));
+ MOCK_CONST_METHOD1(getActiveConfig, Error(std::shared_ptr<const Config>*));
+ MOCK_CONST_METHOD1(getActiveConfigIndex, Error(int* outIndex));
+ MOCK_METHOD1(getChangedCompositionTypes, Error(std::unordered_map<Layer*, HWC2::Composition>*));
+ MOCK_CONST_METHOD1(getColorModes, Error(std::vector<android::ui::ColorMode>*));
+
+ MOCK_CONST_METHOD0(getSupportedPerFrameMetadata, int32_t());
+ MOCK_CONST_METHOD2(getRenderIntents,
+ Error(android::ui::ColorMode, std::vector<android::ui::RenderIntent>*));
+ MOCK_METHOD2(getDataspaceSaturationMatrix, Error(android::ui::Dataspace, android::mat4*));
+ MOCK_CONST_METHOD0(getConfigs, std::vector<std::shared_ptr<const Config>>());
+
+ MOCK_CONST_METHOD1(getName, Error(std::string*));
+ MOCK_METHOD2(getRequests,
+ Error(HWC2::DisplayRequest*, std::unordered_map<Layer*, HWC2::LayerRequest>*));
+ MOCK_CONST_METHOD1(getType, Error(HWC2::DisplayType*));
+ MOCK_CONST_METHOD1(supportsDoze, Error(bool*));
+ MOCK_CONST_METHOD1(getHdrCapabilities, Error(android::HdrCapabilities*));
+ MOCK_CONST_METHOD3(getDisplayedContentSamplingAttributes,
+ Error(android::ui::PixelFormat*, android::ui::Dataspace*, uint8_t*));
+ MOCK_CONST_METHOD3(setDisplayContentSamplingEnabled, Error(bool, uint8_t, uint64_t));
+ MOCK_CONST_METHOD3(getDisplayedContentSample,
+ Error(uint64_t, uint64_t, android::DisplayedFrameStats*));
+ MOCK_CONST_METHOD1(getReleaseFences,
+ Error(std::unordered_map<Layer*, android::sp<android::Fence>>* outFences));
+ MOCK_METHOD1(present, Error(android::sp<android::Fence>*));
+ MOCK_METHOD1(setActiveConfig, Error(const std::shared_ptr<const HWC2::Display::Config>&));
+ MOCK_METHOD4(setClientTarget,
+ Error(uint32_t, const android::sp<android::GraphicBuffer>&,
+ const android::sp<android::Fence>&, android::ui::Dataspace));
+ MOCK_METHOD2(setColorMode, Error(android::ui::ColorMode, android::ui::RenderIntent));
+ MOCK_METHOD2(setColorTransform, Error(const android::mat4&, android_color_transform_t));
+ MOCK_METHOD2(setOutputBuffer,
+ Error(const android::sp<android::GraphicBuffer>&,
+ const android::sp<android::Fence>&));
+ MOCK_METHOD1(setPowerMode, Error(HWC2::PowerMode));
+ MOCK_METHOD1(setVsyncEnabled, Error(HWC2::Vsync));
+ MOCK_METHOD2(validate, Error(uint32_t*, uint32_t*));
+ MOCK_METHOD4(presentOrValidate,
+ Error(uint32_t*, uint32_t*, android::sp<android::Fence>*, uint32_t*));
+};
+
+} // namespace mock
+} // namespace Hwc2
+} // namespace android
\ No newline at end of file