Add unit test on sending power hints in SurfaceFlinger
Bug: b/204322192
Test: atest libsurfaceflinger_unittest:libsurfaceflinger_unittest.SurfaceFlingerPowerHintTest#sendDurationsIncludingHwcWaitTime
Change-Id: I0c9ba1abc169ba0b2136663e3937cd93191730ae
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 7ec8e6f..2b3455f 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -95,6 +95,7 @@
#include <cmath>
#include <cstdint>
#include <functional>
+#include <memory>
#include <mutex>
#include <optional>
#include <type_traits>
@@ -113,6 +114,7 @@
#include "DisplayHardware/FramebufferSurface.h"
#include "DisplayHardware/HWComposer.h"
#include "DisplayHardware/Hal.h"
+#include "DisplayHardware/PowerAdvisor.h"
#include "DisplayHardware/VirtualDisplaySurface.h"
#include "DisplayRenderArea.h"
#include "EffectLayer.h"
@@ -327,7 +329,7 @@
mTunnelModeEnabledReporter(new TunnelModeEnabledReporter()),
mInternalDisplayDensity(getDensityFromProperty("ro.sf.lcd_density", true)),
mEmulatedDisplayDensity(getDensityFromProperty("qemu.sf.lcd_density", false)),
- mPowerAdvisor(*this),
+ mPowerAdvisor(std::make_unique<Hwc2::impl::PowerAdvisor>(*this)),
mWindowInfosListenerInvoker(sp<WindowInfosListenerInvoker>::make(*this)) {
ALOGI("Using HWComposer service: %s", mHwcServiceName.c_str());
}
@@ -677,16 +679,16 @@
}
readPersistentProperties();
- mPowerAdvisor.onBootFinished();
- mPowerAdvisor.enablePowerHint(mFlagManager.use_adpf_cpu_hint());
- if (mPowerAdvisor.usePowerHintSession()) {
+ mPowerAdvisor->onBootFinished();
+ mPowerAdvisor->enablePowerHint(mFlagManager.use_adpf_cpu_hint());
+ if (mPowerAdvisor->usePowerHintSession()) {
std::optional<pid_t> renderEngineTid = getRenderEngine().getRenderEngineTid();
std::vector<int32_t> tidList;
tidList.emplace_back(gettid());
if (renderEngineTid.has_value()) {
tidList.emplace_back(*renderEngineTid);
}
- if (!mPowerAdvisor.startPowerHintSession(tidList)) {
+ if (!mPowerAdvisor->startPowerHintSession(tidList)) {
ALOGW("Cannot start power hint session");
}
}
@@ -812,7 +814,7 @@
// set initial conditions (e.g. unblank default device)
initializeDisplays();
- mPowerAdvisor.init();
+ mPowerAdvisor->init();
char primeShaderCache[PROPERTY_VALUE_MAX];
property_get("service.sf.prime_shader_cache", primeShaderCache, "1");
@@ -1284,10 +1286,10 @@
const char* const whence = __func__;
auto future = mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) {
ATRACE_NAME(whence);
- if (mPowerAdvisor.isUsingExpensiveRendering()) {
+ if (mPowerAdvisor->isUsingExpensiveRendering()) {
for (const auto& [_, display] : mDisplays) {
constexpr bool kDisable = false;
- mPowerAdvisor.setExpensiveRenderingExpected(display->getId(), kDisable);
+ mPowerAdvisor->setExpensiveRenderingExpected(display->getId(), kDisable);
}
}
});
@@ -1809,7 +1811,7 @@
if (hint == FrameHint::kActive) {
mScheduler->resetIdleTimer();
}
- mPowerAdvisor.notifyDisplayUpdateImminent();
+ mPowerAdvisor->notifyDisplayUpdateImminent();
mScheduler->scheduleFrame();
}
@@ -1979,7 +1981,7 @@
bool SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expectedVsyncTime)
FTL_FAKE_GUARD(kMainThreadContext) {
// we set this once at the beginning of commit to ensure consistency throughout the whole frame
- mPowerHintSessionData.sessionEnabled = mPowerAdvisor.usePowerHintSession();
+ mPowerHintSessionData.sessionEnabled = mPowerAdvisor->usePowerHintSession();
if (mPowerHintSessionData.sessionEnabled) {
mPowerHintSessionData.commitStart = systemTime();
}
@@ -1998,8 +2000,8 @@
mScheduledPresentTime = expectedVsyncTime;
if (mPowerHintSessionData.sessionEnabled) {
- mPowerAdvisor.setTargetWorkDuration(mExpectedPresentTime -
- mPowerHintSessionData.commitStart);
+ mPowerAdvisor->setTargetWorkDuration(mExpectedPresentTime -
+ mPowerHintSessionData.commitStart);
}
const auto vsyncIn = [&] {
if (!ATRACE_ENABLED()) return 0.f;
@@ -2263,7 +2265,7 @@
if (mPowerHintSessionData.sessionEnabled) {
const nsecs_t flingerDuration =
(mPowerHintSessionData.presentEnd - mPowerHintSessionData.commitStart);
- mPowerAdvisor.sendActualWorkDuration(flingerDuration, mPowerHintSessionData.presentEnd);
+ mPowerAdvisor->sendActualWorkDuration(flingerDuration, mPowerHintSessionData.presentEnd);
}
}
@@ -2918,7 +2920,7 @@
builder.setPixels(resolution);
builder.setIsSecure(state.isSecure);
- builder.setPowerAdvisor(&mPowerAdvisor);
+ builder.setPowerAdvisor(mPowerAdvisor.get());
builder.setName(state.displayName);
auto compositionDisplay = getCompositionEngine().createDisplay(builder.build());
compositionDisplay->setLayerCachingEnabled(mLayerCachingEnabled);
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 910c5bb..07da731 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -1383,7 +1383,7 @@
sp<os::IInputFlinger> mInputFlinger;
InputWindowCommands mInputWindowCommands;
- Hwc2::impl::PowerAdvisor mPowerAdvisor;
+ std::unique_ptr<Hwc2::PowerAdvisor> mPowerAdvisor;
void enableRefreshRateOverlay(bool enable) REQUIRES(mStateLock);
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index cc9d48c..7823363 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -103,6 +103,7 @@
"SurfaceFlinger_HotplugTest.cpp",
"SurfaceFlinger_NotifyPowerBoostTest.cpp",
"SurfaceFlinger_OnInitializeDisplaysTest.cpp",
+ "SurfaceFlinger_PowerHintTest.cpp",
"SurfaceFlinger_SetDisplayStateTest.cpp",
"SurfaceFlinger_SetPowerModeInternalTest.cpp",
"SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp",
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 15c9d19..c541b92 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -113,8 +113,9 @@
mFlinger.setupTimeStats(std::shared_ptr<TimeStats>(mTimeStats));
mComposer = new Hwc2::mock::Composer();
+ mPowerAdvisor = new Hwc2::mock::PowerAdvisor();
mFlinger.setupComposer(std::unique_ptr<Hwc2::Composer>(mComposer));
-
+ mFlinger.setupPowerAdvisor(std::unique_ptr<Hwc2::PowerAdvisor>(mPowerAdvisor));
mFlinger.mutableMaxRenderTargetSize() = 16384;
}
@@ -188,7 +189,7 @@
Hwc2::mock::Composer* mComposer = nullptr;
renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine();
mock::TimeStats* mTimeStats = new mock::TimeStats();
- Hwc2::mock::PowerAdvisor mPowerAdvisor;
+ Hwc2::mock::PowerAdvisor* mPowerAdvisor = nullptr;
sp<Fence> mClientTargetAcquireFence = Fence::NO_FENCE;
@@ -300,7 +301,7 @@
.setId(DEFAULT_DISPLAY_ID)
.setPixels({DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT})
.setIsSecure(Derived::IS_SECURE)
- .setPowerAdvisor(&test->mPowerAdvisor)
+ .setPowerAdvisor(test->mPowerAdvisor)
.setName(std::string("Injected display for ") +
test_info->test_case_name() + "." + test_info->name())
.build();
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_PowerHintTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_PowerHintTest.cpp
new file mode 100644
index 0000000..0a157c4
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_PowerHintTest.cpp
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2022 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 "SurfaceFlingerPowerHintTest"
+
+#include <compositionengine/Display.h>
+#include <compositionengine/mock/DisplaySurface.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <renderengine/mock/RenderEngine.h>
+#include <algorithm>
+#include <chrono>
+#include <memory>
+#include "TestableSurfaceFlinger.h"
+#include "mock/DisplayHardware/MockComposer.h"
+#include "mock/DisplayHardware/MockPowerAdvisor.h"
+#include "mock/MockEventThread.h"
+#include "mock/MockTimeStats.h"
+#include "mock/MockVsyncController.h"
+#include "mock/system/window/MockNativeWindow.h"
+
+using namespace android;
+using namespace android::Hwc2::mock;
+using namespace android::hardware::power;
+using namespace std::chrono_literals;
+using namespace testing;
+
+namespace android {
+namespace {
+using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector;
+using FakeDisplayDeviceInjector = TestableSurfaceFlinger::FakeDisplayDeviceInjector;
+
+constexpr hal::HWDisplayId HWC_DISPLAY = FakeHwcDisplayInjector::DEFAULT_HWC_DISPLAY_ID;
+constexpr PhysicalDisplayId DEFAULT_DISPLAY_ID = PhysicalDisplayId::fromPort(42u);
+constexpr int DEFAULT_DISPLAY_WIDTH = 1920;
+constexpr int DEFAULT_DISPLAY_HEIGHT = 1024;
+
+class SurfaceFlingerPowerHintTest : public Test {
+public:
+ void SetUp() override;
+
+ void setupScheduler();
+
+protected:
+ TestableSurfaceFlinger mFlinger;
+ renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine();
+ sp<DisplayDevice> mDisplay;
+ sp<compositionengine::mock::DisplaySurface> mDisplaySurface =
+ new compositionengine::mock::DisplaySurface();
+ mock::NativeWindow* mNativeWindow = new mock::NativeWindow();
+ mock::TimeStats* mTimeStats = new mock::TimeStats();
+ Hwc2::mock::PowerAdvisor* mPowerAdvisor = nullptr;
+ Hwc2::mock::Composer* mComposer = nullptr;
+};
+
+void SurfaceFlingerPowerHintTest::SetUp() {
+ setupScheduler();
+ mComposer = new Hwc2::mock::Composer();
+ mPowerAdvisor = new Hwc2::mock::PowerAdvisor();
+ mFlinger.setupRenderEngine(std::unique_ptr<renderengine::RenderEngine>(mRenderEngine));
+ mFlinger.setupTimeStats(std::shared_ptr<TimeStats>(mTimeStats));
+ mFlinger.setupComposer(std::unique_ptr<Hwc2::Composer>(mComposer));
+ mFlinger.setupPowerAdvisor(std::unique_ptr<Hwc2::PowerAdvisor>(mPowerAdvisor));
+ static constexpr bool kIsPrimary = true;
+ FakeHwcDisplayInjector(DEFAULT_DISPLAY_ID, hal::DisplayType::PHYSICAL, kIsPrimary)
+ .setPowerMode(hal::PowerMode::ON)
+ .inject(&mFlinger, mComposer);
+ auto compostionEngineDisplayArgs =
+ compositionengine::DisplayCreationArgsBuilder()
+ .setId(DEFAULT_DISPLAY_ID)
+ .setPixels({DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT})
+ .setPowerAdvisor(mPowerAdvisor)
+ .setName("injected display")
+ .build();
+ auto compositionDisplay =
+ compositionengine::impl::createDisplay(mFlinger.getCompositionEngine(),
+ std::move(compostionEngineDisplayArgs));
+ mDisplay =
+ FakeDisplayDeviceInjector(mFlinger, compositionDisplay,
+ ui::DisplayConnectionType::Internal, HWC_DISPLAY, kIsPrimary)
+ .setDisplaySurface(mDisplaySurface)
+ .setNativeWindow(mNativeWindow)
+ .setPowerMode(hal::PowerMode::ON)
+ .inject();
+}
+
+void SurfaceFlingerPowerHintTest::setupScheduler() {
+ auto eventThread = std::make_unique<mock::EventThread>();
+ auto sfEventThread = std::make_unique<mock::EventThread>();
+
+ EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
+ EXPECT_CALL(*eventThread, createEventConnection(_, _))
+ .WillOnce(Return(new EventThreadConnection(eventThread.get(), /*callingUid=*/0,
+ ResyncCallback())));
+
+ EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
+ EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
+ .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), /*callingUid=*/0,
+ ResyncCallback())));
+
+ auto vsyncController = std::make_unique<mock::VsyncController>();
+ auto vsyncTracker = std::make_unique<mock::VSyncTracker>();
+
+ EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
+ EXPECT_CALL(*vsyncTracker, currentPeriod())
+ .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD));
+ EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
+
+ mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker),
+ std::move(eventThread), std::move(sfEventThread),
+ TestableSurfaceFlinger::SchedulerCallbackImpl::kNoOp,
+ TestableSurfaceFlinger::kTwoDisplayModes);
+}
+
+TEST_F(SurfaceFlingerPowerHintTest, sendDurationsIncludingHwcWaitTime) {
+ ON_CALL(*mPowerAdvisor, usePowerHintSession()).WillByDefault(Return(true));
+
+ const std::chrono::nanoseconds mockVsyncPeriod = 15ms;
+ const std::chrono::nanoseconds expectedTargetTime = 14ms;
+ EXPECT_CALL(*mPowerAdvisor, setTargetWorkDuration(Gt(expectedTargetTime.count()))).Times(1);
+
+ const nsecs_t now = systemTime();
+ const std::chrono::nanoseconds mockHwcRunTime = 20ms;
+ EXPECT_CALL(*mDisplaySurface,
+ prepareFrame(compositionengine::DisplaySurface::CompositionType::Hwc))
+ .Times(1);
+ EXPECT_CALL(*mComposer, presentOrValidateDisplay(HWC_DISPLAY, _, _, _, _, _))
+ .WillOnce([mockHwcRunTime] {
+ std::this_thread::sleep_for(mockHwcRunTime);
+ return hardware::graphics::composer::V2_1::Error::NONE;
+ });
+ EXPECT_CALL(*mPowerAdvisor,
+ sendActualWorkDuration(Gt(mockHwcRunTime.count()),
+ Gt(now + mockHwcRunTime.count())))
+ .Times(1);
+ static constexpr bool kVsyncId = 123; // arbitrary
+ mFlinger.commitAndComposite(now, kVsyncId, now + mockVsyncPeriod.count());
+}
+
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index bf2465f..866d9eb 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -17,6 +17,7 @@
#pragma once
#include <algorithm>
+#include <chrono>
#include <variant>
#include <compositionengine/Display.h>
@@ -200,6 +201,10 @@
std::make_unique<impl::HWComposer>(std::move(composer)));
}
+ void setupPowerAdvisor(std::unique_ptr<Hwc2::PowerAdvisor> powerAdvisor) {
+ mFlinger->mPowerAdvisor = std::move(powerAdvisor);
+ }
+
void setupTimeStats(const std::shared_ptr<TimeStats>& timeStats) {
mFlinger->mCompositionEngine->setTimeStats(timeStats);
}
@@ -328,11 +333,26 @@
/* ------------------------------------------------------------------------
* Forwarding for functions being tested
*/
+
+ nsecs_t commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expectedVSyncTime) {
+ mFlinger->commit(frameTime, vsyncId, expectedVSyncTime);
+ return frameTime;
+ }
+
+ nsecs_t commit(nsecs_t frameTime, int64_t vsyncId) {
+ std::chrono::nanoseconds period = 10ms;
+ return commit(frameTime, vsyncId, frameTime + period.count());
+ }
+
nsecs_t commit() {
const nsecs_t now = systemTime();
const nsecs_t expectedVsyncTime = now + 10'000'000;
- mFlinger->commit(now, kVsyncId, expectedVsyncTime);
- return now;
+ return commit(now, kVsyncId, expectedVsyncTime);
+ }
+
+ void commitAndComposite(const nsecs_t frameTime, const int64_t vsyncId,
+ const nsecs_t expectedVsyncTime) {
+ mFlinger->composite(commit(frameTime, vsyncId, expectedVsyncTime), kVsyncId);
}
void commitAndComposite() { mFlinger->composite(commit(), kVsyncId); }
@@ -458,11 +478,6 @@
mFlinger->onActiveDisplayChangedLocked(activeDisplay);
}
- auto commit(nsecs_t frameTime, int64_t vsyncId) {
- const nsecs_t expectedVsyncTime = frameTime + 10'000'000;
- mFlinger->commit(frameTime, vsyncId, expectedVsyncTime);
- }
-
auto createLayer(LayerCreationArgs& args, sp<IBinder>* outHandle,
const sp<IBinder>& parentHandle, int32_t* outLayerId,
const sp<Layer>& parentLayer, uint32_t* outTransformHint) {
@@ -515,7 +530,6 @@
auto& mutablePhysicalDisplayTokens() { return mFlinger->mPhysicalDisplayTokens; }
auto& mutableTexturePool() { return mFlinger->mTexturePool; }
auto& mutableTransactionFlags() { return mFlinger->mTransactionFlags; }
- auto& mutablePowerAdvisor() { return mFlinger->mPowerAdvisor; }
auto& mutableDebugDisableHWC() { return mFlinger->mDebugDisableHWC; }
auto& mutableMaxRenderTargetSize() { return mFlinger->mMaxRenderTargetSize; }