1 /*
2 * Copyright (C) 2016 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
18 #include <ChoreographerTestUtils.h>
19 #include <android/choreographer.h>
20 #include <android/looper.h>
21 #include <jni.h>
22 #include <sys/time.h>
23 #include <time.h>
24
25 #include <chrono>
26 #include <cmath>
27 #include <cstdlib>
28 #include <cstring>
29 #include <limits>
30 #include <mutex>
31 #include <set>
32 #include <sstream>
33 #include <string>
34 #include <thread>
35 #include <tuple>
36 #include <vector>
37
38 #define LOG_TAG "ChoreographerNativeTest"
39
40
41 using namespace std::chrono_literals;
42
43 struct {
44 struct {
45 jclass clazz;
46 jmethodID checkRefreshRateIsCurrentAndSwitch;
47 } choreographerNativeTest;
48 } gJni;
49
50 static std::set<int64_t> gSupportedRefreshPeriods;
51
52 struct RefreshRateCallback {
RefreshRateCallbackRefreshRateCallback53 RefreshRateCallback(const char* name): name(name) {}
54 std::string name;
55 int count{0};
56 std::chrono::nanoseconds vsyncPeriod{0LL};
57 };
58
59 struct RefreshRateCallbackWithDisplayManager {
RefreshRateCallbackWithDisplayManagerRefreshRateCallbackWithDisplayManager60 RefreshRateCallbackWithDisplayManager(const char* name, JNIEnv* env, jobject clazz)
61 : name(name), env(env), clazz(clazz) {}
62 std::string name;
63 JNIEnv* env;
64 jobject clazz;
65 int count{0};
66 std::chrono::nanoseconds vsyncPeriod{0LL};
67 };
68
refreshRateCallback(int64_t vsyncPeriodNanos,void * data)69 static void refreshRateCallback(int64_t vsyncPeriodNanos, void* data) {
70 std::lock_guard<std::mutex> _l(gLock);
71 RefreshRateCallback* cb = static_cast<RefreshRateCallback*>(data);
72 cb->count++;
73 cb->vsyncPeriod = std::chrono::nanoseconds{vsyncPeriodNanos};
74 }
75
refreshRateCallbackWithDisplayManager(int64_t vsyncPeriodNanos,void * data)76 static void refreshRateCallbackWithDisplayManager(int64_t vsyncPeriodNanos, void* data) {
77 std::lock_guard<std::mutex> _l(gLock);
78 RefreshRateCallbackWithDisplayManager* cb =
79 static_cast<RefreshRateCallbackWithDisplayManager*>(data);
80 cb->count++;
81 cb->vsyncPeriod = std::chrono::nanoseconds{vsyncPeriodNanos};
82 cb->env->CallVoidMethod(cb->clazz,
83 gJni.choreographerNativeTest.checkRefreshRateIsCurrentAndSwitch,
84 static_cast<int>(std::round(1e9f / cb->vsyncPeriod.count())));
85 }
86
dumpSupportedRefreshPeriods()87 static std::string dumpSupportedRefreshPeriods() {
88 std::stringstream ss;
89 ss << "{ ";
90 for (const long& period : gSupportedRefreshPeriods) {
91 ss << period << ",";
92 }
93 ss << "}";
94 return ss.str();
95 }
96
97 template <class T>
verifyRefreshRateCallback(JNIEnv * env,const T & cb,int expectedMin)98 static void verifyRefreshRateCallback(JNIEnv* env, const T& cb, int expectedMin) {
99 std::lock_guard<std::mutex> _l(gLock);
100 ASSERT(cb.count >= expectedMin, "Choreographer failed to invoke '%s' %d times - actual: %d",
101 cb.name.c_str(), expectedMin, cb.count);
102 // Unfortunately we can't verify the specific vsync period as public apis
103 // don't provide a guarantee that we adhere to a particular refresh rate.
104 // The best we can do is check that the reported period is contained in the
105 // set of supported periods.
106 ASSERT(cb.vsyncPeriod > ZERO,
107 "Choreographer failed to report a nonzero refresh period invoking '%s'",
108 cb.name.c_str());
109 ASSERT(gSupportedRefreshPeriods.count(cb.vsyncPeriod.count()) > 0,
110 "Choreographer failed to report a supported refresh period invoking '%s': supported "
111 "periods: %s, actual: %lu",
112 cb.name.c_str(), dumpSupportedRefreshPeriods().c_str(), cb.vsyncPeriod.count());
113 }
114
resetRefreshRateCallback(RefreshRateCallback & cb)115 static void resetRefreshRateCallback(RefreshRateCallback& cb) {
116 std::lock_guard<std::mutex> _l(gLock);
117 cb.count = 0;
118 }
119
android_view_cts_ChoreographerNativeTest_getChoreographer(JNIEnv *,jclass)120 static jlong android_view_cts_ChoreographerNativeTest_getChoreographer(JNIEnv*, jclass) {
121 std::lock_guard<std::mutex> _l{gLock};
122 return reinterpret_cast<jlong>(AChoreographer_getInstance());
123 }
124
android_view_cts_ChoreographerNativeTest_prepareChoreographerTests(JNIEnv * env,jclass,jlong choreographerPtr,jlongArray supportedRefreshPeriods)125 static jboolean android_view_cts_ChoreographerNativeTest_prepareChoreographerTests(JNIEnv* env, jclass,
126 jlong choreographerPtr, jlongArray supportedRefreshPeriods) {
127 std::lock_guard<std::mutex> _l{gLock};
128 AChoreographer* choreographer = reinterpret_cast<AChoreographer*>(choreographerPtr);
129 const size_t count = env->GetArrayLength(supportedRefreshPeriods);
130 const jlong* vals = env->GetLongArrayElements(supportedRefreshPeriods, nullptr);
131 for (size_t i = 0; i < count; ++i) {
132 gSupportedRefreshPeriods.insert(vals[i]);
133 }
134 env->ReleaseLongArrayElements(supportedRefreshPeriods, const_cast<jlong*>(vals), JNI_ABORT);
135 return choreographer != nullptr;
136 }
137
138 static void
android_view_cts_ChoreographerNativeTest_testPostVsyncCallbackWithoutDelayEventuallyRunsCallback(JNIEnv * env,jclass,jlong choreographerPtr)139 android_view_cts_ChoreographerNativeTest_testPostVsyncCallbackWithoutDelayEventuallyRunsCallback(
140 JNIEnv* env, jclass, jlong choreographerPtr) {
141 AChoreographer* choreographer = reinterpret_cast<AChoreographer*>(choreographerPtr);
142 VsyncCallback cb1("cb1", env);
143 VsyncCallback cb2("cb2", env);
144 auto start = now();
145
146 AChoreographer_postVsyncCallback(choreographer, vsyncCallback, &cb1);
147 AChoreographer_postVsyncCallback(choreographer, vsyncCallback, &cb2);
148 std::this_thread::sleep_for(NOMINAL_VSYNC_PERIOD * 3);
149
150 verifyCallback(env, cb1, 1, start, NOMINAL_VSYNC_PERIOD * 3);
151 verifyCallback(env, cb2, 1, start, NOMINAL_VSYNC_PERIOD * 3);
152 {
153 std::lock_guard<std::mutex> _l{gLock};
154 auto delta = cb2.frameTime - cb1.frameTime;
155 ASSERT(delta == ZERO || delta > ZERO && delta < NOMINAL_VSYNC_PERIOD * 2,
156 "Callback 1 and 2 have frame times too large of a delta in frame times");
157 }
158
159 AChoreographer_postVsyncCallback(choreographer, vsyncCallback, &cb1);
160 start = now();
161 std::this_thread::sleep_for(NOMINAL_VSYNC_PERIOD * 3);
162 verifyCallback(env, cb1, 2, start, NOMINAL_VSYNC_PERIOD * 3);
163 verifyCallback(env, cb2, 1, start, ZERO);
164 }
165
android_view_cts_ChoreographerNativeTest_testFrameCallbackDataVsyncIdValid(JNIEnv * env,jclass,jlong choreographerPtr)166 static void android_view_cts_ChoreographerNativeTest_testFrameCallbackDataVsyncIdValid(
167 JNIEnv* env, jclass, jlong choreographerPtr) {
168 AChoreographer* choreographer = reinterpret_cast<AChoreographer*>(choreographerPtr);
169 VsyncCallback cb1("cb1", env);
170 auto start = now();
171
172 AChoreographer_postVsyncCallback(choreographer, vsyncCallback, &cb1);
173 std::this_thread::sleep_for(NOMINAL_VSYNC_PERIOD * 3);
174
175 verifyCallback(env, cb1, 1, start, NOMINAL_VSYNC_PERIOD * 3);
176 std::lock_guard<std::mutex> _l{gLock};
177 for (const VsyncCallback::FrameTime& frameTime : cb1.getTimeline()) {
178 int64_t vsyncId = frameTime.vsyncId;
179 ASSERT(vsyncId >= 0, "Invalid vsync ID");
180 ASSERT(std::count_if(cb1.getTimeline().begin(), cb1.getTimeline().end(),
181 [vsyncId](const VsyncCallback::FrameTime& ft) {
182 return ft.vsyncId == vsyncId;
183 }) == 1,
184 "Vsync ID is not unique");
185 }
186 }
187
android_view_cts_ChoreographerNativeTest_testFrameCallbackDataDeadlineInFuture(JNIEnv * env,jclass,jlong choreographerPtr)188 static void android_view_cts_ChoreographerNativeTest_testFrameCallbackDataDeadlineInFuture(
189 JNIEnv* env, jclass, jlong choreographerPtr) {
190 AChoreographer* choreographer = reinterpret_cast<AChoreographer*>(choreographerPtr);
191 VsyncCallback cb1("cb1", env);
192 auto start = now();
193
194 AChoreographer_postVsyncCallback(choreographer, vsyncCallback, &cb1);
195 std::this_thread::sleep_for(NOMINAL_VSYNC_PERIOD * 3);
196
197 verifyCallback(env, cb1, 1, start, NOMINAL_VSYNC_PERIOD * 3);
198 std::lock_guard<std::mutex> _l{gLock};
199 for (auto [i, lastValue] = std::tuple{0, cb1.frameTime}; i < cb1.getTimeline().size(); i++) {
200 auto deadline = std::chrono::nanoseconds{cb1.getTimeline()[i].deadline};
201 ASSERT(deadline > std::chrono::nanoseconds{start}, "Deadline must be after start time");
202 ASSERT(deadline > cb1.frameTime, "Deadline must be after frame time");
203 ASSERT(deadline > lastValue, "Deadline must be greater than last frame deadline");
204 lastValue = deadline;
205 }
206 }
207
208 static void
android_view_cts_ChoreographerNativeTest_testFrameCallbackDataExpectedPresentTimeInFuture(JNIEnv * env,jclass,jlong choreographerPtr)209 android_view_cts_ChoreographerNativeTest_testFrameCallbackDataExpectedPresentTimeInFuture(
210 JNIEnv* env, jclass, jlong choreographerPtr) {
211 AChoreographer* choreographer = reinterpret_cast<AChoreographer*>(choreographerPtr);
212 VsyncCallback cb1("cb1", env);
213 auto start = now();
214
215 AChoreographer_postVsyncCallback(choreographer, vsyncCallback, &cb1);
216 std::this_thread::sleep_for(NOMINAL_VSYNC_PERIOD * 3);
217
218 verifyCallback(env, cb1, 1, start, NOMINAL_VSYNC_PERIOD * 3);
219 std::lock_guard<std::mutex> _l{gLock};
220 for (auto [i, lastValue] = std::tuple{0, cb1.frameTime}; i < cb1.getTimeline().size(); i++) {
221 auto expectedPresentTime =
222 std::chrono::nanoseconds(cb1.getTimeline()[i].expectedPresentTime);
223 auto deadline = std::chrono::nanoseconds(cb1.getTimeline()[i].deadline);
224 ASSERT(expectedPresentTime > cb1.frameTime,
225 "Expected present time must be after frame time");
226 ASSERT(expectedPresentTime > deadline, "Expected present time must be after deadline");
227 ASSERT(expectedPresentTime > lastValue,
228 "Expected present time must be greater than last frame expected present time");
229 lastValue = expectedPresentTime;
230 }
231 }
232
android_view_cts_ChoreographerNativeTest_testPostCallback64WithoutDelayEventuallyRunsCallback(JNIEnv * env,jclass,jlong choreographerPtr)233 static void android_view_cts_ChoreographerNativeTest_testPostCallback64WithoutDelayEventuallyRunsCallback(
234 JNIEnv* env, jclass, jlong choreographerPtr) {
235 AChoreographer* choreographer = reinterpret_cast<AChoreographer*>(choreographerPtr);
236 Callback cb1("cb1");
237 Callback cb2("cb2");
238 auto start = now();
239
240 AChoreographer_postFrameCallback64(choreographer, frameCallback64, &cb1);
241 AChoreographer_postFrameCallback64(choreographer, frameCallback64, &cb2);
242 std::this_thread::sleep_for(NOMINAL_VSYNC_PERIOD * 3);
243
244 verifyCallback(env, cb1, 1, start, NOMINAL_VSYNC_PERIOD * 3);
245 verifyCallback(env, cb2, 1, start, NOMINAL_VSYNC_PERIOD * 3);
246 {
247 std::lock_guard<std::mutex> _l{gLock};
248 auto delta = cb2.frameTime - cb1.frameTime;
249 ASSERT(delta == ZERO || delta > ZERO && delta < NOMINAL_VSYNC_PERIOD * 2,
250 "Callback 1 and 2 have frame times too large of a delta in frame times");
251 }
252
253 AChoreographer_postFrameCallback64(choreographer, frameCallback64, &cb1);
254 start = now();
255 std::this_thread::sleep_for(NOMINAL_VSYNC_PERIOD * 3);
256 verifyCallback(env, cb1, 2, start, NOMINAL_VSYNC_PERIOD * 3);
257 verifyCallback(env, cb2, 1, start, ZERO);
258 }
259
android_view_cts_ChoreographerNativeTest_testPostCallback64WithDelayEventuallyRunsCallback(JNIEnv * env,jclass,jlong choreographerPtr)260 static void android_view_cts_ChoreographerNativeTest_testPostCallback64WithDelayEventuallyRunsCallback(
261 JNIEnv* env, jclass, jlong choreographerPtr) {
262 AChoreographer* choreographer = reinterpret_cast<AChoreographer*>(choreographerPtr);
263 Callback cb1 = Callback("cb1");
264 auto start = now();
265
266 auto delay = std::chrono::duration_cast<std::chrono::milliseconds>(DELAY_PERIOD).count();
267 AChoreographer_postFrameCallbackDelayed64(choreographer, frameCallback64, &cb1, delay);
268
269 std::this_thread::sleep_for(NOMINAL_VSYNC_PERIOD * 3);
270 verifyCallback(env, cb1, 0, start, ZERO);
271
272 std::this_thread::sleep_for(DELAY_PERIOD);
273 verifyCallback(env, cb1, 1, start, DELAY_PERIOD + NOMINAL_VSYNC_PERIOD * 3);
274 }
275
android_view_cts_ChoreographerNativeTest_testPostCallbackWithoutDelayEventuallyRunsCallback(JNIEnv * env,jclass,jlong choreographerPtr)276 static void android_view_cts_ChoreographerNativeTest_testPostCallbackWithoutDelayEventuallyRunsCallback(
277 JNIEnv* env, jclass, jlong choreographerPtr) {
278 AChoreographer* choreographer = reinterpret_cast<AChoreographer*>(choreographerPtr);
279 Callback cb1("cb1");
280 Callback cb2("cb2");
281 auto start = now();
282 const auto delay = NOMINAL_VSYNC_PERIOD * 3;
283 // Delay calculations are known to be broken on 32-bit systems (overflow),
284 // so we skip testing the delay on such systems by setting this to ZERO.
285 const auto delayToTest = sizeof(long) == sizeof(int64_t) ? delay : ZERO;
286
287 AChoreographer_postFrameCallback(choreographer, frameCallback, &cb1);
288 AChoreographer_postFrameCallback(choreographer, frameCallback, &cb2);
289 std::this_thread::sleep_for(delay);
290
291 verifyCallback(env, cb1, 1, start, delayToTest);
292 verifyCallback(env, cb2, 1, start, delayToTest);
293
294 // This delta can only be reliably calculated on 64-bit systems. We skip this
295 // part of the test on systems known to be broken.
296 if (sizeof(long) == sizeof(int64_t)) {
297 std::lock_guard<std::mutex> _l{gLock};
298 auto delta = cb2.frameTime - cb1.frameTime;
299 ASSERT(delta == ZERO || delta > ZERO && delta < NOMINAL_VSYNC_PERIOD * 2,
300 "Callback 1 and 2 have frame times too large of a delta in frame times");
301 }
302
303 AChoreographer_postFrameCallback(choreographer, frameCallback, &cb1);
304 start = now();
305 std::this_thread::sleep_for(delay);
306
307 verifyCallback(env, cb1, 2, start, delayToTest);
308 verifyCallback(env, cb2, 1, start, ZERO);
309 }
310
android_view_cts_ChoreographerNativeTest_testPostCallbackWithDelayEventuallyRunsCallback(JNIEnv * env,jclass,jlong choreographerPtr)311 static void android_view_cts_ChoreographerNativeTest_testPostCallbackWithDelayEventuallyRunsCallback(
312 JNIEnv* env, jclass, jlong choreographerPtr) {
313 if (sizeof(long) != sizeof(int64_t)) {
314 // skip test for known broken states.
315 return;
316 }
317
318 AChoreographer* choreographer = reinterpret_cast<AChoreographer*>(choreographerPtr);
319 Callback cb1("cb1");
320 auto start = now();
321
322 auto delay = std::chrono::duration_cast<std::chrono::milliseconds>(DELAY_PERIOD).count();
323 AChoreographer_postFrameCallbackDelayed(choreographer, frameCallback, &cb1, delay);
324
325 std::this_thread::sleep_for(NOMINAL_VSYNC_PERIOD * 3);
326 verifyCallback(env, cb1, 0, start, ZERO);
327
328 std::this_thread::sleep_for(DELAY_PERIOD);
329 const auto delayToTest =
330 sizeof(long) == sizeof(int64_t) ? DELAY_PERIOD + NOMINAL_VSYNC_PERIOD * 3 : ZERO;
331 verifyCallback(env, cb1, 1, start, delayToTest);
332 }
333
android_view_cts_ChoreographerNativeTest_testPostCallbackMixedWithoutDelayEventuallyRunsCallback(JNIEnv * env,jclass,jlong choreographerPtr)334 static void android_view_cts_ChoreographerNativeTest_testPostCallbackMixedWithoutDelayEventuallyRunsCallback(
335 JNIEnv* env, jclass, jlong choreographerPtr) {
336 AChoreographer* choreographer = reinterpret_cast<AChoreographer*>(choreographerPtr);
337 Callback cb1("cb1");
338 Callback cb64("cb64");
339 auto start = now();
340
341 AChoreographer_postFrameCallback(choreographer, frameCallback, &cb1);
342 AChoreographer_postFrameCallback64(choreographer, frameCallback64, &cb64);
343 std::this_thread::sleep_for(NOMINAL_VSYNC_PERIOD * 3);
344
345 verifyCallback(env, cb1, 1, start, ZERO);
346 verifyCallback(env, cb64, 1, start, NOMINAL_VSYNC_PERIOD * 3);
347
348 // This delta can only be reliably calculated on 64-bit systems. We skip this
349 // part of the test on systems known to be broken.
350 if (sizeof(long) == sizeof(int64_t)) {
351 std::lock_guard<std::mutex> _l{gLock};
352 auto delta = cb64.frameTime - cb1.frameTime;
353 ASSERT(delta == ZERO || delta > ZERO && delta < NOMINAL_VSYNC_PERIOD * 2,
354 "Callback 1 and 2 have frame times too large of a delta in frame times");
355 }
356
357 AChoreographer_postFrameCallback64(choreographer, frameCallback64, &cb64);
358 start = now();
359 std::this_thread::sleep_for(NOMINAL_VSYNC_PERIOD * 3);
360 verifyCallback(env, cb1, 1, start, ZERO);
361 verifyCallback(env, cb64, 2, start, NOMINAL_VSYNC_PERIOD * 3);
362 }
363
android_view_cts_ChoreographerNativeTest_testPostCallbackMixedWithDelayEventuallyRunsCallback(JNIEnv * env,jclass,jlong choreographerPtr)364 static void android_view_cts_ChoreographerNativeTest_testPostCallbackMixedWithDelayEventuallyRunsCallback(
365 JNIEnv* env, jclass, jlong choreographerPtr) {
366 AChoreographer* choreographer = reinterpret_cast<AChoreographer*>(choreographerPtr);
367 Callback cb1("cb1");
368 Callback cb64("cb64");
369 auto start = now();
370
371 auto delay = std::chrono::duration_cast<std::chrono::milliseconds>(DELAY_PERIOD).count();
372 AChoreographer_postFrameCallbackDelayed(choreographer, frameCallback, &cb1, delay);
373 AChoreographer_postFrameCallbackDelayed64(choreographer, frameCallback64, &cb64, delay);
374
375 std::this_thread::sleep_for(NOMINAL_VSYNC_PERIOD * 3);
376 verifyCallback(env, cb1, 0, start, ZERO);
377 verifyCallback(env, cb64, 0, start, ZERO);
378
379 std::this_thread::sleep_for(DELAY_PERIOD);
380 verifyCallback(env, cb64, 1, start, DELAY_PERIOD + NOMINAL_VSYNC_PERIOD * 3);
381 const auto delayToTestFor32Bit =
382 sizeof(long) == sizeof(int64_t) ? DELAY_PERIOD + NOMINAL_VSYNC_PERIOD * 3 : ZERO;
383 verifyCallback(env, cb1, 1, start, delayToTestFor32Bit);
384 }
385
android_view_cts_ChoreographerNativeTest_testRefreshRateCallback(JNIEnv * env,jclass,jlong choreographerPtr)386 static void android_view_cts_ChoreographerNativeTest_testRefreshRateCallback(
387 JNIEnv* env, jclass, jlong choreographerPtr) {
388 AChoreographer* choreographer = reinterpret_cast<AChoreographer*>(choreographerPtr);
389 RefreshRateCallback cb("cb");
390
391 AChoreographer_registerRefreshRateCallback(choreographer, refreshRateCallback, &cb);
392
393 // Give the display system time to push an initial callback.
394 std::this_thread::sleep_for(NOMINAL_VSYNC_PERIOD * 10);
395 verifyRefreshRateCallback<RefreshRateCallback>(env, cb, 1);
396 AChoreographer_unregisterRefreshRateCallback(choreographer, refreshRateCallback, &cb);
397 }
398
android_view_cts_ChoreographerNativeTest_testUnregisteringRefreshRateCallback(JNIEnv * env,jclass,jlong choreographerPtr)399 static void android_view_cts_ChoreographerNativeTest_testUnregisteringRefreshRateCallback(
400 JNIEnv* env, jclass, jlong choreographerPtr) {
401 AChoreographer* choreographer = reinterpret_cast<AChoreographer*>(choreographerPtr);
402 RefreshRateCallback cb1("cb1");
403 RefreshRateCallback cb2("cb2");
404
405 AChoreographer_registerRefreshRateCallback(choreographer, refreshRateCallback, &cb1);
406
407 // Give the display system time to push an initial callback.
408 std::this_thread::sleep_for(NOMINAL_VSYNC_PERIOD * 10);
409 verifyRefreshRateCallback<RefreshRateCallback>(env, cb1, 1);
410
411 AChoreographer_unregisterRefreshRateCallback(choreographer, refreshRateCallback, &cb1);
412 // Flush out pending callback events for the callback
413 std::this_thread::sleep_for(NOMINAL_VSYNC_PERIOD * 10);
414 resetRefreshRateCallback(cb1);
415
416 AChoreographer_registerRefreshRateCallback(choreographer, refreshRateCallback, &cb2);
417 // Verify that cb2 is called on registration, but not cb1.
418 std::this_thread::sleep_for(NOMINAL_VSYNC_PERIOD * 10);
419 verifyRefreshRateCallback<RefreshRateCallback>(env, cb1, 0);
420 verifyRefreshRateCallback<RefreshRateCallback>(env, cb2, 1);
421 AChoreographer_unregisterRefreshRateCallback(choreographer, refreshRateCallback, &cb2);
422 }
423
android_view_cts_ChoreographerNativeTest_testMultipleRefreshRateCallbacks(JNIEnv * env,jclass,jlong choreographerPtr)424 static void android_view_cts_ChoreographerNativeTest_testMultipleRefreshRateCallbacks(
425 JNIEnv* env, jclass, jlong choreographerPtr) {
426 AChoreographer* choreographer = reinterpret_cast<AChoreographer*>(choreographerPtr);
427 RefreshRateCallback cb1("cb1");
428 RefreshRateCallback cb2("cb2");
429
430 AChoreographer_registerRefreshRateCallback(choreographer, refreshRateCallback, &cb1);
431 AChoreographer_registerRefreshRateCallback(choreographer, refreshRateCallback, &cb2);
432
433 // Give the display system time to push an initial refresh rate change.
434 // Polling the event will allow both callbacks to be triggered.
435 std::this_thread::sleep_for(NOMINAL_VSYNC_PERIOD * 10);
436 verifyRefreshRateCallback<RefreshRateCallback>(env, cb1, 1);
437 verifyRefreshRateCallback<RefreshRateCallback>(env, cb2, 1);
438
439 AChoreographer_unregisterRefreshRateCallback(choreographer, refreshRateCallback, &cb1);
440 AChoreographer_unregisterRefreshRateCallback(choreographer, refreshRateCallback, &cb2);
441 }
442
android_view_cts_ChoreographerNativeTest_testAttemptToAddRefreshRateCallbackTwiceDoesNotAddTwice(JNIEnv * env,jclass,jlong choreographerPtr)443 static void android_view_cts_ChoreographerNativeTest_testAttemptToAddRefreshRateCallbackTwiceDoesNotAddTwice(
444 JNIEnv* env, jclass, jlong choreographerPtr) {
445 AChoreographer* choreographer = reinterpret_cast<AChoreographer*>(choreographerPtr);
446 RefreshRateCallback cb1("cb1");
447 RefreshRateCallback cb2("cb2");
448
449 AChoreographer_registerRefreshRateCallback(choreographer, refreshRateCallback, &cb1);
450 AChoreographer_registerRefreshRateCallback(choreographer, refreshRateCallback, &cb1);
451
452 // Give the display system time to push an initial callback.
453 std::this_thread::sleep_for(NOMINAL_VSYNC_PERIOD * 10);
454 verifyRefreshRateCallback<RefreshRateCallback>(env, cb1, 1);
455
456 AChoreographer_unregisterRefreshRateCallback(choreographer, refreshRateCallback, &cb1);
457 // Flush out pending callback events for the callback
458 std::this_thread::sleep_for(NOMINAL_VSYNC_PERIOD * 10);
459 resetRefreshRateCallback(cb1);
460
461 AChoreographer_registerRefreshRateCallback(choreographer, refreshRateCallback, &cb2);
462 // Verify that cb1 is not called again, even thiough it was registered once
463 // and unregistered again
464 std::this_thread::sleep_for(NOMINAL_VSYNC_PERIOD * 10);
465 verifyRefreshRateCallback<RefreshRateCallback>(env, cb1, 0);
466 AChoreographer_unregisterRefreshRateCallback(choreographer, refreshRateCallback, &cb2);
467 }
468
469 // This test must be run on the UI thread for fine-grained control of looper
470 // scheduling.
android_view_cts_ChoreographerNativeTest_testRefreshRateCallbackMixedWithFrameCallbacks(JNIEnv * env,jclass,jlong choreographerPtr)471 static void android_view_cts_ChoreographerNativeTest_testRefreshRateCallbackMixedWithFrameCallbacks(
472 JNIEnv* env, jclass, jlong choreographerPtr) {
473 AChoreographer* choreographer = reinterpret_cast<AChoreographer*>(choreographerPtr);
474 RefreshRateCallback cb("cb");
475
476 AChoreographer_registerRefreshRateCallback(choreographer, refreshRateCallback, &cb);
477
478 Callback cb1("cb1");
479 Callback cb64("cb64");
480 auto start = now();
481
482 auto vsyncPeriod = std::chrono::duration_cast<std::chrono::milliseconds>(
483 NOMINAL_VSYNC_PERIOD)
484 .count();
485 auto delay = std::chrono::duration_cast<std::chrono::milliseconds>(DELAY_PERIOD).count();
486 AChoreographer_postFrameCallbackDelayed(choreographer, frameCallback, &cb1, delay);
487 AChoreographer_postFrameCallbackDelayed64(choreographer, frameCallback64, &cb64, delay);
488
489 std::this_thread::sleep_for(DELAY_PERIOD + NOMINAL_VSYNC_PERIOD * 10);
490 // Ensure that callbacks are seen by the looper instance at approximately
491 // the same time, and provide enough time for the looper instance to process
492 // the delayed callback and the requested vsync signal if needed.
493 ALooper_pollAll(vsyncPeriod * 5, nullptr, nullptr, nullptr);
494 verifyRefreshRateCallback<RefreshRateCallback>(env, cb, 1);
495 verifyCallback(env, cb64, 1, start,
496 DELAY_PERIOD + NOMINAL_VSYNC_PERIOD * 15);
497 const auto delayToTestFor32Bit =
498 sizeof(long) == sizeof(int64_t)
499 ? DELAY_PERIOD + NOMINAL_VSYNC_PERIOD * 15
500 : ZERO;
501 verifyCallback(env, cb1, 1, start, delayToTestFor32Bit);
502 AChoreographer_unregisterRefreshRateCallback(choreographer, refreshRateCallback, &cb);
503 }
504
505 // This test cannot be run on the UI thread because it relies on callbacks to be dispatched on the
506 // application UI thread.
507 static void
android_view_cts_ChoreographerNativeTest_testRefreshRateCallbacksAreSyncedWithDisplayManager(JNIEnv * env,jobject clazz)508 android_view_cts_ChoreographerNativeTest_testRefreshRateCallbacksAreSyncedWithDisplayManager(
509 JNIEnv* env, jobject clazz) {
510 // Test harness choreographer is not on the main thread, so create a thread-local choreographer
511 // instance.
512 ALooper_prepare(0);
513 AChoreographer* choreographer = AChoreographer_getInstance();
514 RefreshRateCallbackWithDisplayManager cb("cb", env, clazz);
515
516 AChoreographer_registerRefreshRateCallback(choreographer, refreshRateCallbackWithDisplayManager,
517 &cb);
518
519 auto delayPeriod = std::chrono::duration_cast<std::chrono::milliseconds>(DELAY_PERIOD).count();
520
521 const size_t numRuns = 1000;
522 int previousCount = 0;
523 for (int i = 0; i < numRuns; ++i) {
524 const size_t numTries = 5;
525 for (int j = 0; j < numTries; j++) {
526 // In theory we only need to poll once because the test harness configuration should
527 // enforce that we won't get spurious callbacks. In practice, there may still be
528 // spurious callbacks due to hotplug or other display events that aren't suppressed. So
529 // we add some slack by retrying a few times, but we stop at the first refresh rate
530 // callback (1) to keep the test runtime reasonably short, and (2) to keep the test
531 // under better control so that it does not spam the system with refresh rate changes.
532 int result = ALooper_pollOnce(delayPeriod * 5, nullptr, nullptr, nullptr);
533 ASSERT(result == ALOOPER_POLL_CALLBACK, "Callback failed on run: %d with error: %d", i,
534 result);
535 if (previousCount != cb.count) {
536 verifyRefreshRateCallback<RefreshRateCallbackWithDisplayManager>(env, cb,
537 previousCount + 1);
538 previousCount = cb.count;
539 break;
540 }
541
542 ASSERT(j < numTries - 1, "No callback observed for run: %d", i);
543 }
544 }
545 AChoreographer_unregisterRefreshRateCallback(choreographer, refreshRateCallback, &cb);
546 }
547
548 static JNINativeMethod gMethods[] = {
549 {"nativeGetChoreographer", "()J",
550 (void*)android_view_cts_ChoreographerNativeTest_getChoreographer},
551 {"nativePrepareChoreographerTests", "(J[J)Z",
552 (void*)android_view_cts_ChoreographerNativeTest_prepareChoreographerTests},
553 {"nativeTestPostVsyncCallbackWithoutDelayEventuallyRunsCallbacks", "(J)V",
554 (void*)android_view_cts_ChoreographerNativeTest_testPostVsyncCallbackWithoutDelayEventuallyRunsCallback},
555 {"nativeTestFrameCallbackDataVsyncIdValid", "(J)V",
556 (void*)android_view_cts_ChoreographerNativeTest_testFrameCallbackDataVsyncIdValid},
557 {"nativeTestFrameCallbackDataDeadlineInFuture", "(J)V",
558 (void*)android_view_cts_ChoreographerNativeTest_testFrameCallbackDataDeadlineInFuture},
559 {"nativeTestFrameCallbackDataExpectedPresentTimeInFuture", "(J)V",
560 (void*)android_view_cts_ChoreographerNativeTest_testFrameCallbackDataExpectedPresentTimeInFuture},
561 {"nativeTestPostCallback64WithoutDelayEventuallyRunsCallbacks", "(J)V",
562 (void*)android_view_cts_ChoreographerNativeTest_testPostCallback64WithoutDelayEventuallyRunsCallback},
563 {"nativeTestPostCallback64WithDelayEventuallyRunsCallbacks", "(J)V",
564 (void*)android_view_cts_ChoreographerNativeTest_testPostCallback64WithDelayEventuallyRunsCallback},
565 {"nativeTestPostCallbackWithoutDelayEventuallyRunsCallbacks", "(J)V",
566 (void*)android_view_cts_ChoreographerNativeTest_testPostCallbackWithoutDelayEventuallyRunsCallback},
567 {"nativeTestPostCallbackWithDelayEventuallyRunsCallbacks", "(J)V",
568 (void*)android_view_cts_ChoreographerNativeTest_testPostCallbackWithDelayEventuallyRunsCallback},
569 {"nativeTestPostCallbackMixedWithoutDelayEventuallyRunsCallbacks", "(J)V",
570 (void*)android_view_cts_ChoreographerNativeTest_testPostCallbackMixedWithoutDelayEventuallyRunsCallback},
571 {"nativeTestPostCallbackMixedWithDelayEventuallyRunsCallbacks", "(J)V",
572 (void*)android_view_cts_ChoreographerNativeTest_testPostCallbackMixedWithDelayEventuallyRunsCallback},
573 {"nativeTestRefreshRateCallback", "(J)V",
574 (void*)android_view_cts_ChoreographerNativeTest_testRefreshRateCallback},
575 {"nativeTestUnregisteringRefreshRateCallback", "(J)V",
576 (void*)android_view_cts_ChoreographerNativeTest_testUnregisteringRefreshRateCallback},
577 {"nativeTestMultipleRefreshRateCallbacks", "(J)V",
578 (void*)android_view_cts_ChoreographerNativeTest_testMultipleRefreshRateCallbacks},
579 {"nativeTestAttemptToAddRefreshRateCallbackTwiceDoesNotAddTwice", "(J)V",
580 (void*)android_view_cts_ChoreographerNativeTest_testAttemptToAddRefreshRateCallbackTwiceDoesNotAddTwice},
581 {"nativeTestRefreshRateCallbackMixedWithFrameCallbacks", "(J)V",
582 (void*)android_view_cts_ChoreographerNativeTest_testRefreshRateCallbackMixedWithFrameCallbacks},
583 {"nativeTestRefreshRateCallbacksAreSyncedWithDisplayManager", "()V",
584 (void*)android_view_cts_ChoreographerNativeTest_testRefreshRateCallbacksAreSyncedWithDisplayManager},
585 };
586
register_android_view_cts_ChoreographerNativeTest(JNIEnv * env)587 int register_android_view_cts_ChoreographerNativeTest(JNIEnv* env)
588 {
589 jclass clazz = env->FindClass("android/view/cts/ChoreographerNativeTest");
590 gJni.choreographerNativeTest.clazz = static_cast<jclass>(env->NewGlobalRef(clazz));
591 gJni.choreographerNativeTest.checkRefreshRateIsCurrentAndSwitch =
592 env->GetMethodID(clazz, "checkRefreshRateIsCurrentAndSwitch", "(I)V");
593 return env->RegisterNatives(clazz, gMethods,
594 sizeof(gMethods) / sizeof(JNINativeMethod));
595 }
596