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