blob: 2d26bb37e1bdf91c244551f0c88596a21e70926d [file] [log] [blame]
Lloyd Pique24b0a482018-03-09 18:52:26 -08001/*
2 * Copyright (C) 2018 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 <gmock/gmock.h>
21#include <gtest/gtest.h>
22
23#include <log/log.h>
24
25#include <utils/Errors.h>
26
27#include "AsyncCallRecorder.h"
Ana Krulecfefcb582018-08-07 14:22:37 -070028#include "Scheduler/EventThread.h"
Lloyd Pique24b0a482018-03-09 18:52:26 -080029
30using namespace std::chrono_literals;
31using namespace std::placeholders;
32
33using testing::_;
34using testing::Invoke;
35
36namespace android {
37namespace {
38
39class MockVSyncSource : public VSyncSource {
40public:
41 MOCK_METHOD1(setVSyncEnabled, void(bool));
42 MOCK_METHOD1(setCallback, void(VSyncSource::Callback*));
43 MOCK_METHOD1(setPhaseOffset, void(nsecs_t));
44};
45
46} // namespace
47
48class EventThreadTest : public testing::Test {
49protected:
Ana Krulec85c39af2018-12-26 17:29:57 -080050 class MockEventThreadConnection : public android::EventThreadConnection {
Lloyd Pique24b0a482018-03-09 18:52:26 -080051 public:
52 explicit MockEventThreadConnection(android::impl::EventThread* eventThread)
Ana Krulec85c39af2018-12-26 17:29:57 -080053 : android::EventThreadConnection(eventThread) {}
Lloyd Pique24b0a482018-03-09 18:52:26 -080054 MOCK_METHOD1(postEvent, status_t(const DisplayEventReceiver::Event& event));
55 };
56
57 using ConnectionEventRecorder =
58 AsyncCallRecorderWithCannedReturn<status_t (*)(const DisplayEventReceiver::Event&)>;
59
60 EventThreadTest();
61 ~EventThreadTest() override;
62
63 void createThread();
64 sp<MockEventThreadConnection> createConnection(ConnectionEventRecorder& recorder);
65
66 void expectVSyncSetEnabledCallReceived(bool expectedState);
67 void expectVSyncSetPhaseOffsetCallReceived(nsecs_t expectedPhaseOffset);
68 VSyncSource::Callback* expectVSyncSetCallbackCallReceived();
69 void expectInterceptCallReceived(nsecs_t expectedTimestamp);
70 void expectVsyncEventReceivedByConnection(const char* name,
71 ConnectionEventRecorder& connectionEventRecorder,
72 nsecs_t expectedTimestamp, unsigned expectedCount);
73 void expectVsyncEventReceivedByConnection(nsecs_t expectedTimestamp, unsigned expectedCount);
Dominik Laskowski00a6fa22018-06-06 16:42:02 -070074 void expectHotplugEventReceivedByConnection(EventThread::DisplayType expectedDisplayType,
75 bool expectedConnected);
Lloyd Pique24b0a482018-03-09 18:52:26 -080076
77 AsyncCallRecorder<void (*)(bool)> mVSyncSetEnabledCallRecorder;
78 AsyncCallRecorder<void (*)(VSyncSource::Callback*)> mVSyncSetCallbackCallRecorder;
79 AsyncCallRecorder<void (*)(nsecs_t)> mVSyncSetPhaseOffsetCallRecorder;
80 AsyncCallRecorder<void (*)()> mResyncCallRecorder;
81 AsyncCallRecorder<void (*)(nsecs_t)> mInterceptVSyncCallRecorder;
82 ConnectionEventRecorder mConnectionEventCallRecorder{0};
83
84 MockVSyncSource mVSyncSource;
85 std::unique_ptr<android::impl::EventThread> mThread;
86 sp<MockEventThreadConnection> mConnection;
87};
88
89EventThreadTest::EventThreadTest() {
90 const ::testing::TestInfo* const test_info =
91 ::testing::UnitTest::GetInstance()->current_test_info();
92 ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
93
94 EXPECT_CALL(mVSyncSource, setVSyncEnabled(_))
95 .WillRepeatedly(Invoke(mVSyncSetEnabledCallRecorder.getInvocable()));
96
97 EXPECT_CALL(mVSyncSource, setCallback(_))
98 .WillRepeatedly(Invoke(mVSyncSetCallbackCallRecorder.getInvocable()));
99
100 EXPECT_CALL(mVSyncSource, setPhaseOffset(_))
101 .WillRepeatedly(Invoke(mVSyncSetPhaseOffsetCallRecorder.getInvocable()));
102
103 createThread();
104 mConnection = createConnection(mConnectionEventCallRecorder);
105}
106
107EventThreadTest::~EventThreadTest() {
108 const ::testing::TestInfo* const test_info =
109 ::testing::UnitTest::GetInstance()->current_test_info();
110 ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
111}
112
113void EventThreadTest::createThread() {
114 mThread =
115 std::make_unique<android::impl::EventThread>(&mVSyncSource,
116 mResyncCallRecorder.getInvocable(),
117 mInterceptVSyncCallRecorder.getInvocable(),
118 "unit-test-event-thread");
119}
120
121sp<EventThreadTest::MockEventThreadConnection> EventThreadTest::createConnection(
122 ConnectionEventRecorder& recorder) {
123 sp<MockEventThreadConnection> connection = new MockEventThreadConnection(mThread.get());
124 EXPECT_CALL(*connection, postEvent(_)).WillRepeatedly(Invoke(recorder.getInvocable()));
125 return connection;
126}
127
128void EventThreadTest::expectVSyncSetEnabledCallReceived(bool expectedState) {
129 auto args = mVSyncSetEnabledCallRecorder.waitForCall();
130 ASSERT_TRUE(args.has_value());
131 EXPECT_EQ(expectedState, std::get<0>(args.value()));
132}
133
134void EventThreadTest::expectVSyncSetPhaseOffsetCallReceived(nsecs_t expectedPhaseOffset) {
135 auto args = mVSyncSetPhaseOffsetCallRecorder.waitForCall();
136 ASSERT_TRUE(args.has_value());
137 EXPECT_EQ(expectedPhaseOffset, std::get<0>(args.value()));
138}
139
140VSyncSource::Callback* EventThreadTest::expectVSyncSetCallbackCallReceived() {
141 auto callbackSet = mVSyncSetCallbackCallRecorder.waitForCall();
142 return callbackSet.has_value() ? std::get<0>(callbackSet.value()) : nullptr;
143}
144
145void EventThreadTest::expectInterceptCallReceived(nsecs_t expectedTimestamp) {
146 auto args = mInterceptVSyncCallRecorder.waitForCall();
147 ASSERT_TRUE(args.has_value());
148 EXPECT_EQ(expectedTimestamp, std::get<0>(args.value()));
149}
150
151void EventThreadTest::expectVsyncEventReceivedByConnection(
152 const char* name, ConnectionEventRecorder& connectionEventRecorder,
153 nsecs_t expectedTimestamp, unsigned expectedCount) {
154 auto args = connectionEventRecorder.waitForCall();
155 ASSERT_TRUE(args.has_value()) << name << " did not receive an event for timestamp "
156 << expectedTimestamp;
157 const auto& event = std::get<0>(args.value());
158 EXPECT_EQ(DisplayEventReceiver::DISPLAY_EVENT_VSYNC, event.header.type)
159 << name << " did not get the correct event for timestamp " << expectedTimestamp;
160 EXPECT_EQ(expectedTimestamp, event.header.timestamp)
161 << name << " did not get the expected timestamp for timestamp " << expectedTimestamp;
162 EXPECT_EQ(expectedCount, event.vsync.count)
163 << name << " did not get the expected count for timestamp " << expectedTimestamp;
164}
165
166void EventThreadTest::expectVsyncEventReceivedByConnection(nsecs_t expectedTimestamp,
167 unsigned expectedCount) {
168 expectVsyncEventReceivedByConnection("mConnectionEventCallRecorder",
169 mConnectionEventCallRecorder, expectedTimestamp,
170 expectedCount);
171}
172
Dominik Laskowski00a6fa22018-06-06 16:42:02 -0700173void EventThreadTest::expectHotplugEventReceivedByConnection(
174 EventThread::DisplayType expectedDisplayType, bool expectedConnected) {
175 const uint32_t expectedDisplayId =
176 expectedDisplayType == EventThread::DisplayType::Primary ? 0 : 1;
177
Lloyd Pique24b0a482018-03-09 18:52:26 -0800178 auto args = mConnectionEventCallRecorder.waitForCall();
179 ASSERT_TRUE(args.has_value());
180 const auto& event = std::get<0>(args.value());
181 EXPECT_EQ(DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG, event.header.type);
Dominik Laskowski00a6fa22018-06-06 16:42:02 -0700182 EXPECT_EQ(expectedDisplayId, event.header.id);
Lloyd Pique24b0a482018-03-09 18:52:26 -0800183 EXPECT_EQ(expectedConnected, event.hotplug.connected);
184}
185
186namespace {
187
188/* ------------------------------------------------------------------------
189 * Test cases
190 */
191
192TEST_F(EventThreadTest, canCreateAndDestroyThreadWithNoEventsSent) {
193 EXPECT_FALSE(mVSyncSetEnabledCallRecorder.waitForUnexpectedCall().has_value());
194 EXPECT_FALSE(mVSyncSetCallbackCallRecorder.waitForCall(0us).has_value());
195 EXPECT_FALSE(mVSyncSetPhaseOffsetCallRecorder.waitForCall(0us).has_value());
196 EXPECT_FALSE(mResyncCallRecorder.waitForCall(0us).has_value());
197 EXPECT_FALSE(mInterceptVSyncCallRecorder.waitForCall(0us).has_value());
198 EXPECT_FALSE(mConnectionEventCallRecorder.waitForCall(0us).has_value());
199}
200
201TEST_F(EventThreadTest, requestNextVsyncPostsASingleVSyncEventToTheConnection) {
202 // Signal that we want the next vsync event to be posted to the connection
Ana Krulec7d1d6832018-12-27 11:10:09 -0800203 mThread->requestNextVsync(mConnection, false);
Lloyd Pique24b0a482018-03-09 18:52:26 -0800204
205 // EventThread should immediately request a resync.
206 EXPECT_TRUE(mResyncCallRecorder.waitForCall().has_value());
207
208 // EventThread should enable vsync callbacks, and set a callback interface
209 // pointer to use them with the VSync source.
210 expectVSyncSetEnabledCallReceived(true);
211 auto callback = expectVSyncSetCallbackCallReceived();
212 ASSERT_TRUE(callback);
213
214 // Use the received callback to signal a first vsync event.
215 // The interceptor should receive the event, as well as the connection.
216 callback->onVSyncEvent(123);
217 expectInterceptCallReceived(123);
218 expectVsyncEventReceivedByConnection(123, 1u);
219
220 // Use the received callback to signal a second vsync event.
221 // The interceptor should receive the event, but the the connection should
222 // not as it was only interested in the first.
223 callback->onVSyncEvent(456);
224 expectInterceptCallReceived(456);
225 EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value());
226
227 // EventThread should also detect that at this point that it does not need
228 // any more vsync events, and should disable their generation.
229 expectVSyncSetEnabledCallReceived(false);
230}
231
232TEST_F(EventThreadTest, setVsyncRateZeroPostsNoVSyncEventsToThatConnection) {
233 // Create a first connection, register it, and request a vsync rate of zero.
234 ConnectionEventRecorder firstConnectionEventRecorder{0};
235 sp<MockEventThreadConnection> firstConnection = createConnection(firstConnectionEventRecorder);
236 mThread->setVsyncRate(0, firstConnection);
237
238 // By itself, this should not enable vsync events
239 EXPECT_FALSE(mVSyncSetEnabledCallRecorder.waitForUnexpectedCall().has_value());
240 EXPECT_FALSE(mVSyncSetCallbackCallRecorder.waitForCall(0us).has_value());
241
242 // However if there is another connection which wants events at a nonzero rate.....
243 ConnectionEventRecorder secondConnectionEventRecorder{0};
244 sp<MockEventThreadConnection> secondConnection =
245 createConnection(secondConnectionEventRecorder);
246 mThread->setVsyncRate(1, secondConnection);
247
248 // EventThread should enable vsync callbacks, and set a callback interface
249 // pointer to use them with the VSync source.
250 expectVSyncSetEnabledCallReceived(true);
251 auto callback = expectVSyncSetCallbackCallReceived();
252 ASSERT_TRUE(callback);
253
254 // Send a vsync event. EventThread should then make a call to the
255 // interceptor, and the second connection. The first connection should not
256 // get the event.
257 callback->onVSyncEvent(123);
258 expectInterceptCallReceived(123);
259 EXPECT_FALSE(firstConnectionEventRecorder.waitForUnexpectedCall().has_value());
260 expectVsyncEventReceivedByConnection("secondConnection", secondConnectionEventRecorder, 123,
261 1u);
262}
263
264TEST_F(EventThreadTest, setVsyncRateOnePostsAllEventsToThatConnection) {
265 mThread->setVsyncRate(1, mConnection);
266
267 // EventThread should enable vsync callbacks, and set a callback interface
268 // pointer to use them with the VSync source.
269 expectVSyncSetEnabledCallReceived(true);
270 auto callback = expectVSyncSetCallbackCallReceived();
271 ASSERT_TRUE(callback);
272
273 // Send a vsync event. EventThread should then make a call to the
274 // interceptor, and the connection.
275 callback->onVSyncEvent(123);
276 expectInterceptCallReceived(123);
277 expectVsyncEventReceivedByConnection(123, 1u);
278
279 // A second event should go to the same places.
280 callback->onVSyncEvent(456);
281 expectInterceptCallReceived(456);
282 expectVsyncEventReceivedByConnection(456, 2u);
283
284 // A third event should go to the same places.
285 callback->onVSyncEvent(789);
286 expectInterceptCallReceived(789);
287 expectVsyncEventReceivedByConnection(789, 3u);
288}
289
290TEST_F(EventThreadTest, setVsyncRateTwoPostsEveryOtherEventToThatConnection) {
291 mThread->setVsyncRate(2, mConnection);
292
293 // EventThread should enable vsync callbacks, and set a callback interface
294 // pointer to use them with the VSync source.
295 expectVSyncSetEnabledCallReceived(true);
296 auto callback = expectVSyncSetCallbackCallReceived();
297 ASSERT_TRUE(callback);
298
299 // The first event will be seen by the interceptor, and not the connection.
300 callback->onVSyncEvent(123);
301 expectInterceptCallReceived(123);
302 EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value());
303
304 // The second event will be seen by the interceptor and the connection.
305 callback->onVSyncEvent(456);
306 expectInterceptCallReceived(456);
307 expectVsyncEventReceivedByConnection(456, 2u);
308
309 // The third event will be seen by the interceptor, and not the connection.
310 callback->onVSyncEvent(789);
311 expectInterceptCallReceived(789);
312 EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value());
313
314 // The fourth event will be seen by the interceptor and the connection.
315 callback->onVSyncEvent(101112);
316 expectInterceptCallReceived(101112);
317 expectVsyncEventReceivedByConnection(101112, 4u);
318}
319
320TEST_F(EventThreadTest, connectionsRemovedIfInstanceDestroyed) {
321 mThread->setVsyncRate(1, mConnection);
322
323 // EventThread should enable vsync callbacks, and set a callback interface
324 // pointer to use them with the VSync source.
325 expectVSyncSetEnabledCallReceived(true);
326 auto callback = expectVSyncSetCallbackCallReceived();
327 ASSERT_TRUE(callback);
328
329 // Destroy the only (strong) reference to the connection.
330 mConnection = nullptr;
331
332 // The first event will be seen by the interceptor, and not the connection.
333 callback->onVSyncEvent(123);
334 expectInterceptCallReceived(123);
335 EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value());
336
337 // EventThread should disable vsync callbacks
338 expectVSyncSetEnabledCallReceived(false);
339}
340
341TEST_F(EventThreadTest, connectionsRemovedIfEventDeliveryError) {
342 ConnectionEventRecorder errorConnectionEventRecorder{NO_MEMORY};
343 sp<MockEventThreadConnection> errorConnection = createConnection(errorConnectionEventRecorder);
344 mThread->setVsyncRate(1, errorConnection);
345
346 // EventThread should enable vsync callbacks, and set a callback interface
347 // pointer to use them with the VSync source.
348 expectVSyncSetEnabledCallReceived(true);
349 auto callback = expectVSyncSetCallbackCallReceived();
350 ASSERT_TRUE(callback);
351
352 // The first event will be seen by the interceptor, and by the connection,
353 // which then returns an error.
354 callback->onVSyncEvent(123);
355 expectInterceptCallReceived(123);
356 expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 123, 1u);
357
358 // A subsequent event will be seen by the interceptor and not by the
359 // connection.
360 callback->onVSyncEvent(456);
361 expectInterceptCallReceived(456);
362 EXPECT_FALSE(errorConnectionEventRecorder.waitForUnexpectedCall().has_value());
363
364 // EventThread should disable vsync callbacks with the second event
365 expectVSyncSetEnabledCallReceived(false);
366}
367
368TEST_F(EventThreadTest, eventsDroppedIfNonfatalEventDeliveryError) {
369 ConnectionEventRecorder errorConnectionEventRecorder{WOULD_BLOCK};
370 sp<MockEventThreadConnection> errorConnection = createConnection(errorConnectionEventRecorder);
371 mThread->setVsyncRate(1, errorConnection);
372
373 // EventThread should enable vsync callbacks, and set a callback interface
374 // pointer to use them with the VSync source.
375 expectVSyncSetEnabledCallReceived(true);
376 auto callback = expectVSyncSetCallbackCallReceived();
377 ASSERT_TRUE(callback);
378
379 // The first event will be seen by the interceptor, and by the connection,
380 // which then returns an non-fatal error.
381 callback->onVSyncEvent(123);
382 expectInterceptCallReceived(123);
383 expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 123, 1u);
384
385 // A subsequent event will be seen by the interceptor, and by the connection,
386 // which still then returns an non-fatal error.
387 callback->onVSyncEvent(456);
388 expectInterceptCallReceived(456);
389 expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 456, 2u);
390
391 // EventThread will not disable vsync callbacks as the errors are non-fatal.
392 EXPECT_FALSE(mVSyncSetEnabledCallRecorder.waitForUnexpectedCall().has_value());
393}
394
395TEST_F(EventThreadTest, setPhaseOffsetForwardsToVSyncSource) {
396 mThread->setPhaseOffset(321);
397 expectVSyncSetPhaseOffsetCallReceived(321);
398}
399
400TEST_F(EventThreadTest, postHotplugPrimaryDisconnect) {
Dominik Laskowski00a6fa22018-06-06 16:42:02 -0700401 mThread->onHotplugReceived(EventThread::DisplayType::Primary, false);
402 expectHotplugEventReceivedByConnection(EventThread::DisplayType::Primary, false);
Lloyd Pique24b0a482018-03-09 18:52:26 -0800403}
404
405TEST_F(EventThreadTest, postHotplugPrimaryConnect) {
Dominik Laskowski00a6fa22018-06-06 16:42:02 -0700406 mThread->onHotplugReceived(EventThread::DisplayType::Primary, true);
407 expectHotplugEventReceivedByConnection(EventThread::DisplayType::Primary, true);
Lloyd Pique24b0a482018-03-09 18:52:26 -0800408}
409
410TEST_F(EventThreadTest, postHotplugExternalDisconnect) {
Dominik Laskowski00a6fa22018-06-06 16:42:02 -0700411 mThread->onHotplugReceived(EventThread::DisplayType::External, false);
412 expectHotplugEventReceivedByConnection(EventThread::DisplayType::External, false);
Lloyd Pique24b0a482018-03-09 18:52:26 -0800413}
414
415TEST_F(EventThreadTest, postHotplugExternalConnect) {
Dominik Laskowski00a6fa22018-06-06 16:42:02 -0700416 mThread->onHotplugReceived(EventThread::DisplayType::External, true);
417 expectHotplugEventReceivedByConnection(EventThread::DisplayType::External, true);
Lloyd Pique24b0a482018-03-09 18:52:26 -0800418}
419
420} // namespace
421} // namespace android