1 /*
2 * Copyright 2021 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 "LibSurfaceFlingerUnittests"
19
20 #include "DisplayTransactionTestHelpers.h"
21 #include "mock/DisplayHardware/MockDisplayMode.h"
22 #include "mock/MockDisplayModeSpecs.h"
23
24 #include <ftl/fake_guard.h>
25 #include <scheduler/Fps.h>
26
27 namespace android {
28 namespace {
29
30 using android::hardware::graphics::composer::V2_4::Error;
31 using android::hardware::graphics::composer::V2_4::VsyncPeriodChangeTimeline;
32
33 class DisplayModeSwitchingTest : public DisplayTransactionTest {
34 public:
SetUp()35 void SetUp() override {
36 injectFakeBufferQueueFactory();
37 injectFakeNativeWindowSurfaceFactory();
38
39 PrimaryDisplayVariant::setupHwcHotplugCallExpectations(this);
40 PrimaryDisplayVariant::setupFramebufferConsumerBufferQueueCallExpectations(this);
41 PrimaryDisplayVariant::setupFramebufferProducerBufferQueueCallExpectations(this);
42 PrimaryDisplayVariant::setupNativeWindowSurfaceCreationCallExpectations(this);
43 PrimaryDisplayVariant::setupHwcGetActiveConfigCallExpectations(this);
44
45 auto selectorPtr = std::make_shared<scheduler::RefreshRateSelector>(kModes, kModeId60);
46
47 setupScheduler(selectorPtr);
48
49 mFlinger.onComposerHalHotplug(PrimaryDisplayVariant::HWC_DISPLAY_ID, Connection::CONNECTED);
50 mFlinger.configureAndCommit();
51
52 mDisplay = PrimaryDisplayVariant::makeFakeExistingDisplayInjector(this)
53 .setRefreshRateSelector(std::move(selectorPtr))
54 .inject();
55
56 // isVsyncPeriodSwitchSupported should return true, otherwise the SF's HWC proxy
57 // will call setActiveConfig instead of setActiveConfigWithConstraints.
58 ON_CALL(*mComposer, isSupported(Hwc2::Composer::OptionalFeature::RefreshRateSwitching))
59 .WillByDefault(Return(true));
60 }
61
62 static constexpr HWDisplayId kInnerDisplayHwcId = PrimaryDisplayVariant::HWC_DISPLAY_ID;
63 static constexpr HWDisplayId kOuterDisplayHwcId = kInnerDisplayHwcId + 1;
64
injectOuterDisplay()65 auto injectOuterDisplay() {
66 constexpr PhysicalDisplayId kOuterDisplayId = PhysicalDisplayId::fromPort(254u);
67
68 constexpr bool kIsPrimary = false;
69 TestableSurfaceFlinger::FakeHwcDisplayInjector(kOuterDisplayId, hal::DisplayType::PHYSICAL,
70 kIsPrimary)
71 .setHwcDisplayId(kOuterDisplayHwcId)
72 .setPowerMode(hal::PowerMode::OFF)
73 .inject(&mFlinger, mComposer);
74
75 mOuterDisplay = mFakeDisplayInjector.injectInternalDisplay(
76 [&](FakeDisplayDeviceInjector& injector) {
77 injector.setPowerMode(hal::PowerMode::OFF);
78 injector.setDisplayModes(mock::cloneForDisplay(kOuterDisplayId, kModes),
79 kModeId120);
80 },
81 {.displayId = kOuterDisplayId,
82 .hwcDisplayId = kOuterDisplayHwcId,
83 .isPrimary = kIsPrimary});
84
85 return std::forward_as_tuple(mDisplay, mOuterDisplay);
86 }
87
88 protected:
89 void setupScheduler(std::shared_ptr<scheduler::RefreshRateSelector>);
90
91 sp<DisplayDevice> mDisplay, mOuterDisplay;
92 mock::EventThread* mAppEventThread;
93
94 static constexpr DisplayModeId kModeId60{0};
95 static constexpr DisplayModeId kModeId90{1};
96 static constexpr DisplayModeId kModeId120{2};
97 static constexpr DisplayModeId kModeId90_4K{3};
98
99 static inline const DisplayModePtr kMode60 = createDisplayMode(kModeId60, 60_Hz, 0);
100 static inline const DisplayModePtr kMode90 = createDisplayMode(kModeId90, 90_Hz, 1);
101 static inline const DisplayModePtr kMode120 = createDisplayMode(kModeId120, 120_Hz, 2);
102
103 static constexpr ui::Size kResolution4K{3840, 2160};
104 static inline const DisplayModePtr kMode90_4K =
105 createDisplayMode(kModeId90_4K, 90_Hz, 3, kResolution4K);
106
107 static inline const DisplayModes kModes = makeModes(kMode60, kMode90, kMode120, kMode90_4K);
108 };
109
setupScheduler(std::shared_ptr<scheduler::RefreshRateSelector> selectorPtr)110 void DisplayModeSwitchingTest::setupScheduler(
111 std::shared_ptr<scheduler::RefreshRateSelector> selectorPtr) {
112 auto eventThread = std::make_unique<mock::EventThread>();
113 mAppEventThread = eventThread.get();
114 auto sfEventThread = std::make_unique<mock::EventThread>();
115
116 EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
117 EXPECT_CALL(*eventThread, createEventConnection(_, _))
118 .WillOnce(Return(sp<EventThreadConnection>::make(eventThread.get(),
119 mock::EventThread::kCallingUid,
120 ResyncCallback())));
121
122 EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
123 EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
124 .WillOnce(Return(sp<EventThreadConnection>::make(sfEventThread.get(),
125 mock::EventThread::kCallingUid,
126 ResyncCallback())));
127
128 auto vsyncController = std::make_unique<mock::VsyncController>();
129 auto vsyncTracker = std::make_shared<mock::VSyncTracker>();
130
131 EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
132 EXPECT_CALL(*vsyncTracker, currentPeriod())
133 .WillRepeatedly(
134 Return(TestableSurfaceFlinger::FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD));
135 EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
136 mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker),
137 std::move(eventThread), std::move(sfEventThread),
138 std::move(selectorPtr),
139 TestableSurfaceFlinger::SchedulerCallbackImpl::kNoOp);
140 }
141
TEST_F(DisplayModeSwitchingTest,changeRefreshRate_OnActiveDisplay_WithRefreshRequired)142 TEST_F(DisplayModeSwitchingTest, changeRefreshRate_OnActiveDisplay_WithRefreshRequired) {
143 ftl::FakeGuard guard(kMainThreadContext);
144
145 ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value());
146 ASSERT_EQ(mDisplay->getActiveMode().modePtr->getId(), kModeId60);
147
148 mFlinger.onActiveDisplayChanged(nullptr, *mDisplay);
149
150 mFlinger.setDesiredDisplayModeSpecs(mDisplay->getDisplayToken().promote(),
151 mock::createDisplayModeSpecs(kModeId90.value(), false, 0,
152 120));
153
154 ASSERT_TRUE(mDisplay->getDesiredActiveMode().has_value());
155 ASSERT_EQ(mDisplay->getDesiredActiveMode()->modeOpt->modePtr->getId(), kModeId90);
156 ASSERT_EQ(mDisplay->getActiveMode().modePtr->getId(), kModeId60);
157
158 // Verify that next commit will call setActiveConfigWithConstraints in HWC
159 const VsyncPeriodChangeTimeline timeline{.refreshRequired = true};
160 EXPECT_CALL(*mComposer,
161 setActiveConfigWithConstraints(PrimaryDisplayVariant::HWC_DISPLAY_ID,
162 hal::HWConfigId(kModeId90.value()), _, _))
163 .WillOnce(DoAll(SetArgPointee<3>(timeline), Return(Error::NONE)));
164
165 mFlinger.commit();
166
167 Mock::VerifyAndClearExpectations(mComposer);
168 ASSERT_TRUE(mDisplay->getDesiredActiveMode().has_value());
169 ASSERT_EQ(mDisplay->getActiveMode().modePtr->getId(), kModeId60);
170
171 // Verify that the next commit will complete the mode change and send
172 // a onModeChanged event to the framework.
173
174 EXPECT_CALL(*mAppEventThread,
175 onModeChanged(scheduler::FrameRateMode{90_Hz, ftl::as_non_null(kMode90)}));
176 mFlinger.commit();
177 Mock::VerifyAndClearExpectations(mAppEventThread);
178
179 ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value());
180 ASSERT_EQ(mDisplay->getActiveMode().modePtr->getId(), kModeId90);
181 }
182
TEST_F(DisplayModeSwitchingTest,changeRefreshRate_OnActiveDisplay_WithoutRefreshRequired)183 TEST_F(DisplayModeSwitchingTest, changeRefreshRate_OnActiveDisplay_WithoutRefreshRequired) {
184 ftl::FakeGuard guard(kMainThreadContext);
185
186 ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value());
187
188 mFlinger.onActiveDisplayChanged(nullptr, *mDisplay);
189
190 mFlinger.setDesiredDisplayModeSpecs(mDisplay->getDisplayToken().promote(),
191 mock::createDisplayModeSpecs(kModeId90.value(), true, 0,
192 120));
193
194 ASSERT_TRUE(mDisplay->getDesiredActiveMode().has_value());
195 ASSERT_EQ(mDisplay->getDesiredActiveMode()->modeOpt->modePtr->getId(), kModeId90);
196 ASSERT_EQ(mDisplay->getActiveMode().modePtr->getId(), kModeId60);
197
198 // Verify that next commit will call setActiveConfigWithConstraints in HWC
199 // and complete the mode change.
200 const VsyncPeriodChangeTimeline timeline{.refreshRequired = false};
201 EXPECT_CALL(*mComposer,
202 setActiveConfigWithConstraints(PrimaryDisplayVariant::HWC_DISPLAY_ID,
203 hal::HWConfigId(kModeId90.value()), _, _))
204 .WillOnce(DoAll(SetArgPointee<3>(timeline), Return(Error::NONE)));
205
206 EXPECT_CALL(*mAppEventThread,
207 onModeChanged(scheduler::FrameRateMode{90_Hz, ftl::as_non_null(kMode90)}));
208
209 mFlinger.commit();
210
211 ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value());
212 ASSERT_EQ(mDisplay->getActiveMode().modePtr->getId(), kModeId90);
213 }
214
TEST_F(DisplayModeSwitchingTest,twoConsecutiveSetDesiredDisplayModeSpecs)215 TEST_F(DisplayModeSwitchingTest, twoConsecutiveSetDesiredDisplayModeSpecs) {
216 ftl::FakeGuard guard(kMainThreadContext);
217
218 // Test that if we call setDesiredDisplayModeSpecs while a previous mode change
219 // is still being processed the later call will be respected.
220
221 ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value());
222 ASSERT_EQ(mDisplay->getActiveMode().modePtr->getId(), kModeId60);
223
224 mFlinger.onActiveDisplayChanged(nullptr, *mDisplay);
225
226 mFlinger.setDesiredDisplayModeSpecs(mDisplay->getDisplayToken().promote(),
227 mock::createDisplayModeSpecs(kModeId90.value(), false, 0,
228 120));
229
230 const VsyncPeriodChangeTimeline timeline{.refreshRequired = true};
231 EXPECT_CALL(*mComposer,
232 setActiveConfigWithConstraints(PrimaryDisplayVariant::HWC_DISPLAY_ID,
233 hal::HWConfigId(kModeId90.value()), _, _))
234 .WillOnce(DoAll(SetArgPointee<3>(timeline), Return(Error::NONE)));
235
236 mFlinger.commit();
237
238 mFlinger.setDesiredDisplayModeSpecs(mDisplay->getDisplayToken().promote(),
239 mock::createDisplayModeSpecs(kModeId120.value(), false, 0,
240 180));
241
242 ASSERT_TRUE(mDisplay->getDesiredActiveMode().has_value());
243 ASSERT_EQ(mDisplay->getDesiredActiveMode()->modeOpt->modePtr->getId(), kModeId120);
244
245 EXPECT_CALL(*mComposer,
246 setActiveConfigWithConstraints(PrimaryDisplayVariant::HWC_DISPLAY_ID,
247 hal::HWConfigId(kModeId120.value()), _, _))
248 .WillOnce(DoAll(SetArgPointee<3>(timeline), Return(Error::NONE)));
249
250 mFlinger.commit();
251
252 ASSERT_TRUE(mDisplay->getDesiredActiveMode().has_value());
253 ASSERT_EQ(mDisplay->getDesiredActiveMode()->modeOpt->modePtr->getId(), kModeId120);
254
255 mFlinger.commit();
256
257 ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value());
258 ASSERT_EQ(mDisplay->getActiveMode().modePtr->getId(), kModeId120);
259 }
260
TEST_F(DisplayModeSwitchingTest,changeResolution_OnActiveDisplay_WithoutRefreshRequired)261 TEST_F(DisplayModeSwitchingTest, changeResolution_OnActiveDisplay_WithoutRefreshRequired) {
262 ftl::FakeGuard guard(kMainThreadContext);
263
264 ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value());
265 ASSERT_EQ(mDisplay->getActiveMode().modePtr->getId(), kModeId60);
266
267 mFlinger.onActiveDisplayChanged(nullptr, *mDisplay);
268
269 mFlinger.setDesiredDisplayModeSpecs(mDisplay->getDisplayToken().promote(),
270 mock::createDisplayModeSpecs(kModeId90_4K.value(), false, 0,
271 120));
272
273 ASSERT_TRUE(mDisplay->getDesiredActiveMode().has_value());
274 ASSERT_EQ(mDisplay->getDesiredActiveMode()->modeOpt->modePtr->getId(), kModeId90_4K);
275 ASSERT_EQ(mDisplay->getActiveMode().modePtr->getId(), kModeId60);
276
277 // Verify that next commit will call setActiveConfigWithConstraints in HWC
278 // and complete the mode change.
279 const VsyncPeriodChangeTimeline timeline{.refreshRequired = false};
280 EXPECT_CALL(*mComposer,
281 setActiveConfigWithConstraints(PrimaryDisplayVariant::HWC_DISPLAY_ID,
282 hal::HWConfigId(kModeId90_4K.value()), _, _))
283 .WillOnce(DoAll(SetArgPointee<3>(timeline), Return(Error::NONE)));
284
285 EXPECT_CALL(*mAppEventThread, onHotplugReceived(mDisplay->getPhysicalId(), true));
286
287 // Misc expecations. We don't need to enforce these method calls, but since the helper methods
288 // already set expectations we should add new ones here, otherwise the test will fail.
289 EXPECT_CALL(*mConsumer,
290 setDefaultBufferSize(static_cast<uint32_t>(kResolution4K.getWidth()),
291 static_cast<uint32_t>(kResolution4K.getHeight())))
292 .WillOnce(Return(NO_ERROR));
293 EXPECT_CALL(*mConsumer, consumerConnect(_, false)).WillOnce(Return(NO_ERROR));
294 EXPECT_CALL(*mComposer, setClientTargetSlotCount(_)).WillOnce(Return(hal::Error::NONE));
295
296 // Create a new native surface to be used by the recreated display.
297 mNativeWindowSurface = nullptr;
298 injectFakeNativeWindowSurfaceFactory();
299 PrimaryDisplayVariant::setupNativeWindowSurfaceCreationCallExpectations(this);
300
301 const auto displayToken = mDisplay->getDisplayToken().promote();
302
303 mFlinger.commit();
304
305 // The DisplayDevice will be destroyed and recreated,
306 // so we need to update with the new instance.
307 mDisplay = mFlinger.getDisplay(displayToken);
308
309 ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value());
310 ASSERT_EQ(mDisplay->getActiveMode().modePtr->getId(), kModeId90_4K);
311 }
312
313 MATCHER_P2(ModeSwitchingTo, flinger, modeId, "") {
314 if (!arg->getDesiredActiveMode()) {
315 *result_listener << "No desired active mode";
316 return false;
317 }
318
319 if (arg->getDesiredActiveMode()->modeOpt->modePtr->getId() != modeId) {
320 *result_listener << "Unexpected desired active mode " << modeId;
321 return false;
322 }
323
324 if (!flinger->scheduler()->vsyncModulator().isVsyncConfigEarly()) {
325 *result_listener << "VsyncModulator did not shift to early phase";
326 return false;
327 }
328
329 return true;
330 }
331
332 MATCHER_P(ModeSettledTo, modeId, "") {
333 if (const auto desiredOpt = arg->getDesiredActiveMode()) {
334 *result_listener << "Unsettled desired active mode "
335 << desiredOpt->modeOpt->modePtr->getId();
336 return false;
337 }
338
339 ftl::FakeGuard guard(kMainThreadContext);
340
341 if (arg->getActiveMode().modePtr->getId() != modeId) {
342 *result_listener << "Settled to unexpected active mode " << modeId;
343 return false;
344 }
345
346 return true;
347 }
348
TEST_F(DisplayModeSwitchingTest,innerXorOuterDisplay)349 TEST_F(DisplayModeSwitchingTest, innerXorOuterDisplay) {
350 const auto [innerDisplay, outerDisplay] = injectOuterDisplay();
351
352 EXPECT_TRUE(innerDisplay->isPoweredOn());
353 EXPECT_FALSE(outerDisplay->isPoweredOn());
354
355 EXPECT_THAT(innerDisplay, ModeSettledTo(kModeId60));
356 EXPECT_THAT(outerDisplay, ModeSettledTo(kModeId120));
357
358 // Only the inner display is powered on.
359 mFlinger.onActiveDisplayChanged(nullptr, *innerDisplay);
360
361 EXPECT_THAT(innerDisplay, ModeSettledTo(kModeId60));
362 EXPECT_THAT(outerDisplay, ModeSettledTo(kModeId120));
363
364 EXPECT_EQ(NO_ERROR,
365 mFlinger.setDesiredDisplayModeSpecs(innerDisplay->getDisplayToken().promote(),
366 mock::createDisplayModeSpecs(kModeId90.value(),
367 false, 0.f, 120.f)));
368
369 EXPECT_EQ(NO_ERROR,
370 mFlinger.setDesiredDisplayModeSpecs(outerDisplay->getDisplayToken().promote(),
371 mock::createDisplayModeSpecs(kModeId60.value(),
372 false, 0.f, 120.f)));
373
374 EXPECT_THAT(innerDisplay, ModeSwitchingTo(&mFlinger, kModeId90));
375 EXPECT_THAT(outerDisplay, ModeSettledTo(kModeId120));
376
377 const VsyncPeriodChangeTimeline timeline{.refreshRequired = true};
378 EXPECT_CALL(*mComposer,
379 setActiveConfigWithConstraints(kInnerDisplayHwcId,
380 hal::HWConfigId(kModeId90.value()), _, _))
381 .WillOnce(DoAll(SetArgPointee<3>(timeline), Return(Error::NONE)));
382
383 mFlinger.commit();
384
385 EXPECT_THAT(innerDisplay, ModeSwitchingTo(&mFlinger, kModeId90));
386 EXPECT_THAT(outerDisplay, ModeSettledTo(kModeId120));
387
388 mFlinger.commit();
389
390 EXPECT_THAT(innerDisplay, ModeSettledTo(kModeId90));
391 EXPECT_THAT(outerDisplay, ModeSettledTo(kModeId120));
392
393 innerDisplay->setPowerMode(hal::PowerMode::OFF);
394 outerDisplay->setPowerMode(hal::PowerMode::ON);
395
396 // Only the outer display is powered on.
397 mFlinger.onActiveDisplayChanged(innerDisplay.get(), *outerDisplay);
398
399 EXPECT_THAT(innerDisplay, ModeSettledTo(kModeId90));
400 EXPECT_THAT(outerDisplay, ModeSwitchingTo(&mFlinger, kModeId60));
401
402 EXPECT_CALL(*mComposer,
403 setActiveConfigWithConstraints(kOuterDisplayHwcId,
404 hal::HWConfigId(kModeId60.value()), _, _))
405 .WillOnce(DoAll(SetArgPointee<3>(timeline), Return(Error::NONE)));
406
407 mFlinger.commit();
408
409 EXPECT_THAT(innerDisplay, ModeSettledTo(kModeId90));
410 EXPECT_THAT(outerDisplay, ModeSwitchingTo(&mFlinger, kModeId60));
411
412 mFlinger.commit();
413
414 EXPECT_THAT(innerDisplay, ModeSettledTo(kModeId90));
415 EXPECT_THAT(outerDisplay, ModeSettledTo(kModeId60));
416 }
417
TEST_F(DisplayModeSwitchingTest,innerAndOuterDisplay)418 TEST_F(DisplayModeSwitchingTest, innerAndOuterDisplay) {
419 const auto [innerDisplay, outerDisplay] = injectOuterDisplay();
420
421 EXPECT_TRUE(innerDisplay->isPoweredOn());
422 EXPECT_FALSE(outerDisplay->isPoweredOn());
423
424 EXPECT_THAT(innerDisplay, ModeSettledTo(kModeId60));
425 EXPECT_THAT(outerDisplay, ModeSettledTo(kModeId120));
426
427 outerDisplay->setPowerMode(hal::PowerMode::ON);
428
429 // Both displays are powered on.
430 mFlinger.onActiveDisplayChanged(nullptr, *innerDisplay);
431
432 EXPECT_THAT(innerDisplay, ModeSettledTo(kModeId60));
433 EXPECT_THAT(outerDisplay, ModeSettledTo(kModeId120));
434
435 EXPECT_EQ(NO_ERROR,
436 mFlinger.setDesiredDisplayModeSpecs(innerDisplay->getDisplayToken().promote(),
437 mock::createDisplayModeSpecs(kModeId90.value(),
438 false, 0.f, 120.f)));
439
440 EXPECT_EQ(NO_ERROR,
441 mFlinger.setDesiredDisplayModeSpecs(outerDisplay->getDisplayToken().promote(),
442 mock::createDisplayModeSpecs(kModeId60.value(),
443 false, 0.f, 120.f)));
444
445 EXPECT_THAT(innerDisplay, ModeSwitchingTo(&mFlinger, kModeId90));
446 EXPECT_THAT(outerDisplay, ModeSwitchingTo(&mFlinger, kModeId60));
447
448 const VsyncPeriodChangeTimeline timeline{.refreshRequired = true};
449 EXPECT_CALL(*mComposer,
450 setActiveConfigWithConstraints(kInnerDisplayHwcId,
451 hal::HWConfigId(kModeId90.value()), _, _))
452 .WillOnce(DoAll(SetArgPointee<3>(timeline), Return(Error::NONE)));
453
454 EXPECT_CALL(*mComposer,
455 setActiveConfigWithConstraints(kOuterDisplayHwcId,
456 hal::HWConfigId(kModeId60.value()), _, _))
457 .WillOnce(DoAll(SetArgPointee<3>(timeline), Return(Error::NONE)));
458
459 mFlinger.commit();
460
461 EXPECT_THAT(innerDisplay, ModeSwitchingTo(&mFlinger, kModeId90));
462 EXPECT_THAT(outerDisplay, ModeSwitchingTo(&mFlinger, kModeId60));
463
464 mFlinger.commit();
465
466 EXPECT_THAT(innerDisplay, ModeSettledTo(kModeId90));
467 EXPECT_THAT(outerDisplay, ModeSettledTo(kModeId60));
468 }
469
TEST_F(DisplayModeSwitchingTest,powerOffDuringModeSet)470 TEST_F(DisplayModeSwitchingTest, powerOffDuringModeSet) {
471 EXPECT_TRUE(mDisplay->isPoweredOn());
472 EXPECT_THAT(mDisplay, ModeSettledTo(kModeId60));
473
474 EXPECT_EQ(NO_ERROR,
475 mFlinger.setDesiredDisplayModeSpecs(mDisplay->getDisplayToken().promote(),
476 mock::createDisplayModeSpecs(kModeId90.value(),
477 false, 0.f, 120.f)));
478
479 EXPECT_THAT(mDisplay, ModeSwitchingTo(&mFlinger, kModeId90));
480
481 // Power off the display before the mode has been set.
482 mDisplay->setPowerMode(hal::PowerMode::OFF);
483
484 const VsyncPeriodChangeTimeline timeline{.refreshRequired = true};
485 EXPECT_CALL(*mComposer,
486 setActiveConfigWithConstraints(kInnerDisplayHwcId,
487 hal::HWConfigId(kModeId90.value()), _, _))
488 .WillOnce(DoAll(SetArgPointee<3>(timeline), Return(Error::NONE)));
489
490 mFlinger.commit();
491
492 // Powering off should not abort the mode set.
493 EXPECT_FALSE(mDisplay->isPoweredOn());
494 EXPECT_THAT(mDisplay, ModeSwitchingTo(&mFlinger, kModeId90));
495
496 mFlinger.commit();
497
498 EXPECT_THAT(mDisplay, ModeSettledTo(kModeId90));
499 }
500
TEST_F(DisplayModeSwitchingTest,powerOffDuringConcurrentModeSet)501 TEST_F(DisplayModeSwitchingTest, powerOffDuringConcurrentModeSet) {
502 const auto [innerDisplay, outerDisplay] = injectOuterDisplay();
503
504 EXPECT_TRUE(innerDisplay->isPoweredOn());
505 EXPECT_FALSE(outerDisplay->isPoweredOn());
506
507 EXPECT_THAT(innerDisplay, ModeSettledTo(kModeId60));
508 EXPECT_THAT(outerDisplay, ModeSettledTo(kModeId120));
509
510 outerDisplay->setPowerMode(hal::PowerMode::ON);
511
512 // Both displays are powered on.
513 mFlinger.onActiveDisplayChanged(nullptr, *innerDisplay);
514
515 EXPECT_THAT(innerDisplay, ModeSettledTo(kModeId60));
516 EXPECT_THAT(outerDisplay, ModeSettledTo(kModeId120));
517
518 EXPECT_EQ(NO_ERROR,
519 mFlinger.setDesiredDisplayModeSpecs(innerDisplay->getDisplayToken().promote(),
520 mock::createDisplayModeSpecs(kModeId90.value(),
521 false, 0.f, 120.f)));
522
523 EXPECT_EQ(NO_ERROR,
524 mFlinger.setDesiredDisplayModeSpecs(outerDisplay->getDisplayToken().promote(),
525 mock::createDisplayModeSpecs(kModeId60.value(),
526 false, 0.f, 120.f)));
527
528 EXPECT_THAT(innerDisplay, ModeSwitchingTo(&mFlinger, kModeId90));
529 EXPECT_THAT(outerDisplay, ModeSwitchingTo(&mFlinger, kModeId60));
530
531 // Power off the outer display before the mode has been set.
532 outerDisplay->setPowerMode(hal::PowerMode::OFF);
533
534 const VsyncPeriodChangeTimeline timeline{.refreshRequired = true};
535 EXPECT_CALL(*mComposer,
536 setActiveConfigWithConstraints(kInnerDisplayHwcId,
537 hal::HWConfigId(kModeId90.value()), _, _))
538 .WillOnce(DoAll(SetArgPointee<3>(timeline), Return(Error::NONE)));
539
540 mFlinger.commit();
541
542 // Powering off the inactive display should abort the mode set.
543 EXPECT_THAT(innerDisplay, ModeSwitchingTo(&mFlinger, kModeId90));
544 EXPECT_THAT(outerDisplay, ModeSettledTo(kModeId120));
545
546 mFlinger.commit();
547
548 EXPECT_THAT(innerDisplay, ModeSettledTo(kModeId90));
549 EXPECT_THAT(outerDisplay, ModeSettledTo(kModeId120));
550
551 innerDisplay->setPowerMode(hal::PowerMode::OFF);
552 outerDisplay->setPowerMode(hal::PowerMode::ON);
553
554 // Only the outer display is powered on.
555 mFlinger.onActiveDisplayChanged(innerDisplay.get(), *outerDisplay);
556
557 EXPECT_CALL(*mComposer,
558 setActiveConfigWithConstraints(kOuterDisplayHwcId,
559 hal::HWConfigId(kModeId60.value()), _, _))
560 .WillOnce(DoAll(SetArgPointee<3>(timeline), Return(Error::NONE)));
561
562 mFlinger.commit();
563
564 // The mode set should resume once the display becomes active.
565 EXPECT_THAT(innerDisplay, ModeSettledTo(kModeId90));
566 EXPECT_THAT(outerDisplay, ModeSwitchingTo(&mFlinger, kModeId60));
567
568 mFlinger.commit();
569
570 EXPECT_THAT(innerDisplay, ModeSettledTo(kModeId90));
571 EXPECT_THAT(outerDisplay, ModeSettledTo(kModeId60));
572 }
573
574 } // namespace
575 } // namespace android
576