1 /*
2  * Copyright 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #undef LOG_TAG
18 #define LOG_TAG "PowerAdvisorTest"
19 
20 #include <DisplayHardware/PowerAdvisor.h>
21 #include <android_os.h>
22 #include <binder/Status.h>
23 #include <com_android_graphics_surfaceflinger_flags.h>
24 #include <common/FlagManager.h>
25 #include <common/test/FlagUtils.h>
26 #include <gmock/gmock.h>
27 #include <gtest/gtest.h>
28 #include <powermanager/PowerHalWrapper.h>
29 #include <ui/DisplayId.h>
30 #include <chrono>
31 #include <future>
32 #include "TestableSurfaceFlinger.h"
33 #include "mock/DisplayHardware/MockPowerHalController.h"
34 #include "mock/DisplayHardware/MockPowerHintSessionWrapper.h"
35 
36 using namespace android;
37 using namespace android::Hwc2::mock;
38 using namespace android::hardware::power;
39 using namespace std::chrono_literals;
40 using namespace testing;
41 using namespace android::power;
42 
43 namespace android::Hwc2::impl {
44 
45 class PowerAdvisorTest : public testing::Test {
46 public:
47     void SetUp() override;
48     void SetUpFmq(bool usesSharedEventFlag, bool isQueueFull);
49     void startPowerHintSession(bool returnValidSession = true);
50     void fakeBasicFrameTiming(TimePoint startTime, Duration vsyncPeriod);
51     void setExpectedTiming(Duration totalFrameTargetDuration, TimePoint expectedPresentTime);
52     Duration getFenceWaitDelayDuration(bool skipValidate);
53     Duration getErrorMargin();
54     void setTimingTestingMode(bool testinMode);
55     void allowReportActualToAcquireMutex();
56     bool sessionExists();
57     int64_t toNanos(Duration d);
58 
59     struct GpuTestConfig {
60         bool adpfGpuFlagOn;
61         Duration frame1GpuFenceDuration;
62         Duration frame2GpuFenceDuration;
63         Duration vsyncPeriod;
64         Duration presentDuration = 0ms;
65         Duration postCompDuration = 0ms;
66         bool frame1RequiresRenderEngine;
67         bool frame2RequiresRenderEngine;
68         bool usesFmq = false;
69         bool usesSharedFmqFlag = true;
70         bool fmqFull = false;
71     };
72 
73     void testGpuScenario(GpuTestConfig& config, WorkDuration& ret);
74 
75 protected:
76     TestableSurfaceFlinger mFlinger;
77     std::unique_ptr<PowerAdvisor> mPowerAdvisor;
78     MockPowerHalController* mMockPowerHalController;
79     std::shared_ptr<MockPowerHintSessionWrapper> mMockPowerHintSession;
80     std::shared_ptr<AidlMessageQueue<ChannelMessage, SynchronizedReadWrite>> mBackendFmq;
81     std::shared_ptr<AidlMessageQueue<int8_t, SynchronizedReadWrite>> mBackendFlagQueue;
82     android::hardware::EventFlag* mEventFlag;
83     uint32_t mWriteFlagBitmask = 2;
84     uint32_t mReadFlagBitmask = 1;
85     int64_t mSessionId = 123;
86     SET_FLAG_FOR_TEST(android::os::adpf_use_fmq_channel, true);
87     SET_FLAG_FOR_TEST(android::os::adpf_use_fmq_channel_fixed, false);
88 };
89 
sessionExists()90 bool PowerAdvisorTest::sessionExists() {
91     std::scoped_lock lock(mPowerAdvisor->mHintSessionMutex);
92     return mPowerAdvisor->mHintSession != nullptr;
93 }
94 
toNanos(Duration d)95 int64_t PowerAdvisorTest::toNanos(Duration d) {
96     return std::chrono::nanoseconds(d).count();
97 }
98 
SetUp()99 void PowerAdvisorTest::SetUp() {
100     mPowerAdvisor = std::make_unique<impl::PowerAdvisor>(*mFlinger.flinger());
101     mPowerAdvisor->mPowerHal = std::make_unique<NiceMock<MockPowerHalController>>();
102     mMockPowerHalController =
103             reinterpret_cast<MockPowerHalController*>(mPowerAdvisor->mPowerHal.get());
104     ON_CALL(*mMockPowerHalController, getHintSessionPreferredRate)
105             .WillByDefault(Return(
106                     ByMove(HalResult<int64_t>::fromStatus(ndk::ScopedAStatus::ok(), 16000))));
107 }
108 
SetUpFmq(bool usesSharedEventFlag,bool isQueueFull)109 void PowerAdvisorTest::SetUpFmq(bool usesSharedEventFlag, bool isQueueFull) {
110     mBackendFmq = std::make_shared<
111             AidlMessageQueue<ChannelMessage, SynchronizedReadWrite>>(2, !usesSharedEventFlag);
112     ChannelConfig config;
113     config.channelDescriptor = mBackendFmq->dupeDesc();
114     if (usesSharedEventFlag) {
115         mBackendFlagQueue =
116                 std::make_shared<AidlMessageQueue<int8_t, SynchronizedReadWrite>>(1, true);
117         config.eventFlagDescriptor = mBackendFlagQueue->dupeDesc();
118         ASSERT_EQ(android::hardware::EventFlag::createEventFlag(mBackendFlagQueue
119                                                                         ->getEventFlagWord(),
120                                                                 &mEventFlag),
121                   android::NO_ERROR);
122     } else {
123         ASSERT_EQ(android::hardware::EventFlag::createEventFlag(mBackendFmq->getEventFlagWord(),
124                                                                 &mEventFlag),
125                   android::NO_ERROR);
126     }
127     config.writeFlagBitmask = static_cast<int32_t>(mWriteFlagBitmask);
128     config.readFlagBitmask = static_cast<int32_t>(mReadFlagBitmask);
129     ON_CALL(*mMockPowerHalController, getSessionChannel)
130             .WillByDefault(Return(
131                     ByMove(HalResult<ChannelConfig>::fromStatus(Status::ok(), std::move(config)))));
132     startPowerHintSession();
133     if (isQueueFull) {
134         std::vector<ChannelMessage> msgs;
135         msgs.resize(2);
136         mBackendFmq->writeBlocking(msgs.data(), 2, mReadFlagBitmask, mWriteFlagBitmask,
137                                    std::chrono::nanoseconds(1ms).count(), mEventFlag);
138     }
139 }
140 
startPowerHintSession(bool returnValidSession)141 void PowerAdvisorTest::startPowerHintSession(bool returnValidSession) {
142     mMockPowerHintSession = std::make_shared<NiceMock<MockPowerHintSessionWrapper>>();
143     if (returnValidSession) {
144         ON_CALL(*mMockPowerHalController, createHintSessionWithConfig)
145                 .WillByDefault(DoAll(SetArgPointee<5>(aidl::android::hardware::power::SessionConfig{
146                                              .id = mSessionId}),
147                                      Return(HalResult<std::shared_ptr<PowerHintSessionWrapper>>::
148                                                     fromStatus(binder::Status::ok(),
149                                                                mMockPowerHintSession))));
150     } else {
151         ON_CALL(*mMockPowerHalController, createHintSessionWithConfig).WillByDefault([] {
152             return HalResult<
153                     std::shared_ptr<PowerHintSessionWrapper>>::fromStatus(ndk::ScopedAStatus::ok(),
154                                                                           nullptr);
155         });
156     }
157     mPowerAdvisor->enablePowerHintSession(true);
158     mPowerAdvisor->startPowerHintSession({1, 2, 3});
159     ON_CALL(*mMockPowerHintSession, updateTargetWorkDuration)
160             .WillByDefault(Return(testing::ByMove(HalResult<void>::ok())));
161 }
162 
setExpectedTiming(Duration totalFrameTargetDuration,TimePoint expectedPresentTime)163 void PowerAdvisorTest::setExpectedTiming(Duration totalFrameTargetDuration,
164                                          TimePoint expectedPresentTime) {
165     mPowerAdvisor->setTotalFrameTargetWorkDuration(totalFrameTargetDuration);
166     mPowerAdvisor->setExpectedPresentTime(expectedPresentTime);
167 }
168 
fakeBasicFrameTiming(TimePoint startTime,Duration vsyncPeriod)169 void PowerAdvisorTest::fakeBasicFrameTiming(TimePoint startTime, Duration vsyncPeriod) {
170     mPowerAdvisor->setCommitStart(startTime);
171     mPowerAdvisor->setFrameDelay(0ns);
172     mPowerAdvisor->updateTargetWorkDuration(vsyncPeriod);
173 }
174 
setTimingTestingMode(bool testingMode)175 void PowerAdvisorTest::setTimingTestingMode(bool testingMode) {
176     mPowerAdvisor->mTimingTestingMode = testingMode;
177 }
178 
allowReportActualToAcquireMutex()179 void PowerAdvisorTest::allowReportActualToAcquireMutex() {
180     mPowerAdvisor->mDelayReportActualMutexAcquisitonPromise.set_value(true);
181 }
182 
testGpuScenario(GpuTestConfig & config,WorkDuration & ret)183 void PowerAdvisorTest::testGpuScenario(GpuTestConfig& config, WorkDuration& ret) {
184     SET_FLAG_FOR_TEST(com::android::graphics::surfaceflinger::flags::adpf_gpu_sf,
185                       config.adpfGpuFlagOn);
186     SET_FLAG_FOR_TEST(android::os::adpf_use_fmq_channel_fixed, config.usesFmq);
187     mPowerAdvisor->onBootFinished();
188     bool expectsFmqSuccess = config.usesSharedFmqFlag && !config.fmqFull;
189     if (config.usesFmq) {
190         SetUpFmq(config.usesSharedFmqFlag, config.fmqFull);
191     } else {
192         startPowerHintSession();
193     }
194 
195     std::vector<DisplayId> displayIds{PhysicalDisplayId::fromPort(42u), GpuVirtualDisplayId(0),
196                                       GpuVirtualDisplayId(1)};
197     mPowerAdvisor->setDisplays(displayIds);
198     auto display1 = displayIds[0];
199     // 60hz
200 
201     TimePoint startTime = TimePoint::now();
202     int64_t target;
203     SessionHint hint;
204     if (!config.usesFmq || !expectsFmqSuccess) {
205         EXPECT_CALL(*mMockPowerHintSession, updateTargetWorkDuration(_))
206                 .Times(1)
207                 .WillOnce(DoAll(testing::SaveArg<0>(&target),
208                                 testing::Return(testing::ByMove(HalResult<void>::ok()))));
209         EXPECT_CALL(*mMockPowerHintSession, sendHint(_))
210                 .Times(1)
211                 .WillOnce(DoAll(testing::SaveArg<0>(&hint),
212                                 testing::Return(testing::ByMove(HalResult<void>::ok()))));
213     }
214     // advisor only starts on frame 2 so do an initial frame
215     fakeBasicFrameTiming(startTime, config.vsyncPeriod);
216     // send a load hint
217     mPowerAdvisor->notifyCpuLoadUp();
218     if (config.usesFmq && expectsFmqSuccess) {
219         std::vector<ChannelMessage> msgs;
220         ASSERT_EQ(mBackendFmq->availableToRead(), 2uL);
221         msgs.resize(2);
222         ASSERT_TRUE(mBackendFmq->readBlocking(msgs.data(), 2, mReadFlagBitmask, mWriteFlagBitmask,
223                                               std::chrono::nanoseconds(1ms).count(), mEventFlag));
224         ASSERT_EQ(msgs[0].sessionID, mSessionId);
225         ASSERT_GE(msgs[0].timeStampNanos, startTime.ns());
226         ASSERT_EQ(msgs[0].data.getTag(),
227                   ChannelMessage::ChannelMessageContents::Tag::targetDuration);
228         target = msgs[0].data.get<ChannelMessage::ChannelMessageContents::Tag::targetDuration>();
229         ASSERT_EQ(msgs[1].sessionID, mSessionId);
230         ASSERT_GE(msgs[1].timeStampNanos, startTime.ns());
231         ASSERT_EQ(msgs[1].data.getTag(), ChannelMessage::ChannelMessageContents::Tag::hint);
232         hint = msgs[1].data.get<ChannelMessage::ChannelMessageContents::Tag::hint>();
233     }
234     ASSERT_EQ(target, config.vsyncPeriod.ns());
235     ASSERT_EQ(hint, SessionHint::CPU_LOAD_UP);
236 
237     setExpectedTiming(config.vsyncPeriod, startTime + config.vsyncPeriod);
238 
239     // report GPU
240     mPowerAdvisor->setRequiresRenderEngine(display1, config.frame1RequiresRenderEngine);
241     if (config.adpfGpuFlagOn) {
242         mPowerAdvisor->setGpuStartTime(display1, startTime);
243     }
244     if (config.frame1GpuFenceDuration.count() == Fence::SIGNAL_TIME_PENDING) {
245         mPowerAdvisor->setGpuFenceTime(display1,
246                                        std::make_unique<FenceTime>(Fence::SIGNAL_TIME_PENDING));
247     } else {
248         TimePoint end = startTime + config.frame1GpuFenceDuration;
249         mPowerAdvisor->setGpuFenceTime(display1, std::make_unique<FenceTime>(end.ns()));
250     }
251 
252     // increment the frame
253     std::this_thread::sleep_for(config.vsyncPeriod);
254     startTime = TimePoint::now();
255     fakeBasicFrameTiming(startTime, config.vsyncPeriod);
256     if (config.usesFmq && expectsFmqSuccess) {
257         // same target update will not trigger FMQ write
258         ASSERT_EQ(mBackendFmq->availableToRead(), 0uL);
259     }
260     setExpectedTiming(config.vsyncPeriod, startTime + config.vsyncPeriod);
261 
262     // report GPU
263     mPowerAdvisor->setRequiresRenderEngine(display1, config.frame2RequiresRenderEngine);
264     if (config.adpfGpuFlagOn) {
265         mPowerAdvisor->setGpuStartTime(display1, startTime);
266     }
267     if (config.frame2GpuFenceDuration.count() == Fence::SIGNAL_TIME_PENDING) {
268         mPowerAdvisor->setGpuFenceTime(display1,
269                                        std::make_unique<FenceTime>(Fence::SIGNAL_TIME_PENDING));
270     } else {
271         TimePoint end = startTime + config.frame2GpuFenceDuration;
272         mPowerAdvisor->setGpuFenceTime(display1, std::make_unique<FenceTime>(end.ns()));
273     }
274     mPowerAdvisor->setSfPresentTiming(startTime, startTime + config.presentDuration);
275     mPowerAdvisor->setCompositeEnd(startTime + config.presentDuration + config.postCompDuration);
276 
277     // don't report timing for the HWC
278     mPowerAdvisor->setHwcValidateTiming(displayIds[0], startTime, startTime);
279     mPowerAdvisor->setHwcPresentTiming(displayIds[0], startTime, startTime);
280 
281     if (config.usesFmq && expectsFmqSuccess) {
282         mPowerAdvisor->reportActualWorkDuration();
283         ASSERT_EQ(mBackendFmq->availableToRead(), 1uL);
284         std::vector<ChannelMessage> msgs;
285         msgs.resize(1);
286         ASSERT_TRUE(mBackendFmq->readBlocking(msgs.data(), 1, mReadFlagBitmask, mWriteFlagBitmask,
287                                               std::chrono::nanoseconds(1ms).count(), mEventFlag));
288         ASSERT_EQ(msgs[0].sessionID, mSessionId);
289         ASSERT_GE(msgs[0].timeStampNanos, startTime.ns());
290         ASSERT_EQ(msgs[0].data.getTag(), ChannelMessage::ChannelMessageContents::Tag::workDuration);
291         auto actual = msgs[0].data.get<ChannelMessage::ChannelMessageContents::Tag::workDuration>();
292         ret.workPeriodStartTimestampNanos = actual.workPeriodStartTimestampNanos;
293         ret.cpuDurationNanos = actual.cpuDurationNanos;
294         ret.gpuDurationNanos = actual.gpuDurationNanos;
295         ret.durationNanos = actual.durationNanos;
296     } else {
297         std::vector<aidl::android::hardware::power::WorkDuration> durationReq;
298         EXPECT_CALL(*mMockPowerHintSession, reportActualWorkDuration(_))
299                 .Times(1)
300                 .WillOnce(DoAll(testing::SaveArg<0>(&durationReq),
301                                 testing::Return(testing::ByMove(HalResult<void>::ok()))));
302         mPowerAdvisor->reportActualWorkDuration();
303         ASSERT_EQ(durationReq.size(), 1u);
304         ret = std::move(durationReq[0]);
305     }
306 }
307 
getFenceWaitDelayDuration(bool skipValidate)308 Duration PowerAdvisorTest::getFenceWaitDelayDuration(bool skipValidate) {
309     return (skipValidate ? PowerAdvisor::kFenceWaitStartDelaySkippedValidate
310                          : PowerAdvisor::kFenceWaitStartDelayValidated);
311 }
312 
getErrorMargin()313 Duration PowerAdvisorTest::getErrorMargin() {
314     return mPowerAdvisor->sTargetSafetyMargin;
315 }
316 
317 namespace {
318 
TEST_F(PowerAdvisorTest,hintSessionUseHwcDisplay)319 TEST_F(PowerAdvisorTest, hintSessionUseHwcDisplay) {
320     mPowerAdvisor->onBootFinished();
321     startPowerHintSession();
322 
323     std::vector<DisplayId> displayIds{PhysicalDisplayId::fromPort(42u)};
324 
325     // 60hz
326     const Duration vsyncPeriod{std::chrono::nanoseconds(1s) / 60};
327     const Duration presentDuration = 5ms;
328     const Duration postCompDuration = 1ms;
329 
330     TimePoint startTime{100ns};
331 
332     // advisor only starts on frame 2 so do an initial no-op frame
333     fakeBasicFrameTiming(startTime, vsyncPeriod);
334     setExpectedTiming(vsyncPeriod, startTime + vsyncPeriod);
335     mPowerAdvisor->setDisplays(displayIds);
336     mPowerAdvisor->setSfPresentTiming(startTime, startTime + presentDuration);
337     mPowerAdvisor->setCompositeEnd(startTime + presentDuration + postCompDuration);
338 
339     // increment the frame
340     startTime += vsyncPeriod;
341 
342     const Duration expectedDuration = getErrorMargin() + presentDuration + postCompDuration;
343     EXPECT_CALL(*mMockPowerHintSession,
344                 reportActualWorkDuration(ElementsAre(
345                         Field(&WorkDuration::durationNanos, Eq(expectedDuration.ns())))))
346             .Times(1)
347             .WillOnce(Return(testing::ByMove(HalResult<void>::ok())));
348     fakeBasicFrameTiming(startTime, vsyncPeriod);
349     setExpectedTiming(vsyncPeriod, startTime + vsyncPeriod);
350     mPowerAdvisor->setDisplays(displayIds);
351     mPowerAdvisor->setHwcValidateTiming(displayIds[0], startTime + 1ms, startTime + 1500us);
352     mPowerAdvisor->setHwcPresentTiming(displayIds[0], startTime + 2ms, startTime + 2500us);
353     mPowerAdvisor->setSfPresentTiming(startTime, startTime + presentDuration);
354     mPowerAdvisor->reportActualWorkDuration();
355 }
356 
TEST_F(PowerAdvisorTest,hintSessionSubtractsHwcFenceTime)357 TEST_F(PowerAdvisorTest, hintSessionSubtractsHwcFenceTime) {
358     mPowerAdvisor->onBootFinished();
359     startPowerHintSession();
360 
361     std::vector<DisplayId> displayIds{PhysicalDisplayId::fromPort(42u)};
362 
363     // 60hz
364     const Duration vsyncPeriod{std::chrono::nanoseconds(1s) / 60};
365     const Duration presentDuration = 5ms;
366     const Duration postCompDuration = 1ms;
367     const Duration hwcBlockedDuration = 500us;
368 
369     TimePoint startTime{100ns};
370 
371     // advisor only starts on frame 2 so do an initial no-op frame
372     fakeBasicFrameTiming(startTime, vsyncPeriod);
373     setExpectedTiming(vsyncPeriod, startTime + vsyncPeriod);
374     mPowerAdvisor->setDisplays(displayIds);
375     mPowerAdvisor->setSfPresentTiming(startTime, startTime + presentDuration);
376     mPowerAdvisor->setCompositeEnd(startTime + presentDuration + postCompDuration);
377 
378     // increment the frame
379     startTime += vsyncPeriod;
380 
381     const Duration expectedDuration = getErrorMargin() + presentDuration +
382             getFenceWaitDelayDuration(false) - hwcBlockedDuration + postCompDuration;
383     EXPECT_CALL(*mMockPowerHintSession,
384                 reportActualWorkDuration(ElementsAre(
385                         Field(&WorkDuration::durationNanos, Eq(expectedDuration.ns())))))
386             .Times(1)
387             .WillOnce(Return(testing::ByMove(HalResult<void>::ok())));
388 
389     fakeBasicFrameTiming(startTime, vsyncPeriod);
390     setExpectedTiming(vsyncPeriod, startTime + vsyncPeriod);
391     mPowerAdvisor->setDisplays(displayIds);
392     mPowerAdvisor->setHwcValidateTiming(displayIds[0], startTime + 1ms, startTime + 1500us);
393     mPowerAdvisor->setHwcPresentTiming(displayIds[0], startTime + 2ms, startTime + 3ms);
394     // now report the fence as having fired during the display HWC time
395     mPowerAdvisor->setSfPresentTiming(startTime + 2ms + hwcBlockedDuration,
396                                       startTime + presentDuration);
397     mPowerAdvisor->reportActualWorkDuration();
398 }
399 
TEST_F(PowerAdvisorTest,hintSessionUsingSecondaryVirtualDisplays)400 TEST_F(PowerAdvisorTest, hintSessionUsingSecondaryVirtualDisplays) {
401     mPowerAdvisor->onBootFinished();
402     startPowerHintSession();
403 
404     std::vector<DisplayId> displayIds{PhysicalDisplayId::fromPort(42u), GpuVirtualDisplayId(0),
405                                       GpuVirtualDisplayId(1)};
406 
407     // 60hz
408     const Duration vsyncPeriod{std::chrono::nanoseconds(1s) / 60};
409     // make present duration much later than the hwc display by itself will account for
410     const Duration presentDuration{10ms};
411     const Duration postCompDuration{1ms};
412 
413     TimePoint startTime{100ns};
414 
415     // advisor only starts on frame 2 so do an initial no-op frame
416     fakeBasicFrameTiming(startTime, vsyncPeriod);
417     setExpectedTiming(vsyncPeriod, startTime + vsyncPeriod);
418     mPowerAdvisor->setDisplays(displayIds);
419     mPowerAdvisor->setSfPresentTiming(startTime, startTime + presentDuration);
420     mPowerAdvisor->setCompositeEnd(startTime + presentDuration + postCompDuration);
421 
422     // increment the frame
423     startTime += vsyncPeriod;
424 
425     const Duration expectedDuration = getErrorMargin() + presentDuration + postCompDuration;
426     EXPECT_CALL(*mMockPowerHintSession,
427                 reportActualWorkDuration(ElementsAre(
428                         Field(&WorkDuration::durationNanos, Eq(expectedDuration.ns())))))
429             .Times(1)
430             .WillOnce(Return(testing::ByMove(HalResult<void>::ok())));
431 
432     fakeBasicFrameTiming(startTime, vsyncPeriod);
433     setExpectedTiming(vsyncPeriod, startTime + vsyncPeriod);
434     mPowerAdvisor->setDisplays(displayIds);
435 
436     // don't report timing for the gpu displays since they don't use hwc
437     mPowerAdvisor->setHwcValidateTiming(displayIds[0], startTime + 1ms, startTime + 1500us);
438     mPowerAdvisor->setHwcPresentTiming(displayIds[0], startTime + 2ms, startTime + 2500us);
439     mPowerAdvisor->setSfPresentTiming(startTime, startTime + presentDuration);
440     mPowerAdvisor->reportActualWorkDuration();
441 }
442 
TEST_F(PowerAdvisorTest,hintSessionValidWhenNullFromPowerHAL)443 TEST_F(PowerAdvisorTest, hintSessionValidWhenNullFromPowerHAL) {
444     mPowerAdvisor->onBootFinished();
445 
446     startPowerHintSession(false);
447 
448     std::vector<DisplayId> displayIds{PhysicalDisplayId::fromPort(42u)};
449 
450     // 60hz
451     const Duration vsyncPeriod{std::chrono::nanoseconds(1s) / 60};
452     const Duration presentDuration = 5ms;
453     const Duration postCompDuration = 1ms;
454 
455     TimePoint startTime{100ns};
456 
457     // advisor only starts on frame 2 so do an initial no-op frame
458     fakeBasicFrameTiming(startTime, vsyncPeriod);
459     setExpectedTiming(vsyncPeriod, startTime + vsyncPeriod);
460     mPowerAdvisor->setDisplays(displayIds);
461     mPowerAdvisor->setSfPresentTiming(startTime, startTime + presentDuration);
462     mPowerAdvisor->setCompositeEnd(startTime + presentDuration + postCompDuration);
463 
464     // increment the frame
465     startTime += vsyncPeriod;
466 
467     const Duration expectedDuration = getErrorMargin() + presentDuration + postCompDuration;
468     EXPECT_CALL(*mMockPowerHintSession,
469                 reportActualWorkDuration(ElementsAre(
470                         Field(&WorkDuration::durationNanos, Eq(expectedDuration.ns())))))
471             .Times(0);
472     fakeBasicFrameTiming(startTime, vsyncPeriod);
473     setExpectedTiming(vsyncPeriod, startTime + vsyncPeriod);
474     mPowerAdvisor->setDisplays(displayIds);
475     mPowerAdvisor->setHwcValidateTiming(displayIds[0], startTime + 1ms, startTime + 1500us);
476     mPowerAdvisor->setHwcPresentTiming(displayIds[0], startTime + 2ms, startTime + 2500us);
477     mPowerAdvisor->setSfPresentTiming(startTime, startTime + presentDuration);
478     mPowerAdvisor->reportActualWorkDuration();
479 }
480 
TEST_F(PowerAdvisorTest,hintSessionTestNotifyReportRace)481 TEST_F(PowerAdvisorTest, hintSessionTestNotifyReportRace) {
482     // notifyDisplayUpdateImminentAndCpuReset or notifyCpuLoadUp gets called in background
483     // reportActual gets called during callback and sees true session, passes ensure
484     // first notify finishes, setting value to true. Another async method gets called, acquires the
485     // lock between reportactual finishing ensure and acquiring the lock itself, and sets session to
486     // nullptr. reportActual acquires the lock, and the session is now null, so it does nullptr
487     // deref
488 
489     mPowerAdvisor->onBootFinished();
490     startPowerHintSession();
491 
492     // --- fake a bunch of timing data
493     std::vector<DisplayId> displayIds{PhysicalDisplayId::fromPort(42u)};
494     // 60hz
495     const Duration vsyncPeriod{std::chrono::nanoseconds(1s) / 60};
496     const Duration presentDuration = 5ms;
497     const Duration postCompDuration = 1ms;
498     TimePoint startTime{100ns};
499     // advisor only starts on frame 2 so do an initial no-op frame
500     fakeBasicFrameTiming(startTime, vsyncPeriod);
501     setExpectedTiming(vsyncPeriod, startTime + vsyncPeriod);
502     mPowerAdvisor->setDisplays(displayIds);
503     mPowerAdvisor->setSfPresentTiming(startTime, startTime + presentDuration);
504     mPowerAdvisor->setCompositeEnd(startTime + presentDuration + postCompDuration);
505     // increment the frame
506     startTime += vsyncPeriod;
507     fakeBasicFrameTiming(startTime, vsyncPeriod);
508     setExpectedTiming(vsyncPeriod, startTime + vsyncPeriod);
509     mPowerAdvisor->setDisplays(displayIds);
510     mPowerAdvisor->setHwcValidateTiming(displayIds[0], startTime + 1ms, startTime + 1500us);
511     mPowerAdvisor->setHwcPresentTiming(displayIds[0], startTime + 2ms, startTime + 2500us);
512     mPowerAdvisor->setSfPresentTiming(startTime, startTime + presentDuration);
513     // --- Done faking timing data
514 
515     setTimingTestingMode(true);
516     std::promise<bool> letSendHintFinish;
517 
518     ON_CALL(*mMockPowerHintSession, sendHint).WillByDefault([&letSendHintFinish] {
519         letSendHintFinish.get_future().wait();
520         return HalResult<void>::fromStatus(ndk::ScopedAStatus::fromExceptionCode(-127));
521     });
522 
523     ON_CALL(*mMockPowerHintSession, reportActualWorkDuration).WillByDefault([] {
524         return HalResult<void>::fromStatus(ndk::ScopedAStatus::fromExceptionCode(-127));
525     });
526 
527     ON_CALL(*mMockPowerHalController, createHintSessionWithConfig).WillByDefault([] {
528         return HalResult<std::shared_ptr<PowerHintSessionWrapper>>::
529                 fromStatus(ndk::ScopedAStatus::fromExceptionCode(-127), nullptr);
530     });
531 
532     // First background call, to notice the session is down
533     auto firstHint = std::async(std::launch::async, [this] {
534         mPowerAdvisor->notifyCpuLoadUp();
535         return true;
536     });
537     std::this_thread::sleep_for(10ms);
538 
539     // Call reportActual while callback is resolving to try and sneak past ensure
540     auto reportActual =
541             std::async(std::launch::async, [this] { mPowerAdvisor->reportActualWorkDuration(); });
542 
543     std::this_thread::sleep_for(10ms);
544     // Let the first call finish
545     letSendHintFinish.set_value(true);
546     letSendHintFinish = std::promise<bool>{};
547     firstHint.wait();
548 
549     // Do the second notify call, to ensure the session is nullptr
550     auto secondHint = std::async(std::launch::async, [this] {
551         mPowerAdvisor->notifyCpuLoadUp();
552         return true;
553     });
554     letSendHintFinish.set_value(true);
555     secondHint.wait();
556     // Let report finish, potentially dereferencing
557     allowReportActualToAcquireMutex();
558     reportActual.wait();
559     EXPECT_EQ(sessionExists(), false);
560 }
561 
TEST_F(PowerAdvisorTest,legacyHintSessionCreationStillWorks)562 TEST_F(PowerAdvisorTest, legacyHintSessionCreationStillWorks) {
563     mPowerAdvisor->onBootFinished();
564     mMockPowerHintSession = std::make_shared<NiceMock<MockPowerHintSessionWrapper>>();
565     EXPECT_CALL(*mMockPowerHalController, createHintSessionWithConfig)
566             .Times(1)
567             .WillOnce(Return(HalResult<std::shared_ptr<PowerHintSessionWrapper>>::
568                                      fromStatus(ndk::ScopedAStatus::fromExceptionCode(
569                                                         EX_UNSUPPORTED_OPERATION),
570                                                 nullptr)));
571 
572     EXPECT_CALL(*mMockPowerHalController, createHintSession)
573             .Times(1)
574             .WillOnce(Return(HalResult<std::shared_ptr<PowerHintSessionWrapper>>::
575                                      fromStatus(binder::Status::ok(), mMockPowerHintSession)));
576     mPowerAdvisor->enablePowerHintSession(true);
577     ASSERT_TRUE(mPowerAdvisor->startPowerHintSession({1, 2, 3}));
578 }
579 
TEST_F(PowerAdvisorTest,setGpuFenceTime_cpuThenGpuFrames)580 TEST_F(PowerAdvisorTest, setGpuFenceTime_cpuThenGpuFrames) {
581     GpuTestConfig config{
582             .adpfGpuFlagOn = false,
583             // faked buffer fence time for testing
584             .frame1GpuFenceDuration = 41ms,
585             .frame2GpuFenceDuration = 31ms,
586             .vsyncPeriod = 10ms,
587             .presentDuration = 2ms,
588             .postCompDuration = 8ms,
589             .frame1RequiresRenderEngine = false,
590             .frame2RequiresRenderEngine = true,
591     };
592     WorkDuration res;
593     testGpuScenario(config, res);
594     EXPECT_EQ(res.gpuDurationNanos, 0L);
595     EXPECT_EQ(res.cpuDurationNanos, 0L);
596     EXPECT_GE(res.durationNanos, toNanos(30ms + getErrorMargin()));
597     EXPECT_LE(res.durationNanos, toNanos(31ms + getErrorMargin()));
598 }
599 
TEST_F(PowerAdvisorTest,setGpuFenceTime_cpuThenGpuFrames_flagOn)600 TEST_F(PowerAdvisorTest, setGpuFenceTime_cpuThenGpuFrames_flagOn) {
601     GpuTestConfig config{
602             .adpfGpuFlagOn = true,
603             .frame1GpuFenceDuration = 40ms,
604             .frame2GpuFenceDuration = 30ms,
605             .vsyncPeriod = 10ms,
606             .presentDuration = 2ms,
607             .postCompDuration = 8ms,
608             .frame1RequiresRenderEngine = false,
609             .frame2RequiresRenderEngine = true,
610     };
611     WorkDuration res;
612     testGpuScenario(config, res);
613     EXPECT_EQ(res.gpuDurationNanos, toNanos(30ms));
614     EXPECT_EQ(res.cpuDurationNanos, toNanos(10ms));
615     EXPECT_EQ(res.durationNanos, toNanos(30ms + getErrorMargin()));
616 }
617 
TEST_F(PowerAdvisorTest,setGpuFenceTime_gpuThenCpuFrames)618 TEST_F(PowerAdvisorTest, setGpuFenceTime_gpuThenCpuFrames) {
619     GpuTestConfig config{
620             .adpfGpuFlagOn = false,
621             // faked fence time for testing
622             .frame1GpuFenceDuration = 41ms,
623             .frame2GpuFenceDuration = 31ms,
624             .vsyncPeriod = 10ms,
625             .presentDuration = 2ms,
626             .postCompDuration = 8ms,
627             .frame1RequiresRenderEngine = true,
628             .frame2RequiresRenderEngine = false,
629     };
630     WorkDuration res;
631     testGpuScenario(config, res);
632     EXPECT_EQ(res.gpuDurationNanos, 0L);
633     EXPECT_EQ(res.cpuDurationNanos, 0L);
634     EXPECT_EQ(res.durationNanos, toNanos(10ms + getErrorMargin()));
635 }
636 
TEST_F(PowerAdvisorTest,setGpuFenceTime_gpuThenCpuFrames_flagOn)637 TEST_F(PowerAdvisorTest, setGpuFenceTime_gpuThenCpuFrames_flagOn) {
638     GpuTestConfig config{
639             .adpfGpuFlagOn = true,
640             .frame1GpuFenceDuration = 40ms,
641             .frame2GpuFenceDuration = 30ms,
642             .vsyncPeriod = 10ms,
643             .presentDuration = 2ms,
644             .postCompDuration = 8ms,
645             .frame1RequiresRenderEngine = true,
646             .frame2RequiresRenderEngine = false,
647     };
648     WorkDuration res;
649     testGpuScenario(config, res);
650     EXPECT_EQ(res.gpuDurationNanos, 0L);
651     EXPECT_EQ(res.cpuDurationNanos, toNanos(10ms));
652     EXPECT_EQ(res.durationNanos, toNanos(10ms + getErrorMargin()));
653 }
654 
TEST_F(PowerAdvisorTest,setGpuFenceTime_twoSignaledGpuFrames)655 TEST_F(PowerAdvisorTest, setGpuFenceTime_twoSignaledGpuFrames) {
656     GpuTestConfig config{
657             .adpfGpuFlagOn = false,
658             // added a margin as a workaround since we set GPU start time at the time of fence set
659             // call
660             .frame1GpuFenceDuration = 31ms,
661             .frame2GpuFenceDuration = 51ms,
662             .vsyncPeriod = 10ms,
663             .presentDuration = 2ms,
664             .postCompDuration = 8ms,
665             .frame1RequiresRenderEngine = true,
666             .frame2RequiresRenderEngine = true,
667     };
668     WorkDuration res;
669     testGpuScenario(config, res);
670     EXPECT_EQ(res.gpuDurationNanos, 0L);
671     EXPECT_EQ(res.cpuDurationNanos, 0L);
672     EXPECT_GE(res.durationNanos, toNanos(50ms + getErrorMargin()));
673     EXPECT_LE(res.durationNanos, toNanos(51ms + getErrorMargin()));
674 }
675 
TEST_F(PowerAdvisorTest,setGpuFenceTime_twoSignaledGpuFenceFrames_flagOn)676 TEST_F(PowerAdvisorTest, setGpuFenceTime_twoSignaledGpuFenceFrames_flagOn) {
677     GpuTestConfig config{
678             .adpfGpuFlagOn = true,
679             .frame1GpuFenceDuration = 30ms,
680             .frame2GpuFenceDuration = 50ms,
681             .vsyncPeriod = 10ms,
682             .presentDuration = 2ms,
683             .postCompDuration = 8ms,
684             .frame1RequiresRenderEngine = true,
685             .frame2RequiresRenderEngine = true,
686     };
687     WorkDuration res;
688     testGpuScenario(config, res);
689     EXPECT_EQ(res.gpuDurationNanos, toNanos(50ms));
690     EXPECT_EQ(res.cpuDurationNanos, toNanos(10ms));
691     EXPECT_EQ(res.durationNanos, toNanos(50ms + getErrorMargin()));
692 }
693 
TEST_F(PowerAdvisorTest,setGpuFenceTime_UnsingaledGpuFenceFrameUsingPreviousFrame)694 TEST_F(PowerAdvisorTest, setGpuFenceTime_UnsingaledGpuFenceFrameUsingPreviousFrame) {
695     GpuTestConfig config{
696             .adpfGpuFlagOn = false,
697             .frame1GpuFenceDuration = 31ms,
698             .frame2GpuFenceDuration = Duration::fromNs(Fence::SIGNAL_TIME_PENDING),
699             .vsyncPeriod = 10ms,
700             .presentDuration = 2ms,
701             .postCompDuration = 8ms,
702             .frame1RequiresRenderEngine = true,
703             .frame2RequiresRenderEngine = true,
704     };
705     WorkDuration res;
706     testGpuScenario(config, res);
707     EXPECT_EQ(res.gpuDurationNanos, 0L);
708     EXPECT_EQ(res.cpuDurationNanos, 0L);
709     EXPECT_GE(res.durationNanos, toNanos(30ms + getErrorMargin()));
710     EXPECT_LE(res.durationNanos, toNanos(31ms + getErrorMargin()));
711 }
712 
TEST_F(PowerAdvisorTest,setGpuFenceTime_UnsingaledGpuFenceFrameUsingPreviousFrame_flagOn)713 TEST_F(PowerAdvisorTest, setGpuFenceTime_UnsingaledGpuFenceFrameUsingPreviousFrame_flagOn) {
714     GpuTestConfig config{
715             .adpfGpuFlagOn = true,
716             .frame1GpuFenceDuration = 30ms,
717             .frame2GpuFenceDuration = Duration::fromNs(Fence::SIGNAL_TIME_PENDING),
718             .vsyncPeriod = 10ms,
719             .presentDuration = 22ms,
720             .postCompDuration = 88ms,
721             .frame1RequiresRenderEngine = true,
722             .frame2RequiresRenderEngine = true,
723     };
724     WorkDuration res;
725     testGpuScenario(config, res);
726     EXPECT_EQ(res.gpuDurationNanos, toNanos(30ms));
727     EXPECT_EQ(res.cpuDurationNanos, toNanos(110ms));
728     EXPECT_EQ(res.durationNanos, toNanos(110ms + getErrorMargin()));
729 }
730 
TEST_F(PowerAdvisorTest,fmq_sendTargetAndActualDuration)731 TEST_F(PowerAdvisorTest, fmq_sendTargetAndActualDuration) {
732     GpuTestConfig config{
733             .adpfGpuFlagOn = true,
734             .frame1GpuFenceDuration = 30ms,
735             .frame2GpuFenceDuration = Duration::fromNs(Fence::SIGNAL_TIME_PENDING),
736             .vsyncPeriod = 10ms,
737             .presentDuration = 22ms,
738             .postCompDuration = 88ms,
739             .frame1RequiresRenderEngine = true,
740             .frame2RequiresRenderEngine = true,
741             .usesFmq = true,
742             .usesSharedFmqFlag = true,
743     };
744     WorkDuration res;
745     testGpuScenario(config, res);
746     EXPECT_EQ(res.gpuDurationNanos, toNanos(30ms));
747     EXPECT_EQ(res.cpuDurationNanos, toNanos(110ms));
748     EXPECT_EQ(res.durationNanos, toNanos(110ms + getErrorMargin()));
749 }
750 
TEST_F(PowerAdvisorTest,fmq_sendTargetAndActualDuration_noSharedFlag)751 TEST_F(PowerAdvisorTest, fmq_sendTargetAndActualDuration_noSharedFlag) {
752     GpuTestConfig config{
753             .adpfGpuFlagOn = true,
754             .frame1GpuFenceDuration = 30ms,
755             .frame2GpuFenceDuration = Duration::fromNs(Fence::SIGNAL_TIME_PENDING),
756             .vsyncPeriod = 10ms,
757             .presentDuration = 22ms,
758             .postCompDuration = 88ms,
759             .frame1RequiresRenderEngine = true,
760             .frame2RequiresRenderEngine = true,
761             .usesFmq = true,
762             .usesSharedFmqFlag = false,
763     };
764     WorkDuration res;
765     testGpuScenario(config, res);
766     EXPECT_EQ(res.gpuDurationNanos, toNanos(30ms));
767     EXPECT_EQ(res.cpuDurationNanos, toNanos(110ms));
768     EXPECT_EQ(res.durationNanos, toNanos(110ms + getErrorMargin()));
769 }
770 
TEST_F(PowerAdvisorTest,fmq_sendTargetAndActualDuration_queueFull)771 TEST_F(PowerAdvisorTest, fmq_sendTargetAndActualDuration_queueFull) {
772     GpuTestConfig config{.adpfGpuFlagOn = true,
773                          .frame1GpuFenceDuration = 30ms,
774                          .frame2GpuFenceDuration = Duration::fromNs(Fence::SIGNAL_TIME_PENDING),
775                          .vsyncPeriod = 10ms,
776                          .presentDuration = 22ms,
777                          .postCompDuration = 88ms,
778                          .frame1RequiresRenderEngine = true,
779                          .frame2RequiresRenderEngine = true,
780                          .usesFmq = true,
781                          .usesSharedFmqFlag = true,
782                          .fmqFull = true};
783     WorkDuration res;
784     testGpuScenario(config, res);
785     EXPECT_EQ(res.gpuDurationNanos, toNanos(30ms));
786     EXPECT_EQ(res.cpuDurationNanos, toNanos(110ms));
787     EXPECT_EQ(res.durationNanos, toNanos(110ms + getErrorMargin()));
788 }
789 
TEST_F(PowerAdvisorTest,fmq_sendHint)790 TEST_F(PowerAdvisorTest, fmq_sendHint) {
791     SET_FLAG_FOR_TEST(android::os::adpf_use_fmq_channel_fixed, true);
792     mPowerAdvisor->onBootFinished();
793     SetUpFmq(true, false);
794     auto startTime = uptimeNanos();
795     mPowerAdvisor->notifyCpuLoadUp();
796     std::vector<ChannelMessage> msgs;
797     ASSERT_EQ(mBackendFmq->availableToRead(), 1uL);
798     msgs.resize(1);
799     ASSERT_TRUE(mBackendFmq->readBlocking(msgs.data(), 1, mReadFlagBitmask, mWriteFlagBitmask,
800                                           std::chrono::nanoseconds(1ms).count(), mEventFlag));
801     ASSERT_EQ(msgs[0].sessionID, mSessionId);
802     ASSERT_GE(msgs[0].timeStampNanos, startTime);
803     ASSERT_EQ(msgs[0].data.getTag(), ChannelMessage::ChannelMessageContents::Tag::hint);
804     auto hint = msgs[0].data.get<ChannelMessage::ChannelMessageContents::Tag::hint>();
805     ASSERT_EQ(hint, SessionHint::CPU_LOAD_UP);
806 }
807 
TEST_F(PowerAdvisorTest,fmq_sendHint_noSharedFlag)808 TEST_F(PowerAdvisorTest, fmq_sendHint_noSharedFlag) {
809     SET_FLAG_FOR_TEST(android::os::adpf_use_fmq_channel_fixed, true);
810     mPowerAdvisor->onBootFinished();
811     SetUpFmq(false, false);
812     SessionHint hint;
813     EXPECT_CALL(*mMockPowerHintSession, sendHint(_))
814             .Times(1)
815             .WillOnce(DoAll(testing::SaveArg<0>(&hint),
816                             testing::Return(testing::ByMove(HalResult<void>::ok()))));
817     mPowerAdvisor->notifyCpuLoadUp();
818     ASSERT_EQ(mBackendFmq->availableToRead(), 0uL);
819     ASSERT_EQ(hint, SessionHint::CPU_LOAD_UP);
820 }
821 
TEST_F(PowerAdvisorTest,fmq_sendHint_queueFull)822 TEST_F(PowerAdvisorTest, fmq_sendHint_queueFull) {
823     SET_FLAG_FOR_TEST(android::os::adpf_use_fmq_channel_fixed, true);
824     mPowerAdvisor->onBootFinished();
825     SetUpFmq(true, true);
826     ASSERT_EQ(mBackendFmq->availableToRead(), 2uL);
827     SessionHint hint;
828     EXPECT_CALL(*mMockPowerHintSession, sendHint(_))
829             .Times(1)
830             .WillOnce(DoAll(testing::SaveArg<0>(&hint),
831                             testing::Return(testing::ByMove(HalResult<void>::ok()))));
832     std::vector<ChannelMessage> msgs;
833     msgs.resize(1);
834     mBackendFmq->writeBlocking(msgs.data(), 1, mReadFlagBitmask, mWriteFlagBitmask,
835                                std::chrono::nanoseconds(1ms).count(), mEventFlag);
836     mPowerAdvisor->notifyCpuLoadUp();
837     ASSERT_EQ(mBackendFmq->availableToRead(), 2uL);
838     ASSERT_EQ(hint, SessionHint::CPU_LOAD_UP);
839 }
840 
841 } // namespace
842 } // namespace android::Hwc2::impl
843