• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2019 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 // TODO(b/129481165): remove the #pragma below and fix conversion issues
18 #pragma clang diagnostic push
19 #pragma clang diagnostic ignored "-Wconversion"
20 
21 #undef LOG_TAG
22 #define LOG_TAG "CompositionTest"
23 
24 #include <compositionengine/Display.h>
25 #include <compositionengine/mock/DisplaySurface.h>
26 #include <gmock/gmock.h>
27 #include <gtest/gtest.h>
28 #include <gui/SurfaceComposerClient.h>
29 #include <log/log.h>
30 #include <utils/String8.h>
31 
32 #include "TestableScheduler.h"
33 #include "TestableSurfaceFlinger.h"
34 #include "mock/MockDispSync.h"
35 #include "mock/MockEventControlThread.h"
36 #include "mock/MockEventThread.h"
37 #include "mock/MockMessageQueue.h"
38 
39 namespace android {
40 
41 using testing::_;
42 using testing::Return;
43 
44 using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector;
45 
46 class TransactionApplicationTest : public testing::Test {
47 public:
TransactionApplicationTest()48     TransactionApplicationTest() {
49         const ::testing::TestInfo* const test_info =
50                 ::testing::UnitTest::GetInstance()->current_test_info();
51         ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
52 
53         mFlinger.mutableEventQueue().reset(mMessageQueue);
54         setupScheduler();
55     }
56 
~TransactionApplicationTest()57     ~TransactionApplicationTest() {
58         const ::testing::TestInfo* const test_info =
59                 ::testing::UnitTest::GetInstance()->current_test_info();
60         ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
61     }
62 
setupScheduler()63     void setupScheduler() {
64         auto eventThread = std::make_unique<mock::EventThread>();
65         auto sfEventThread = std::make_unique<mock::EventThread>();
66 
67         EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
68         EXPECT_CALL(*eventThread, createEventConnection(_, _))
69                 .WillOnce(Return(
70                         new EventThreadConnection(eventThread.get(), ResyncCallback(),
71                                                   ISurfaceComposer::eConfigChangedSuppress)));
72 
73         EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
74         EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
75                 .WillOnce(Return(
76                         new EventThreadConnection(sfEventThread.get(), ResyncCallback(),
77                                                   ISurfaceComposer::eConfigChangedSuppress)));
78 
79         EXPECT_CALL(*mPrimaryDispSync, computeNextRefresh(0, _)).WillRepeatedly(Return(0));
80         EXPECT_CALL(*mPrimaryDispSync, getPeriod())
81                 .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_REFRESH_RATE));
82 
83         mFlinger.setupScheduler(std::unique_ptr<mock::DispSync>(mPrimaryDispSync),
84                                 std::make_unique<mock::EventControlThread>(),
85                                 std::move(eventThread), std::move(sfEventThread));
86     }
87 
88     TestableScheduler* mScheduler;
89     TestableSurfaceFlinger mFlinger;
90 
91     std::unique_ptr<mock::EventThread> mEventThread = std::make_unique<mock::EventThread>();
92     mock::EventControlThread* mEventControlThread = new mock::EventControlThread();
93 
94     mock::MessageQueue* mMessageQueue = new mock::MessageQueue();
95     mock::DispSync* mPrimaryDispSync = new mock::DispSync();
96 
97     struct TransactionInfo {
98         Vector<ComposerState> states;
99         Vector<DisplayState> displays;
100         uint32_t flags = 0;
101         sp<IBinder> applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance());
102         InputWindowCommands inputWindowCommands;
103         int64_t desiredPresentTime = -1;
104         client_cache_t uncacheBuffer;
105     };
106 
checkEqual(TransactionInfo info,SurfaceFlinger::TransactionState state)107     void checkEqual(TransactionInfo info, SurfaceFlinger::TransactionState state) {
108         EXPECT_EQ(0, info.states.size());
109         EXPECT_EQ(0, state.states.size());
110 
111         EXPECT_EQ(0, info.displays.size());
112         EXPECT_EQ(0, state.displays.size());
113         EXPECT_EQ(info.flags, state.flags);
114         EXPECT_EQ(info.desiredPresentTime, state.desiredPresentTime);
115     }
116 
setupSingle(TransactionInfo & transaction,uint32_t flags,bool syncInputWindows,int64_t desiredPresentTime)117     void setupSingle(TransactionInfo& transaction, uint32_t flags, bool syncInputWindows,
118                      int64_t desiredPresentTime) {
119         mTransactionNumber++;
120         transaction.flags |= flags; // ISurfaceComposer::eSynchronous;
121         transaction.inputWindowCommands.syncInputWindows = syncInputWindows;
122         transaction.desiredPresentTime = desiredPresentTime;
123     }
124 
NotPlacedOnTransactionQueue(uint32_t flags,bool syncInputWindows)125     void NotPlacedOnTransactionQueue(uint32_t flags, bool syncInputWindows) {
126         ASSERT_EQ(0, mFlinger.getTransactionQueue().size());
127         // called in SurfaceFlinger::signalTransaction
128         EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
129         EXPECT_CALL(*mPrimaryDispSync, expectedPresentTime(_)).WillOnce(Return(systemTime()));
130         TransactionInfo transaction;
131         setupSingle(transaction, flags, syncInputWindows,
132                     /*desiredPresentTime*/ -1);
133         nsecs_t applicationTime = systemTime();
134         mFlinger.setTransactionState(transaction.states, transaction.displays, transaction.flags,
135                                      transaction.applyToken, transaction.inputWindowCommands,
136                                      transaction.desiredPresentTime, transaction.uncacheBuffer,
137                                      mHasListenerCallbacks, mCallbacks);
138 
139         // This transaction should not have been placed on the transaction queue.
140         // If transaction is synchronous or syncs input windows, SF
141         // applyTransactionState should time out (5s) wating for SF to commit
142         // the transaction or to receive a signal that syncInputWindows has
143         // completed.  If this is animation, it should not time out waiting.
144         nsecs_t returnedTime = systemTime();
145         if (flags & ISurfaceComposer::eSynchronous || syncInputWindows) {
146             EXPECT_GE(returnedTime, applicationTime + s2ns(5));
147         } else {
148             EXPECT_LE(returnedTime, applicationTime + s2ns(5));
149         }
150         auto transactionQueue = mFlinger.getTransactionQueue();
151         EXPECT_EQ(0, transactionQueue.size());
152     }
153 
PlaceOnTransactionQueue(uint32_t flags,bool syncInputWindows)154     void PlaceOnTransactionQueue(uint32_t flags, bool syncInputWindows) {
155         ASSERT_EQ(0, mFlinger.getTransactionQueue().size());
156         // called in SurfaceFlinger::signalTransaction
157         EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
158 
159         // first check will see desired present time has not passed,
160         // but afterwards it will look like the desired present time has passed
161         nsecs_t time = systemTime();
162         EXPECT_CALL(*mPrimaryDispSync, expectedPresentTime(_))
163                 .WillOnce(Return(time + nsecs_t(5 * 1e8)));
164         TransactionInfo transaction;
165         setupSingle(transaction, flags, syncInputWindows,
166                     /*desiredPresentTime*/ time + s2ns(1));
167         nsecs_t applicationSentTime = systemTime();
168         mFlinger.setTransactionState(transaction.states, transaction.displays, transaction.flags,
169                                      transaction.applyToken, transaction.inputWindowCommands,
170                                      transaction.desiredPresentTime, transaction.uncacheBuffer,
171                                      mHasListenerCallbacks, mCallbacks);
172 
173         nsecs_t returnedTime = systemTime();
174         EXPECT_LE(returnedTime, applicationSentTime + s2ns(5));
175         // This transaction should have been placed on the transaction queue
176         auto transactionQueue = mFlinger.getTransactionQueue();
177         EXPECT_EQ(1, transactionQueue.size());
178     }
179 
BlockedByPriorTransaction(uint32_t flags,bool syncInputWindows)180     void BlockedByPriorTransaction(uint32_t flags, bool syncInputWindows) {
181         ASSERT_EQ(0, mFlinger.getTransactionQueue().size());
182         // called in SurfaceFlinger::signalTransaction
183         nsecs_t time = systemTime();
184         EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
185         EXPECT_CALL(*mPrimaryDispSync, expectedPresentTime(_))
186                 .WillOnce(Return(time + nsecs_t(5 * 1e8)));
187         // transaction that should go on the pending thread
188         TransactionInfo transactionA;
189         setupSingle(transactionA, /*flags*/ 0, /*syncInputWindows*/ false,
190                     /*desiredPresentTime*/ time + s2ns(1));
191 
192         // transaction that would not have gone on the pending thread if not
193         // blocked
194         TransactionInfo transactionB;
195         setupSingle(transactionB, flags, syncInputWindows,
196                     /*desiredPresentTime*/ -1);
197 
198         nsecs_t applicationSentTime = systemTime();
199         mFlinger.setTransactionState(transactionA.states, transactionA.displays, transactionA.flags,
200                                      transactionA.applyToken, transactionA.inputWindowCommands,
201                                      transactionA.desiredPresentTime, transactionA.uncacheBuffer,
202                                      mHasListenerCallbacks, mCallbacks);
203 
204         // This thread should not have been blocked by the above transaction
205         // (5s is the timeout period that applyTransactionState waits for SF to
206         // commit the transaction)
207         EXPECT_LE(systemTime(), applicationSentTime + s2ns(5));
208 
209         applicationSentTime = systemTime();
210         mFlinger.setTransactionState(transactionB.states, transactionB.displays, transactionB.flags,
211                                      transactionB.applyToken, transactionB.inputWindowCommands,
212                                      transactionB.desiredPresentTime, transactionB.uncacheBuffer,
213                                      mHasListenerCallbacks, mCallbacks);
214 
215         // this thread should have been blocked by the above transaction
216         // if this is an animation, this thread should be blocked for 5s
217         // in setTransactionState waiting for transactionA to flush.  Otherwise,
218         // the transaction should be placed on the pending queue
219         if (flags & ISurfaceComposer::eAnimation) {
220             EXPECT_GE(systemTime(), applicationSentTime + s2ns(5));
221         } else {
222             EXPECT_LE(systemTime(), applicationSentTime + s2ns(5));
223         }
224 
225         // check that there is one binder on the pending queue.
226         auto transactionQueue = mFlinger.getTransactionQueue();
227         EXPECT_EQ(1, transactionQueue.size());
228 
229         auto& [applyToken, transactionStates] = *(transactionQueue.begin());
230         EXPECT_EQ(2, transactionStates.size());
231 
232         auto& transactionStateA = transactionStates.front();
233         transactionStates.pop();
234         checkEqual(transactionA, transactionStateA);
235         auto& transactionStateB = transactionStates.front();
236         checkEqual(transactionB, transactionStateB);
237     }
238 
239     bool mHasListenerCallbacks = false;
240     std::vector<ListenerCallbacks> mCallbacks;
241     int mTransactionNumber = 0;
242 };
243 
TEST_F(TransactionApplicationTest,Flush_RemovesFromQueue)244 TEST_F(TransactionApplicationTest, Flush_RemovesFromQueue) {
245     ASSERT_EQ(0, mFlinger.getTransactionQueue().size());
246     // called in SurfaceFlinger::signalTransaction
247     EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
248 
249     // nsecs_t time = systemTime();
250     EXPECT_CALL(*mPrimaryDispSync, expectedPresentTime(_))
251             .WillOnce(Return(nsecs_t(5 * 1e8)))
252             .WillOnce(Return(s2ns(2)));
253     TransactionInfo transactionA; // transaction to go on pending queue
254     setupSingle(transactionA, /*flags*/ 0, /*syncInputWindows*/ false,
255                 /*desiredPresentTime*/ s2ns(1));
256     mFlinger.setTransactionState(transactionA.states, transactionA.displays, transactionA.flags,
257                                  transactionA.applyToken, transactionA.inputWindowCommands,
258                                  transactionA.desiredPresentTime, transactionA.uncacheBuffer,
259                                  mHasListenerCallbacks, mCallbacks);
260 
261     auto& transactionQueue = mFlinger.getTransactionQueue();
262     ASSERT_EQ(1, transactionQueue.size());
263 
264     auto& [applyToken, transactionStates] = *(transactionQueue.begin());
265     ASSERT_EQ(1, transactionStates.size());
266 
267     auto& transactionState = transactionStates.front();
268     checkEqual(transactionA, transactionState);
269 
270     // because flushing uses the cached expected present time, we send an empty
271     // transaction here (sending a null applyToken to fake it as from a
272     // different process) to re-query and reset the cached expected present time
273     TransactionInfo empty;
274     empty.applyToken = sp<IBinder>();
275     mFlinger.setTransactionState(empty.states, empty.displays, empty.flags, empty.applyToken,
276                                  empty.inputWindowCommands, empty.desiredPresentTime,
277                                  empty.uncacheBuffer, mHasListenerCallbacks, mCallbacks);
278 
279     // flush transaction queue should flush as desiredPresentTime has
280     // passed
281     mFlinger.flushTransactionQueues();
282 
283     EXPECT_EQ(0, transactionQueue.size());
284 }
285 
TEST_F(TransactionApplicationTest,NotPlacedOnTransactionQueue_Synchronous)286 TEST_F(TransactionApplicationTest, NotPlacedOnTransactionQueue_Synchronous) {
287     NotPlacedOnTransactionQueue(ISurfaceComposer::eSynchronous, /*syncInputWindows*/ false);
288 }
289 
TEST_F(TransactionApplicationTest,NotPlacedOnTransactionQueue_Animation)290 TEST_F(TransactionApplicationTest, NotPlacedOnTransactionQueue_Animation) {
291     NotPlacedOnTransactionQueue(ISurfaceComposer::eAnimation, /*syncInputWindows*/ false);
292 }
293 
TEST_F(TransactionApplicationTest,NotPlacedOnTransactionQueue_SyncInputWindows)294 TEST_F(TransactionApplicationTest, NotPlacedOnTransactionQueue_SyncInputWindows) {
295     NotPlacedOnTransactionQueue(/*flags*/ 0, /*syncInputWindows*/ true);
296 }
297 
TEST_F(TransactionApplicationTest,PlaceOnTransactionQueue_Synchronous)298 TEST_F(TransactionApplicationTest, PlaceOnTransactionQueue_Synchronous) {
299     PlaceOnTransactionQueue(ISurfaceComposer::eSynchronous, /*syncInputWindows*/ false);
300 }
301 
TEST_F(TransactionApplicationTest,PlaceOnTransactionQueue_Animation)302 TEST_F(TransactionApplicationTest, PlaceOnTransactionQueue_Animation) {
303     PlaceOnTransactionQueue(ISurfaceComposer::eAnimation, /*syncInputWindows*/ false);
304 }
305 
TEST_F(TransactionApplicationTest,PlaceOnTransactionQueue_SyncInputWindows)306 TEST_F(TransactionApplicationTest, PlaceOnTransactionQueue_SyncInputWindows) {
307     PlaceOnTransactionQueue(/*flags*/ 0, /*syncInputWindows*/ true);
308 }
309 
TEST_F(TransactionApplicationTest,BlockWithPriorTransaction_Synchronous)310 TEST_F(TransactionApplicationTest, BlockWithPriorTransaction_Synchronous) {
311     BlockedByPriorTransaction(ISurfaceComposer::eSynchronous, /*syncInputWindows*/ false);
312 }
313 
TEST_F(TransactionApplicationTest,BlockWithPriorTransaction_Animation)314 TEST_F(TransactionApplicationTest, BlockWithPriorTransaction_Animation) {
315     BlockedByPriorTransaction(ISurfaceComposer::eSynchronous, /*syncInputWindows*/ false);
316 }
317 
TEST_F(TransactionApplicationTest,BlockWithPriorTransaction_SyncInputWindows)318 TEST_F(TransactionApplicationTest, BlockWithPriorTransaction_SyncInputWindows) {
319     BlockedByPriorTransaction(/*flags*/ 0, /*syncInputWindows*/ true);
320 }
321 
TEST_F(TransactionApplicationTest,FromHandle)322 TEST_F(TransactionApplicationTest, FromHandle) {
323     sp<IBinder> badHandle;
324     auto ret = mFlinger.fromHandle(badHandle);
325     EXPECT_EQ(nullptr, ret.promote().get());
326 }
327 } // namespace android
328 
329 // TODO(b/129481165): remove the #pragma below and fix conversion issues
330 #pragma clang diagnostic pop // ignored "-Wconversion"
331