1 /*
2  * Copyright 2023 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 <com_android_graphics_surfaceflinger_flags.h>
21 #include <common/test/FlagUtils.h>
22 #include "DualDisplayTransactionTest.h"
23 
24 #include <gmock/gmock.h>
25 #include <gtest/gtest.h>
26 
27 using namespace com::android::graphics::surfaceflinger;
28 
29 namespace android {
30 namespace {
31 
32 constexpr bool kExpectSetPowerModeOnce = false;
33 struct FoldableTest : DualDisplayTransactionTest<hal::PowerMode::OFF, hal::PowerMode::OFF,
34                                                  kExpectSetPowerModeOnce> {};
35 
TEST_F(FoldableTest,promotesPacesetterOnBoot)36 TEST_F(FoldableTest, promotesPacesetterOnBoot) {
37     // When the device boots, the inner display should be the pacesetter.
38     ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kInnerDisplayId);
39 
40     // ...and should still be after powering on.
41     mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON);
42     ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kInnerDisplayId);
43 }
44 
TEST_F(FoldableTest,promotesPacesetterOnFoldUnfold)45 TEST_F(FoldableTest, promotesPacesetterOnFoldUnfold) {
46     mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON);
47 
48     // The outer display should become the pacesetter after folding.
49     mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::OFF);
50     mFlinger.setPowerModeInternal(mOuterDisplay, PowerMode::ON);
51     ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kOuterDisplayId);
52 
53     // The inner display should become the pacesetter after unfolding.
54     mFlinger.setPowerModeInternal(mOuterDisplay, PowerMode::OFF);
55     mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON);
56     ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kInnerDisplayId);
57 }
58 
TEST_F(FoldableTest,promotesPacesetterOnConcurrentPowerOn)59 TEST_F(FoldableTest, promotesPacesetterOnConcurrentPowerOn) {
60     mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON);
61 
62     // The inner display should stay the pacesetter if both are powered on.
63     // TODO(b/255635821): The pacesetter should depend on the displays' refresh rates.
64     mFlinger.setPowerModeInternal(mOuterDisplay, PowerMode::ON);
65     ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kInnerDisplayId);
66 
67     // The outer display should become the pacesetter if designated.
68     mFlinger.scheduler()->setPacesetterDisplay(kOuterDisplayId);
69     ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kOuterDisplayId);
70 
71     // The inner display should become the pacesetter if designated.
72     mFlinger.scheduler()->setPacesetterDisplay(kInnerDisplayId);
73     ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kInnerDisplayId);
74 }
75 
TEST_F(FoldableTest,promotesPacesetterOnConcurrentPowerOff)76 TEST_F(FoldableTest, promotesPacesetterOnConcurrentPowerOff) {
77     mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON);
78     mFlinger.setPowerModeInternal(mOuterDisplay, PowerMode::ON);
79 
80     // The outer display should become the pacesetter if the inner display powers off.
81     mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::OFF);
82     ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kOuterDisplayId);
83 
84     // The outer display should stay the pacesetter if both are powered on.
85     // TODO(b/255635821): The pacesetter should depend on the displays' refresh rates.
86     mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON);
87     ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kOuterDisplayId);
88 
89     // The inner display should become the pacesetter if the outer display powers off.
90     mFlinger.setPowerModeInternal(mOuterDisplay, PowerMode::OFF);
91     ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kInnerDisplayId);
92 }
93 
TEST_F(FoldableTest,doesNotRequestHardwareVsyncIfPoweredOff)94 TEST_F(FoldableTest, doesNotRequestHardwareVsyncIfPoweredOff) {
95     // Both displays are powered off.
96     EXPECT_CALL(mFlinger.mockSchedulerCallback(), requestHardwareVsync(kInnerDisplayId, _))
97             .Times(0);
98     EXPECT_CALL(mFlinger.mockSchedulerCallback(), requestHardwareVsync(kOuterDisplayId, _))
99             .Times(0);
100 
101     EXPECT_FALSE(mInnerDisplay->isPoweredOn());
102     EXPECT_FALSE(mOuterDisplay->isPoweredOn());
103 
104     auto& scheduler = *mFlinger.scheduler();
105     scheduler.onHardwareVsyncRequest(kInnerDisplayId, true);
106     scheduler.onHardwareVsyncRequest(kOuterDisplayId, true);
107 }
108 
TEST_F(FoldableTest,requestsHardwareVsyncForInnerDisplay)109 TEST_F(FoldableTest, requestsHardwareVsyncForInnerDisplay) {
110     // Only inner display is powered on.
111     EXPECT_CALL(mFlinger.mockSchedulerCallback(), requestHardwareVsync(kInnerDisplayId, true))
112             .Times(1);
113     EXPECT_CALL(mFlinger.mockSchedulerCallback(), requestHardwareVsync(kOuterDisplayId, _))
114             .Times(0);
115 
116     // The injected VsyncSchedule uses TestableScheduler::mockRequestHardwareVsync, so no calls to
117     // ISchedulerCallback::requestHardwareVsync are expected during setPowerModeInternal.
118     mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON);
119 
120     EXPECT_TRUE(mInnerDisplay->isPoweredOn());
121     EXPECT_FALSE(mOuterDisplay->isPoweredOn());
122 
123     auto& scheduler = *mFlinger.scheduler();
124     scheduler.onHardwareVsyncRequest(kInnerDisplayId, true);
125     scheduler.onHardwareVsyncRequest(kOuterDisplayId, true);
126 }
127 
TEST_F(FoldableTest,requestsHardwareVsyncForOuterDisplay)128 TEST_F(FoldableTest, requestsHardwareVsyncForOuterDisplay) {
129     // Only outer display is powered on.
130     EXPECT_CALL(mFlinger.mockSchedulerCallback(), requestHardwareVsync(kInnerDisplayId, _))
131             .Times(0);
132     EXPECT_CALL(mFlinger.mockSchedulerCallback(), requestHardwareVsync(kOuterDisplayId, true))
133             .Times(1);
134 
135     // The injected VsyncSchedule uses TestableScheduler::mockRequestHardwareVsync, so no calls to
136     // ISchedulerCallback::requestHardwareVsync are expected during setPowerModeInternal.
137     mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON);
138     mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::OFF);
139     mFlinger.setPowerModeInternal(mOuterDisplay, PowerMode::ON);
140 
141     EXPECT_FALSE(mInnerDisplay->isPoweredOn());
142     EXPECT_TRUE(mOuterDisplay->isPoweredOn());
143 
144     auto& scheduler = *mFlinger.scheduler();
145     scheduler.onHardwareVsyncRequest(kInnerDisplayId, true);
146     scheduler.onHardwareVsyncRequest(kOuterDisplayId, true);
147 }
148 
TEST_F(FoldableTest,requestsHardwareVsyncForBothDisplays)149 TEST_F(FoldableTest, requestsHardwareVsyncForBothDisplays) {
150     // Both displays are powered on.
151     EXPECT_CALL(mFlinger.mockSchedulerCallback(), requestHardwareVsync(kInnerDisplayId, true))
152             .Times(1);
153     EXPECT_CALL(mFlinger.mockSchedulerCallback(), requestHardwareVsync(kOuterDisplayId, true))
154             .Times(1);
155 
156     // The injected VsyncSchedule uses TestableScheduler::mockRequestHardwareVsync, so no calls to
157     // ISchedulerCallback::requestHardwareVsync are expected during setPowerModeInternal.
158     mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON);
159     mFlinger.setPowerModeInternal(mOuterDisplay, PowerMode::ON);
160 
161     EXPECT_TRUE(mInnerDisplay->isPoweredOn());
162     EXPECT_TRUE(mOuterDisplay->isPoweredOn());
163 
164     auto& scheduler = *mFlinger.scheduler();
165     scheduler.onHardwareVsyncRequest(mInnerDisplay->getPhysicalId(), true);
166     scheduler.onHardwareVsyncRequest(mOuterDisplay->getPhysicalId(), true);
167 }
168 
TEST_F(FoldableTest,requestVsyncOnPowerOn)169 TEST_F(FoldableTest, requestVsyncOnPowerOn) {
170     SET_FLAG_FOR_TEST(flags::multithreaded_present, true);
171     EXPECT_CALL(mFlinger.scheduler()->mockRequestHardwareVsync, Call(kInnerDisplayId, true))
172             .Times(1);
173     EXPECT_CALL(mFlinger.scheduler()->mockRequestHardwareVsync, Call(kOuterDisplayId, true))
174             .Times(1);
175 
176     mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON);
177     mFlinger.setPowerModeInternal(mOuterDisplay, PowerMode::ON);
178 }
179 
TEST_F(FoldableTest,disableVsyncOnPowerOffPacesetter)180 TEST_F(FoldableTest, disableVsyncOnPowerOffPacesetter) {
181     SET_FLAG_FOR_TEST(flags::multithreaded_present, true);
182     // When the device boots, the inner display should be the pacesetter.
183     ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kInnerDisplayId);
184 
185     testing::InSequence seq;
186     EXPECT_CALL(mFlinger.scheduler()->mockRequestHardwareVsync, Call(kInnerDisplayId, true))
187             .Times(1);
188     EXPECT_CALL(mFlinger.scheduler()->mockRequestHardwareVsync, Call(kOuterDisplayId, true))
189             .Times(1);
190 
191     // Turning off the pacesetter will result in disabling VSYNC.
192     EXPECT_CALL(mFlinger.scheduler()->mockRequestHardwareVsync, Call(kInnerDisplayId, false))
193             .Times(1);
194 
195     mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON);
196     mFlinger.setPowerModeInternal(mOuterDisplay, PowerMode::ON);
197 
198     mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::OFF);
199 
200     // Other display is now the pacesetter.
201     ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kOuterDisplayId);
202 }
203 
204 } // namespace
205 } // namespace android
206