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 <android/choreographer.h> 19 20 #include <jni.h> 21 #include <sys/time.h> 22 #include <time.h> 23 24 #include <chrono> 25 #include <cstdlib> 26 #include <cstring> 27 #include <mutex> 28 #include <thread> 29 30 #define LOG_TAG "ChoreographerNative" 31 32 #define ASSERT(condition, format, args...) \ 33 if (!(condition)) { \ 34 fail(env, format, ## args); \ 35 return; \ 36 } 37 38 39 using namespace std::chrono_literals; 40 41 static constexpr std::chrono::nanoseconds NOMINAL_VSYNC_PERIOD{16ms}; 42 static constexpr std::chrono::nanoseconds DELAY_PERIOD{NOMINAL_VSYNC_PERIOD * 5}; 43 44 static std::mutex gLock; 45 struct Callback { 46 int count{0}; 47 std::chrono::nanoseconds frameTime{0}; 48 }; 49 50 static void frameCallback(long frameTimeNanos, void* data) { 51 std::lock_guard<std::mutex> _l(gLock); 52 Callback* cb = static_cast<Callback*>(data); 53 cb->count++; 54 cb->frameTime = std::chrono::nanoseconds{frameTimeNanos}; 55 } 56 57 static std::chrono::nanoseconds now() { 58 return std::chrono::steady_clock::now().time_since_epoch(); 59 } 60 61 static void fail(JNIEnv* env, const char* format, ...) { 62 va_list args; 63 64 va_start(args, format); 65 char *msg; 66 int rc = vasprintf(&msg, format, args); 67 va_end(args); 68 69 jclass exClass; 70 const char *className = "java/lang/AssertionError"; 71 exClass = env->FindClass(className); 72 env->ThrowNew(exClass, msg); 73 free(msg); 74 } 75 76 static jlong android_view_cts_ChoreographerNativeTest_getChoreographer(JNIEnv*, jclass) { 77 std::lock_guard<std::mutex> _l{gLock}; 78 return reinterpret_cast<jlong>(AChoreographer_getInstance()); 79 } 80 81 static jboolean android_view_cts_ChoreographerNativeTest_prepareChoreographerTests(JNIEnv*, jclass, 82 jlong choreographerPtr) { 83 std::lock_guard<std::mutex> _l{gLock}; 84 AChoreographer* choreographer = reinterpret_cast<AChoreographer*>(choreographerPtr); 85 return choreographer != nullptr; 86 } 87 88 static void android_view_cts_ChoreographerNativeTest_testPostCallbackWithoutDelayEventuallyRunsCallback( 89 JNIEnv* env, jclass, jlong choreographerPtr) { 90 AChoreographer* choreographer = reinterpret_cast<AChoreographer*>(choreographerPtr); 91 Callback* cb1 = new Callback(); 92 Callback* cb2 = new Callback(); 93 auto start = now(); 94 95 AChoreographer_postFrameCallback(choreographer, frameCallback, cb1); 96 AChoreographer_postFrameCallback(choreographer, frameCallback, cb2); 97 std::this_thread::sleep_for(NOMINAL_VSYNC_PERIOD * 3); 98 { 99 std::lock_guard<std::mutex> _l{gLock}; 100 ASSERT(cb1->count == 1, "Choreographer failed to invoke callback 1"); 101 ASSERT(cb1->frameTime - start < NOMINAL_VSYNC_PERIOD * 3, 102 "Callback 1 has incorect frame time on first invokation"); 103 ASSERT(cb2->count == 1, "Choreographer failed to invoke callback 2"); 104 ASSERT(cb2->frameTime - start < NOMINAL_VSYNC_PERIOD * 3, 105 "Callback 2 has incorect frame time on first invokation"); 106 auto delta = cb2->frameTime - cb1->frameTime; 107 ASSERT(delta == delta.zero() || delta > delta.zero() && delta < NOMINAL_VSYNC_PERIOD * 2, 108 "Callback 1 and 2 have frame times too large of a delta in frame times"); 109 } 110 111 AChoreographer_postFrameCallback(choreographer, frameCallback, cb1); 112 start = now(); 113 std::this_thread::sleep_for(NOMINAL_VSYNC_PERIOD * 3); 114 { 115 std::lock_guard<std::mutex> _l{gLock}; 116 ASSERT(cb1->count == 2, "Choreographer failed to invoke callback 1 a second time"); 117 ASSERT(cb1->frameTime - start < NOMINAL_VSYNC_PERIOD * 3, 118 "Callback 1 has incorect frame time on second invokation"); 119 ASSERT(cb2->count == 1, "Choreographer invoked callback 2 when not posted"); 120 } 121 } 122 123 static void android_view_cts_ChoreographerNativeTest_testPostCallbackWithDelayEventuallyRunsCallback( 124 JNIEnv* env, jclass, jlong choreographerPtr) { 125 AChoreographer* choreographer = reinterpret_cast<AChoreographer*>(choreographerPtr); 126 Callback* cb1 = new Callback(); 127 auto start = now(); 128 129 auto delay = std::chrono::duration_cast<std::chrono::milliseconds>(DELAY_PERIOD).count(); 130 AChoreographer_postFrameCallbackDelayed(choreographer, frameCallback, cb1, delay); 131 std::this_thread::sleep_for(NOMINAL_VSYNC_PERIOD * 3); 132 { 133 std::lock_guard<std::mutex> _l{gLock}; 134 ASSERT(cb1->count == 0, 135 "Choreographer failed to delay callback for a sufficient period of time"); 136 } 137 std::this_thread::sleep_for(DELAY_PERIOD); 138 { 139 std::lock_guard<std::mutex> _l{gLock}; 140 ASSERT(cb1->count == 1, "Choreographer failed to invoke delayed callback"); 141 ASSERT(cb1->frameTime - start < DELAY_PERIOD + NOMINAL_VSYNC_PERIOD * 3, 142 "Frametime on callback is incorrect") 143 } 144 } 145 146 static JNINativeMethod gMethods[] = { 147 { "nativeGetChoreographer", "()J", 148 (void *) android_view_cts_ChoreographerNativeTest_getChoreographer}, 149 { "nativePrepareChoreographerTests", "(J)Z", 150 (void *) android_view_cts_ChoreographerNativeTest_prepareChoreographerTests}, 151 { "nativeTestPostCallbackWithoutDelayEventuallyRunsCallbacks", "(J)V", 152 (void *) android_view_cts_ChoreographerNativeTest_testPostCallbackWithoutDelayEventuallyRunsCallback}, 153 { "nativeTestPostCallbackWithDelayEventuallyRunsCallbacks", "(J)V", 154 (void *) android_view_cts_ChoreographerNativeTest_testPostCallbackWithDelayEventuallyRunsCallback}, 155 }; 156 157 int register_android_view_cts_ChoreographerNativeTest(JNIEnv* env) 158 { 159 jclass clazz = env->FindClass("android/view/cts/ChoreographerNativeTest"); 160 return env->RegisterNatives(clazz, gMethods, 161 sizeof(gMethods) / sizeof(JNINativeMethod)); 162 } 163