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