• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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