1 /* 2 * Copyright (C) 2011 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 package android.view; 18 19 import static android.view.DisplayEventReceiver.VSYNC_SOURCE_APP; 20 import static android.view.DisplayEventReceiver.VSYNC_SOURCE_SURFACE_FLINGER; 21 22 import android.annotation.NonNull; 23 import android.annotation.Nullable; 24 import android.annotation.SuppressLint; 25 import android.annotation.TestApi; 26 import android.compat.annotation.UnsupportedAppUsage; 27 import android.graphics.FrameInfo; 28 import android.graphics.Insets; 29 import android.hardware.display.DisplayManagerGlobal; 30 import android.os.Build; 31 import android.os.Handler; 32 import android.os.Looper; 33 import android.os.Message; 34 import android.os.SystemClock; 35 import android.os.SystemProperties; 36 import android.os.Trace; 37 import android.util.Log; 38 import android.util.TimeUtils; 39 import android.view.animation.AnimationUtils; 40 41 import java.io.PrintWriter; 42 43 /** 44 * Coordinates the timing of animations, input and drawing. 45 * <p> 46 * The choreographer receives timing pulses (such as vertical synchronization) 47 * from the display subsystem then schedules work to occur as part of rendering 48 * the next display frame. 49 * </p><p> 50 * Applications typically interact with the choreographer indirectly using 51 * higher level abstractions in the animation framework or the view hierarchy. 52 * Here are some examples of things you can do using the higher-level APIs. 53 * </p> 54 * <ul> 55 * <li>To post an animation to be processed on a regular time basis synchronized with 56 * display frame rendering, use {@link android.animation.ValueAnimator#start}.</li> 57 * <li>To post a {@link Runnable} to be invoked once at the beginning of the next display 58 * frame, use {@link View#postOnAnimation}.</li> 59 * <li>To post a {@link Runnable} to be invoked once at the beginning of the next display 60 * frame after a delay, use {@link View#postOnAnimationDelayed}.</li> 61 * <li>To post a call to {@link View#invalidate()} to occur once at the beginning of the 62 * next display frame, use {@link View#postInvalidateOnAnimation()} or 63 * {@link View#postInvalidateOnAnimation(int, int, int, int)}.</li> 64 * <li>To ensure that the contents of a {@link View} scroll smoothly and are drawn in 65 * sync with display frame rendering, do nothing. This already happens automatically. 66 * {@link View#onDraw} will be called at the appropriate time.</li> 67 * </ul> 68 * <p> 69 * However, there are a few cases where you might want to use the functions of the 70 * choreographer directly in your application. Here are some examples. 71 * </p> 72 * <ul> 73 * <li>If your application does its rendering in a different thread, possibly using GL, 74 * or does not use the animation framework or view hierarchy at all 75 * and you want to ensure that it is appropriately synchronized with the display, then use 76 * {@link Choreographer#postFrameCallback}.</li> 77 * <li>... and that's about it.</li> 78 * </ul> 79 * <p> 80 * Each {@link Looper} thread has its own choreographer. Other threads can 81 * post callbacks to run on the choreographer but they will run on the {@link Looper} 82 * to which the choreographer belongs. 83 * </p> 84 */ 85 public final class Choreographer { 86 private static final String TAG = "Choreographer"; 87 88 // Prints debug messages about jank which was detected (low volume). 89 private static final boolean DEBUG_JANK = false; 90 91 // Prints debug messages about every frame and callback registered (high volume). 92 private static final boolean DEBUG_FRAMES = false; 93 94 // The default amount of time in ms between animation frames. 95 // When vsync is not enabled, we want to have some idea of how long we should 96 // wait before posting the next animation message. It is important that the 97 // default value be less than the true inter-frame delay on all devices to avoid 98 // situations where we might skip frames by waiting too long (we must compensate 99 // for jitter and hardware variations). Regardless of this value, the animation 100 // and display loop is ultimately rate-limited by how fast new graphics buffers can 101 // be dequeued. 102 private static final long DEFAULT_FRAME_DELAY = 10; 103 104 // The number of milliseconds between animation frames. 105 private static volatile long sFrameDelay = DEFAULT_FRAME_DELAY; 106 107 // Thread local storage for the choreographer. 108 private static final ThreadLocal<Choreographer> sThreadInstance = 109 new ThreadLocal<Choreographer>() { 110 @Override 111 protected Choreographer initialValue() { 112 Looper looper = Looper.myLooper(); 113 if (looper == null) { 114 throw new IllegalStateException("The current thread must have a looper!"); 115 } 116 Choreographer choreographer = new Choreographer(looper, VSYNC_SOURCE_APP); 117 if (looper == Looper.getMainLooper()) { 118 mMainInstance = choreographer; 119 } 120 return choreographer; 121 } 122 }; 123 124 private static volatile Choreographer mMainInstance; 125 126 // Thread local storage for the SF choreographer. 127 private static final ThreadLocal<Choreographer> sSfThreadInstance = 128 new ThreadLocal<Choreographer>() { 129 @Override 130 protected Choreographer initialValue() { 131 Looper looper = Looper.myLooper(); 132 if (looper == null) { 133 throw new IllegalStateException("The current thread must have a looper!"); 134 } 135 return new Choreographer(looper, VSYNC_SOURCE_SURFACE_FLINGER); 136 } 137 }; 138 139 // Enable/disable vsync for animations and drawing. 140 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769497) 141 private static final boolean USE_VSYNC = SystemProperties.getBoolean( 142 "debug.choreographer.vsync", true); 143 144 // Enable/disable using the frame time instead of returning now. 145 private static final boolean USE_FRAME_TIME = SystemProperties.getBoolean( 146 "debug.choreographer.frametime", true); 147 148 // Set a limit to warn about skipped frames. 149 // Skipped frames imply jank. 150 private static final int SKIPPED_FRAME_WARNING_LIMIT = SystemProperties.getInt( 151 "debug.choreographer.skipwarning", 30); 152 153 private static final int MSG_DO_FRAME = 0; 154 private static final int MSG_DO_SCHEDULE_VSYNC = 1; 155 private static final int MSG_DO_SCHEDULE_CALLBACK = 2; 156 157 // All frame callbacks posted by applications have this token or VSYNC_CALLBACK_TOKEN. 158 private static final Object FRAME_CALLBACK_TOKEN = new Object() { 159 public String toString() { return "FRAME_CALLBACK_TOKEN"; } 160 }; 161 private static final Object VSYNC_CALLBACK_TOKEN = new Object() { 162 public String toString() { 163 return "VSYNC_CALLBACK_TOKEN"; 164 } 165 }; 166 167 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 168 private final Object mLock = new Object(); 169 170 private final Looper mLooper; 171 private final FrameHandler mHandler; 172 173 // The display event receiver can only be accessed by the looper thread to which 174 // it is attached. We take care to ensure that we post message to the looper 175 // if appropriate when interacting with the display event receiver. 176 @UnsupportedAppUsage 177 private final FrameDisplayEventReceiver mDisplayEventReceiver; 178 179 private CallbackRecord mCallbackPool; 180 181 @UnsupportedAppUsage 182 private final CallbackQueue[] mCallbackQueues; 183 184 private boolean mFrameScheduled; 185 private boolean mCallbacksRunning; 186 @UnsupportedAppUsage 187 private long mLastFrameTimeNanos; 188 189 /** DO NOT USE since this will not updated when screen refresh changes. */ 190 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, 191 publicAlternatives = "Use {@link android.view.Display#getRefreshRate} instead") 192 @Deprecated 193 private long mFrameIntervalNanos; 194 private long mLastFrameIntervalNanos; 195 196 private boolean mDebugPrintNextFrameTimeDelta; 197 private int mFPSDivisor = 1; 198 private DisplayEventReceiver.VsyncEventData mLastVsyncEventData = 199 new DisplayEventReceiver.VsyncEventData(); 200 201 /** 202 * Contains information about the current frame for jank-tracking, 203 * mainly timings of key events along with a bit of metadata about 204 * view tree state 205 * 206 * TODO: Is there a better home for this? Currently Choreographer 207 * is the only one with CALLBACK_ANIMATION start time, hence why this 208 * resides here. 209 * 210 * @hide 211 */ 212 FrameInfo mFrameInfo = new FrameInfo(); 213 214 /** 215 * Must be kept in sync with CALLBACK_* ints below, used to index into this array. 216 * @hide 217 */ 218 private static final String[] CALLBACK_TRACE_TITLES = { 219 "input", "animation", "insets_animation", "traversal", "commit" 220 }; 221 222 /** 223 * Callback type: Input callback. Runs first. 224 * @hide 225 */ 226 public static final int CALLBACK_INPUT = 0; 227 228 /** 229 * Callback type: Animation callback. Runs before {@link #CALLBACK_INSETS_ANIMATION}. 230 * @hide 231 */ 232 @TestApi 233 public static final int CALLBACK_ANIMATION = 1; 234 235 /** 236 * Callback type: Animation callback to handle inset updates. This is separate from 237 * {@link #CALLBACK_ANIMATION} as we need to "gather" all inset animation updates via 238 * {@link WindowInsetsAnimationController#setInsetsAndAlpha(Insets, float, float)} for multiple 239 * ongoing animations but then update the whole view system with a single callback to 240 * {@link View#dispatchWindowInsetsAnimationProgress} that contains all the combined updated 241 * insets. 242 * <p> 243 * Both input and animation may change insets, so we need to run this after these callbacks, but 244 * before traversals. 245 * <p> 246 * Runs before traversals. 247 * @hide 248 */ 249 public static final int CALLBACK_INSETS_ANIMATION = 2; 250 251 /** 252 * Callback type: Traversal callback. Handles layout and draw. Runs 253 * after all other asynchronous messages have been handled. 254 * @hide 255 */ 256 public static final int CALLBACK_TRAVERSAL = 3; 257 258 /** 259 * Callback type: Commit callback. Handles post-draw operations for the frame. 260 * Runs after traversal completes. The {@link #getFrameTime() frame time} reported 261 * during this callback may be updated to reflect delays that occurred while 262 * traversals were in progress in case heavy layout operations caused some frames 263 * to be skipped. The frame time reported during this callback provides a better 264 * estimate of the start time of the frame in which animations (and other updates 265 * to the view hierarchy state) actually took effect. 266 * @hide 267 */ 268 public static final int CALLBACK_COMMIT = 4; 269 270 private static final int CALLBACK_LAST = CALLBACK_COMMIT; 271 Choreographer(Looper looper, int vsyncSource)272 private Choreographer(Looper looper, int vsyncSource) { 273 mLooper = looper; 274 mHandler = new FrameHandler(looper); 275 mDisplayEventReceiver = USE_VSYNC 276 ? new FrameDisplayEventReceiver(looper, vsyncSource) 277 : null; 278 mLastFrameTimeNanos = Long.MIN_VALUE; 279 280 mFrameIntervalNanos = (long)(1000000000 / getRefreshRate()); 281 282 mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1]; 283 for (int i = 0; i <= CALLBACK_LAST; i++) { 284 mCallbackQueues[i] = new CallbackQueue(); 285 } 286 // b/68769804: For low FPS experiments. 287 setFPSDivisor(SystemProperties.getInt(ThreadedRenderer.DEBUG_FPS_DIVISOR, 1)); 288 } 289 getRefreshRate()290 private static float getRefreshRate() { 291 DisplayInfo di = DisplayManagerGlobal.getInstance().getDisplayInfo( 292 Display.DEFAULT_DISPLAY); 293 return di.getRefreshRate(); 294 } 295 296 /** 297 * Gets the choreographer for the calling thread. Must be called from 298 * a thread that already has a {@link android.os.Looper} associated with it. 299 * 300 * @return The choreographer for this thread. 301 * @throws IllegalStateException if the thread does not have a looper. 302 */ getInstance()303 public static Choreographer getInstance() { 304 return sThreadInstance.get(); 305 } 306 307 /** 308 * @hide 309 */ 310 @UnsupportedAppUsage getSfInstance()311 public static Choreographer getSfInstance() { 312 return sSfThreadInstance.get(); 313 } 314 315 /** 316 * @return The Choreographer of the main thread, if it exists, or {@code null} otherwise. 317 * @hide 318 */ getMainThreadInstance()319 public static Choreographer getMainThreadInstance() { 320 return mMainInstance; 321 } 322 323 /** Destroys the calling thread's choreographer 324 * @hide 325 */ releaseInstance()326 public static void releaseInstance() { 327 Choreographer old = sThreadInstance.get(); 328 sThreadInstance.remove(); 329 old.dispose(); 330 } 331 dispose()332 private void dispose() { 333 mDisplayEventReceiver.dispose(); 334 } 335 336 /** 337 * The amount of time, in milliseconds, between each frame of the animation. 338 * <p> 339 * This is a requested time that the animation will attempt to honor, but the actual delay 340 * between frames may be different, depending on system load and capabilities. This is a static 341 * function because the same delay will be applied to all animations, since they are all 342 * run off of a single timing loop. 343 * </p><p> 344 * The frame delay may be ignored when the animation system uses an external timing 345 * source, such as the display refresh rate (vsync), to govern animations. 346 * </p> 347 * 348 * @return the requested time between frames, in milliseconds 349 * @hide 350 */ 351 @UnsupportedAppUsage 352 @TestApi getFrameDelay()353 public static long getFrameDelay() { 354 return sFrameDelay; 355 } 356 357 /** 358 * The amount of time, in milliseconds, between each frame of the animation. 359 * <p> 360 * This is a requested time that the animation will attempt to honor, but the actual delay 361 * between frames may be different, depending on system load and capabilities. This is a static 362 * function because the same delay will be applied to all animations, since they are all 363 * run off of a single timing loop. 364 * </p><p> 365 * The frame delay may be ignored when the animation system uses an external timing 366 * source, such as the display refresh rate (vsync), to govern animations. 367 * </p> 368 * 369 * @param frameDelay the requested time between frames, in milliseconds 370 * @hide 371 */ 372 @TestApi setFrameDelay(long frameDelay)373 public static void setFrameDelay(long frameDelay) { 374 sFrameDelay = frameDelay; 375 } 376 377 /** 378 * Subtracts typical frame delay time from a delay interval in milliseconds. 379 * <p> 380 * This method can be used to compensate for animation delay times that have baked 381 * in assumptions about the frame delay. For example, it's quite common for code to 382 * assume a 60Hz frame time and bake in a 16ms delay. When we call 383 * {@link #postAnimationCallbackDelayed} we want to know how long to wait before 384 * posting the animation callback but let the animation timer take care of the remaining 385 * frame delay time. 386 * </p><p> 387 * This method is somewhat conservative about how much of the frame delay it 388 * subtracts. It uses the same value returned by {@link #getFrameDelay} which by 389 * default is 10ms even though many parts of the system assume 16ms. Consequently, 390 * we might still wait 6ms before posting an animation callback that we want to run 391 * on the next frame, but this is much better than waiting a whole 16ms and likely 392 * missing the deadline. 393 * </p> 394 * 395 * @param delayMillis The original delay time including an assumed frame delay. 396 * @return The adjusted delay time with the assumed frame delay subtracted out. 397 * @hide 398 */ subtractFrameDelay(long delayMillis)399 public static long subtractFrameDelay(long delayMillis) { 400 final long frameDelay = sFrameDelay; 401 return delayMillis <= frameDelay ? 0 : delayMillis - frameDelay; 402 } 403 404 /** 405 * @return The refresh rate as the nanoseconds between frames 406 * @hide 407 */ getFrameIntervalNanos()408 public long getFrameIntervalNanos() { 409 synchronized (mLock) { 410 return mLastFrameIntervalNanos; 411 } 412 } 413 dump(String prefix, PrintWriter writer)414 void dump(String prefix, PrintWriter writer) { 415 String innerPrefix = prefix + " "; 416 writer.print(prefix); writer.println("Choreographer:"); 417 writer.print(innerPrefix); writer.print("mFrameScheduled="); 418 writer.println(mFrameScheduled); 419 writer.print(innerPrefix); writer.print("mLastFrameTime="); 420 writer.println(TimeUtils.formatUptime(mLastFrameTimeNanos / 1000000)); 421 } 422 423 /** 424 * Posts a callback to run on the next frame. 425 * <p> 426 * The callback runs once then is automatically removed. 427 * </p> 428 * 429 * @param callbackType The callback type. 430 * @param action The callback action to run during the next frame. 431 * @param token The callback token, or null if none. 432 * 433 * @see #removeCallbacks 434 * @hide 435 */ 436 @UnsupportedAppUsage 437 @TestApi postCallback(int callbackType, Runnable action, Object token)438 public void postCallback(int callbackType, Runnable action, Object token) { 439 postCallbackDelayed(callbackType, action, token, 0); 440 } 441 442 /** 443 * Posts a callback to run on the next frame after the specified delay. 444 * <p> 445 * The callback runs once then is automatically removed. 446 * </p> 447 * 448 * @param callbackType The callback type. 449 * @param action The callback action to run during the next frame after the specified delay. 450 * @param token The callback token, or null if none. 451 * @param delayMillis The delay time in milliseconds. 452 * 453 * @see #removeCallback 454 * @hide 455 */ 456 @UnsupportedAppUsage 457 @TestApi postCallbackDelayed(int callbackType, Runnable action, Object token, long delayMillis)458 public void postCallbackDelayed(int callbackType, 459 Runnable action, Object token, long delayMillis) { 460 if (action == null) { 461 throw new IllegalArgumentException("action must not be null"); 462 } 463 if (callbackType < 0 || callbackType > CALLBACK_LAST) { 464 throw new IllegalArgumentException("callbackType is invalid"); 465 } 466 467 postCallbackDelayedInternal(callbackType, action, token, delayMillis); 468 } 469 postCallbackDelayedInternal(int callbackType, Object action, Object token, long delayMillis)470 private void postCallbackDelayedInternal(int callbackType, 471 Object action, Object token, long delayMillis) { 472 if (DEBUG_FRAMES) { 473 Log.d(TAG, "PostCallback: type=" + callbackType 474 + ", action=" + action + ", token=" + token 475 + ", delayMillis=" + delayMillis); 476 } 477 478 synchronized (mLock) { 479 final long now = SystemClock.uptimeMillis(); 480 final long dueTime = now + delayMillis; 481 mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token); 482 483 if (dueTime <= now) { 484 scheduleFrameLocked(now); 485 } else { 486 Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action); 487 msg.arg1 = callbackType; 488 msg.setAsynchronous(true); 489 mHandler.sendMessageAtTime(msg, dueTime); 490 } 491 } 492 } 493 494 /** 495 * Posts a vsync callback to run on the next frame. 496 * <p> 497 * The callback runs once then is automatically removed. 498 * </p> 499 * 500 * @param callback The vsync callback to run during the next frame. 501 * 502 * @see #removeVsyncCallback 503 */ postVsyncCallback(@onNull VsyncCallback callback)504 public void postVsyncCallback(@NonNull VsyncCallback callback) { 505 if (callback == null) { 506 throw new IllegalArgumentException("callback must not be null"); 507 } 508 509 postCallbackDelayedInternal(CALLBACK_ANIMATION, callback, VSYNC_CALLBACK_TOKEN, 0); 510 } 511 512 /** 513 * Removes callbacks that have the specified action and token. 514 * 515 * @param callbackType The callback type. 516 * @param action The action property of the callbacks to remove, or null to remove 517 * callbacks with any action. 518 * @param token The token property of the callbacks to remove, or null to remove 519 * callbacks with any token. 520 * 521 * @see #postCallback 522 * @see #postCallbackDelayed 523 * @hide 524 */ 525 @UnsupportedAppUsage 526 @TestApi removeCallbacks(int callbackType, Runnable action, Object token)527 public void removeCallbacks(int callbackType, Runnable action, Object token) { 528 if (callbackType < 0 || callbackType > CALLBACK_LAST) { 529 throw new IllegalArgumentException("callbackType is invalid"); 530 } 531 532 removeCallbacksInternal(callbackType, action, token); 533 } 534 removeCallbacksInternal(int callbackType, Object action, Object token)535 private void removeCallbacksInternal(int callbackType, Object action, Object token) { 536 if (DEBUG_FRAMES) { 537 Log.d(TAG, "RemoveCallbacks: type=" + callbackType 538 + ", action=" + action + ", token=" + token); 539 } 540 541 synchronized (mLock) { 542 mCallbackQueues[callbackType].removeCallbacksLocked(action, token); 543 if (action != null && token == null) { 544 mHandler.removeMessages(MSG_DO_SCHEDULE_CALLBACK, action); 545 } 546 } 547 } 548 549 /** 550 * Posts a frame callback to run on the next frame. 551 * <p> 552 * The callback runs once then is automatically removed. 553 * </p> 554 * 555 * @param callback The frame callback to run during the next frame. 556 * 557 * @see #postFrameCallbackDelayed 558 * @see #removeFrameCallback 559 */ postFrameCallback(FrameCallback callback)560 public void postFrameCallback(FrameCallback callback) { 561 postFrameCallbackDelayed(callback, 0); 562 } 563 564 /** 565 * Posts a frame callback to run on the next frame after the specified delay. 566 * <p> 567 * The callback runs once then is automatically removed. 568 * </p> 569 * 570 * @param callback The frame callback to run during the next frame. 571 * @param delayMillis The delay time in milliseconds. 572 * 573 * @see #postFrameCallback 574 * @see #removeFrameCallback 575 */ postFrameCallbackDelayed(FrameCallback callback, long delayMillis)576 public void postFrameCallbackDelayed(FrameCallback callback, long delayMillis) { 577 if (callback == null) { 578 throw new IllegalArgumentException("callback must not be null"); 579 } 580 581 postCallbackDelayedInternal(CALLBACK_ANIMATION, 582 callback, FRAME_CALLBACK_TOKEN, delayMillis); 583 } 584 585 /** 586 * Removes a previously posted frame callback. 587 * 588 * @param callback The frame callback to remove. 589 * 590 * @see #postFrameCallback 591 * @see #postFrameCallbackDelayed 592 */ removeFrameCallback(FrameCallback callback)593 public void removeFrameCallback(FrameCallback callback) { 594 if (callback == null) { 595 throw new IllegalArgumentException("callback must not be null"); 596 } 597 598 removeCallbacksInternal(CALLBACK_ANIMATION, callback, FRAME_CALLBACK_TOKEN); 599 } 600 601 /** 602 * Removes a previously posted vsync callback. 603 * 604 * @param callback The vsync callback to remove. 605 * 606 * @see #postVsyncCallback 607 */ removeVsyncCallback(@ullable VsyncCallback callback)608 public void removeVsyncCallback(@Nullable VsyncCallback callback) { 609 if (callback == null) { 610 throw new IllegalArgumentException("callback must not be null"); 611 } 612 613 removeCallbacksInternal(CALLBACK_ANIMATION, callback, VSYNC_CALLBACK_TOKEN); 614 } 615 616 /** 617 * Gets the time when the current frame started. 618 * <p> 619 * This method provides the time in milliseconds when the frame started being rendered. 620 * The frame time provides a stable time base for synchronizing animations 621 * and drawing. It should be used instead of {@link SystemClock#uptimeMillis()} 622 * or {@link System#nanoTime()} for animations and drawing in the UI. Using the frame 623 * time helps to reduce inter-frame jitter because the frame time is fixed at the time 624 * the frame was scheduled to start, regardless of when the animations or drawing 625 * callback actually runs. All callbacks that run as part of rendering a frame will 626 * observe the same frame time so using the frame time also helps to synchronize effects 627 * that are performed by different callbacks. 628 * </p><p> 629 * Please note that the framework already takes care to process animations and 630 * drawing using the frame time as a stable time base. Most applications should 631 * not need to use the frame time information directly. 632 * </p><p> 633 * This method should only be called from within a callback. 634 * </p> 635 * 636 * @return The frame start time, in the {@link SystemClock#uptimeMillis()} time base. 637 * 638 * @throws IllegalStateException if no frame is in progress. 639 * @hide 640 */ 641 @UnsupportedAppUsage getFrameTime()642 public long getFrameTime() { 643 return getFrameTimeNanos() / TimeUtils.NANOS_PER_MS; 644 } 645 646 /** 647 * Same as {@link #getFrameTime()} but with nanosecond precision. 648 * 649 * @return The frame start time, in the {@link System#nanoTime()} time base. 650 * 651 * @throws IllegalStateException if no frame is in progress. 652 * @hide 653 */ 654 @UnsupportedAppUsage getFrameTimeNanos()655 public long getFrameTimeNanos() { 656 synchronized (mLock) { 657 if (!mCallbacksRunning) { 658 throw new IllegalStateException("This method must only be called as " 659 + "part of a callback while a frame is in progress."); 660 } 661 return USE_FRAME_TIME ? mLastFrameTimeNanos : System.nanoTime(); 662 } 663 } 664 665 /** 666 * Like {@link #getLastFrameTimeNanos}, but always returns the last frame time, not matter 667 * whether callbacks are currently running. 668 * @return The frame start time of the last frame, in the {@link System#nanoTime()} time base. 669 * @hide 670 */ getLastFrameTimeNanos()671 public long getLastFrameTimeNanos() { 672 synchronized (mLock) { 673 return USE_FRAME_TIME ? mLastFrameTimeNanos : System.nanoTime(); 674 } 675 } 676 scheduleFrameLocked(long now)677 private void scheduleFrameLocked(long now) { 678 if (!mFrameScheduled) { 679 mFrameScheduled = true; 680 if (USE_VSYNC) { 681 if (DEBUG_FRAMES) { 682 Log.d(TAG, "Scheduling next frame on vsync."); 683 } 684 685 // If running on the Looper thread, then schedule the vsync immediately, 686 // otherwise post a message to schedule the vsync from the UI thread 687 // as soon as possible. 688 if (isRunningOnLooperThreadLocked()) { 689 scheduleVsyncLocked(); 690 } else { 691 Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC); 692 msg.setAsynchronous(true); 693 mHandler.sendMessageAtFrontOfQueue(msg); 694 } 695 } else { 696 final long nextFrameTime = Math.max( 697 mLastFrameTimeNanos / TimeUtils.NANOS_PER_MS + sFrameDelay, now); 698 if (DEBUG_FRAMES) { 699 Log.d(TAG, "Scheduling next frame in " + (nextFrameTime - now) + " ms."); 700 } 701 Message msg = mHandler.obtainMessage(MSG_DO_FRAME); 702 msg.setAsynchronous(true); 703 mHandler.sendMessageAtTime(msg, nextFrameTime); 704 } 705 } 706 } 707 708 /** 709 * Returns the vsync id of the last frame callback. Client are expected to call 710 * this function from their frame callback function to get the vsyncId and pass 711 * it together with a buffer or transaction to the Surface Composer. Calling 712 * this function from anywhere else will return an undefined value. 713 * 714 * @hide 715 */ getVsyncId()716 public long getVsyncId() { 717 return mLastVsyncEventData.preferredFrameTimeline().vsyncId; 718 } 719 720 /** 721 * Returns the frame deadline in {@link System#nanoTime()} timebase that it is allotted for the 722 * frame to be completed. Client are expected to call this function from their frame callback 723 * function. Calling this function from anywhere else will return an undefined value. 724 * 725 * @hide 726 */ getFrameDeadline()727 public long getFrameDeadline() { 728 return mLastVsyncEventData.preferredFrameTimeline().deadline; 729 } 730 setFPSDivisor(int divisor)731 void setFPSDivisor(int divisor) { 732 if (divisor <= 0) divisor = 1; 733 mFPSDivisor = divisor; 734 ThreadedRenderer.setFPSDivisor(divisor); 735 } 736 traceMessage(String msg)737 private void traceMessage(String msg) { 738 Trace.traceBegin(Trace.TRACE_TAG_VIEW, msg); 739 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 740 } 741 doFrame(long frameTimeNanos, int frame, DisplayEventReceiver.VsyncEventData vsyncEventData)742 void doFrame(long frameTimeNanos, int frame, 743 DisplayEventReceiver.VsyncEventData vsyncEventData) { 744 final long startNanos; 745 final long frameIntervalNanos = vsyncEventData.frameInterval; 746 try { 747 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { 748 Trace.traceBegin(Trace.TRACE_TAG_VIEW, 749 "Choreographer#doFrame " + vsyncEventData.preferredFrameTimeline().vsyncId); 750 } 751 FrameData frameData = new FrameData(frameTimeNanos, vsyncEventData); 752 synchronized (mLock) { 753 if (!mFrameScheduled) { 754 traceMessage("Frame not scheduled"); 755 return; // no work to do 756 } 757 758 if (DEBUG_JANK && mDebugPrintNextFrameTimeDelta) { 759 mDebugPrintNextFrameTimeDelta = false; 760 Log.d(TAG, "Frame time delta: " 761 + ((frameTimeNanos - mLastFrameTimeNanos) * 0.000001f) + " ms"); 762 } 763 764 long intendedFrameTimeNanos = frameTimeNanos; 765 startNanos = System.nanoTime(); 766 final long jitterNanos = startNanos - frameTimeNanos; 767 if (jitterNanos >= frameIntervalNanos) { 768 long lastFrameOffset = 0; 769 if (frameIntervalNanos == 0) { 770 Log.i(TAG, "Vsync data empty due to timeout"); 771 } else { 772 lastFrameOffset = jitterNanos % frameIntervalNanos; 773 final long skippedFrames = jitterNanos / frameIntervalNanos; 774 if (skippedFrames >= SKIPPED_FRAME_WARNING_LIMIT) { 775 Log.i(TAG, "Skipped " + skippedFrames + " frames! " 776 + "The application may be doing too much work on its main " 777 + "thread."); 778 } 779 if (DEBUG_JANK) { 780 Log.d(TAG, "Missed vsync by " + (jitterNanos * 0.000001f) + " ms " 781 + "which is more than the frame interval of " 782 + (frameIntervalNanos * 0.000001f) + " ms! " 783 + "Skipping " + skippedFrames + " frames and setting frame " 784 + "time to " + (lastFrameOffset * 0.000001f) 785 + " ms in the past."); 786 } 787 } 788 frameTimeNanos = startNanos - lastFrameOffset; 789 frameData.updateFrameData(frameTimeNanos); 790 } 791 792 if (frameTimeNanos < mLastFrameTimeNanos) { 793 if (DEBUG_JANK) { 794 Log.d(TAG, "Frame time appears to be going backwards. May be due to a " 795 + "previously skipped frame. Waiting for next vsync."); 796 } 797 traceMessage("Frame time goes backward"); 798 scheduleVsyncLocked(); 799 return; 800 } 801 802 if (mFPSDivisor > 1) { 803 long timeSinceVsync = frameTimeNanos - mLastFrameTimeNanos; 804 if (timeSinceVsync < (frameIntervalNanos * mFPSDivisor) && timeSinceVsync > 0) { 805 traceMessage("Frame skipped due to FPSDivisor"); 806 scheduleVsyncLocked(); 807 return; 808 } 809 } 810 811 mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos, 812 vsyncEventData.preferredFrameTimeline().vsyncId, 813 vsyncEventData.preferredFrameTimeline().deadline, startNanos, 814 vsyncEventData.frameInterval); 815 mFrameScheduled = false; 816 mLastFrameTimeNanos = frameTimeNanos; 817 mLastFrameIntervalNanos = frameIntervalNanos; 818 mLastVsyncEventData = vsyncEventData; 819 } 820 821 AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS); 822 823 mFrameInfo.markInputHandlingStart(); 824 doCallbacks(Choreographer.CALLBACK_INPUT, frameData, frameIntervalNanos); 825 826 mFrameInfo.markAnimationsStart(); 827 doCallbacks(Choreographer.CALLBACK_ANIMATION, frameData, frameIntervalNanos); 828 doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameData, 829 frameIntervalNanos); 830 831 mFrameInfo.markPerformTraversalsStart(); 832 doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameData, frameIntervalNanos); 833 834 doCallbacks(Choreographer.CALLBACK_COMMIT, frameData, frameIntervalNanos); 835 } finally { 836 AnimationUtils.unlockAnimationClock(); 837 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 838 } 839 840 if (DEBUG_FRAMES) { 841 final long endNanos = System.nanoTime(); 842 Log.d(TAG, "Frame " + frame + ": Finished, took " 843 + (endNanos - startNanos) * 0.000001f + " ms, latency " 844 + (startNanos - frameTimeNanos) * 0.000001f + " ms."); 845 } 846 } 847 doCallbacks(int callbackType, FrameData frameData, long frameIntervalNanos)848 void doCallbacks(int callbackType, FrameData frameData, long frameIntervalNanos) { 849 CallbackRecord callbacks; 850 long frameTimeNanos = frameData.mFrameTimeNanos; 851 synchronized (mLock) { 852 // We use "now" to determine when callbacks become due because it's possible 853 // for earlier processing phases in a frame to post callbacks that should run 854 // in a following phase, such as an input event that causes an animation to start. 855 final long now = System.nanoTime(); 856 callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked( 857 now / TimeUtils.NANOS_PER_MS); 858 if (callbacks == null) { 859 return; 860 } 861 mCallbacksRunning = true; 862 863 // Update the frame time if necessary when committing the frame. 864 // We only update the frame time if we are more than 2 frames late reaching 865 // the commit phase. This ensures that the frame time which is observed by the 866 // callbacks will always increase from one frame to the next and never repeat. 867 // We never want the next frame's starting frame time to end up being less than 868 // or equal to the previous frame's commit frame time. Keep in mind that the 869 // next frame has most likely already been scheduled by now so we play it 870 // safe by ensuring the commit time is always at least one frame behind. 871 if (callbackType == Choreographer.CALLBACK_COMMIT) { 872 final long jitterNanos = now - frameTimeNanos; 873 Trace.traceCounter(Trace.TRACE_TAG_VIEW, "jitterNanos", (int) jitterNanos); 874 if (jitterNanos >= 2 * frameIntervalNanos) { 875 final long lastFrameOffset = jitterNanos % frameIntervalNanos 876 + frameIntervalNanos; 877 if (DEBUG_JANK) { 878 Log.d(TAG, "Commit callback delayed by " + (jitterNanos * 0.000001f) 879 + " ms which is more than twice the frame interval of " 880 + (frameIntervalNanos * 0.000001f) + " ms! " 881 + "Setting frame time to " + (lastFrameOffset * 0.000001f) 882 + " ms in the past."); 883 mDebugPrintNextFrameTimeDelta = true; 884 } 885 frameTimeNanos = now - lastFrameOffset; 886 mLastFrameTimeNanos = frameTimeNanos; 887 frameData.updateFrameData(frameTimeNanos); 888 } 889 } 890 } 891 try { 892 Trace.traceBegin(Trace.TRACE_TAG_VIEW, CALLBACK_TRACE_TITLES[callbackType]); 893 for (CallbackRecord c = callbacks; c != null; c = c.next) { 894 if (DEBUG_FRAMES) { 895 Log.d(TAG, "RunCallback: type=" + callbackType 896 + ", action=" + c.action + ", token=" + c.token 897 + ", latencyMillis=" + (SystemClock.uptimeMillis() - c.dueTime)); 898 } 899 c.run(frameData); 900 } 901 } finally { 902 synchronized (mLock) { 903 mCallbacksRunning = false; 904 do { 905 final CallbackRecord next = callbacks.next; 906 recycleCallbackLocked(callbacks); 907 callbacks = next; 908 } while (callbacks != null); 909 } 910 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 911 } 912 } 913 doScheduleVsync()914 void doScheduleVsync() { 915 synchronized (mLock) { 916 if (mFrameScheduled) { 917 scheduleVsyncLocked(); 918 } 919 } 920 } 921 doScheduleCallback(int callbackType)922 void doScheduleCallback(int callbackType) { 923 synchronized (mLock) { 924 if (!mFrameScheduled) { 925 final long now = SystemClock.uptimeMillis(); 926 if (mCallbackQueues[callbackType].hasDueCallbacksLocked(now)) { 927 scheduleFrameLocked(now); 928 } 929 } 930 } 931 } 932 933 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) scheduleVsyncLocked()934 private void scheduleVsyncLocked() { 935 try { 936 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#scheduleVsyncLocked"); 937 mDisplayEventReceiver.scheduleVsync(); 938 } finally { 939 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 940 } 941 } 942 isRunningOnLooperThreadLocked()943 private boolean isRunningOnLooperThreadLocked() { 944 return Looper.myLooper() == mLooper; 945 } 946 obtainCallbackLocked(long dueTime, Object action, Object token)947 private CallbackRecord obtainCallbackLocked(long dueTime, Object action, Object token) { 948 CallbackRecord callback = mCallbackPool; 949 if (callback == null) { 950 callback = new CallbackRecord(); 951 } else { 952 mCallbackPool = callback.next; 953 callback.next = null; 954 } 955 callback.dueTime = dueTime; 956 callback.action = action; 957 callback.token = token; 958 return callback; 959 } 960 recycleCallbackLocked(CallbackRecord callback)961 private void recycleCallbackLocked(CallbackRecord callback) { 962 callback.action = null; 963 callback.token = null; 964 callback.next = mCallbackPool; 965 mCallbackPool = callback; 966 } 967 968 /** 969 * Implement this interface to receive a callback when a new display frame is 970 * being rendered. The callback is invoked on the {@link Looper} thread to 971 * which the {@link Choreographer} is attached. 972 */ 973 public interface FrameCallback { 974 /** 975 * Called when a new display frame is being rendered. 976 * <p> 977 * This method provides the time in nanoseconds when the frame started being rendered. 978 * The frame time provides a stable time base for synchronizing animations 979 * and drawing. It should be used instead of {@link SystemClock#uptimeMillis()} 980 * or {@link System#nanoTime()} for animations and drawing in the UI. Using the frame 981 * time helps to reduce inter-frame jitter because the frame time is fixed at the time 982 * the frame was scheduled to start, regardless of when the animations or drawing 983 * callback actually runs. All callbacks that run as part of rendering a frame will 984 * observe the same frame time so using the frame time also helps to synchronize effects 985 * that are performed by different callbacks. 986 * </p><p> 987 * Please note that the framework already takes care to process animations and 988 * drawing using the frame time as a stable time base. Most applications should 989 * not need to use the frame time information directly. 990 * </p> 991 * 992 * @param frameTimeNanos The time in nanoseconds when the frame started being rendered, 993 * in the {@link System#nanoTime()} timebase. Divide this value by {@code 1000000} 994 * to convert it to the {@link SystemClock#uptimeMillis()} time base. 995 */ doFrame(long frameTimeNanos)996 public void doFrame(long frameTimeNanos); 997 } 998 999 /** Holds data that describes one possible VSync frame event to render at. */ 1000 public static class FrameTimeline { 1001 static final FrameTimeline INVALID_FRAME_TIMELINE = new FrameTimeline( 1002 FrameInfo.INVALID_VSYNC_ID, Long.MAX_VALUE, Long.MAX_VALUE); 1003 FrameTimeline(long vsyncId, long expectedPresentTimeNanos, long deadlineNanos)1004 FrameTimeline(long vsyncId, long expectedPresentTimeNanos, long deadlineNanos) { 1005 this.mVsyncId = vsyncId; 1006 this.mExpectedPresentTimeNanos = expectedPresentTimeNanos; 1007 this.mDeadlineNanos = deadlineNanos; 1008 } 1009 1010 private long mVsyncId; 1011 private long mExpectedPresentTimeNanos; 1012 private long mDeadlineNanos; 1013 1014 /** 1015 * The id that corresponds to this frame timeline, used to correlate a frame 1016 * produced by HWUI with the timeline data stored in Surface Flinger. 1017 */ getVsyncId()1018 public long getVsyncId() { 1019 return mVsyncId; 1020 } 1021 1022 /** Reset the vsync ID to invalid. */ resetVsyncId()1023 void resetVsyncId() { 1024 mVsyncId = FrameInfo.INVALID_VSYNC_ID; 1025 } 1026 1027 /** 1028 * The time in {@link System#nanoTime()} timebase which this frame is expected to be 1029 * presented. 1030 */ getExpectedPresentationTimeNanos()1031 public long getExpectedPresentationTimeNanos() { 1032 return mExpectedPresentTimeNanos; 1033 } 1034 1035 /** 1036 * The time in {@link System#nanoTime()} timebase which this frame needs to be ready by. 1037 */ getDeadlineNanos()1038 public long getDeadlineNanos() { 1039 return mDeadlineNanos; 1040 } 1041 } 1042 1043 /** 1044 * The payload for {@link VsyncCallback} which includes frame information such as when 1045 * the frame started being rendered, and multiple possible frame timelines and their 1046 * information including deadline and expected present time. 1047 */ 1048 public static class FrameData { 1049 static final FrameTimeline[] INVALID_FRAME_TIMELINES = new FrameTimeline[0]; FrameData()1050 FrameData() { 1051 this.mFrameTimelines = INVALID_FRAME_TIMELINES; 1052 this.mPreferredFrameTimeline = FrameTimeline.INVALID_FRAME_TIMELINE; 1053 } 1054 FrameData(long frameTimeNanos, DisplayEventReceiver.VsyncEventData vsyncEventData)1055 FrameData(long frameTimeNanos, DisplayEventReceiver.VsyncEventData vsyncEventData) { 1056 FrameTimeline[] frameTimelines = 1057 new FrameTimeline[vsyncEventData.frameTimelines.length]; 1058 for (int i = 0; i < vsyncEventData.frameTimelines.length; i++) { 1059 DisplayEventReceiver.VsyncEventData.FrameTimeline frameTimeline = 1060 vsyncEventData.frameTimelines[i]; 1061 frameTimelines[i] = new FrameTimeline(frameTimeline.vsyncId, 1062 frameTimeline.expectedPresentTime, frameTimeline.deadline); 1063 } 1064 this.mFrameTimeNanos = frameTimeNanos; 1065 this.mFrameTimelines = frameTimelines; 1066 this.mPreferredFrameTimeline = 1067 frameTimelines[vsyncEventData.preferredFrameTimelineIndex]; 1068 } 1069 1070 private long mFrameTimeNanos; 1071 private FrameTimeline[] mFrameTimelines; 1072 private FrameTimeline mPreferredFrameTimeline; 1073 updateFrameData(long frameTimeNanos)1074 void updateFrameData(long frameTimeNanos) { 1075 mFrameTimeNanos = frameTimeNanos; 1076 for (FrameTimeline ft : mFrameTimelines) { 1077 // The ID is no longer valid because the frame time that was registered with the ID 1078 // no longer matches. 1079 // TODO(b/205721584): Ask SF for valid vsync information. 1080 ft.resetVsyncId(); 1081 } 1082 } 1083 1084 /** The time in nanoseconds when the frame started being rendered. */ getFrameTimeNanos()1085 public long getFrameTimeNanos() { 1086 return mFrameTimeNanos; 1087 } 1088 1089 /** The possible frame timelines, sorted chronologically. */ 1090 @NonNull 1091 @SuppressLint("ArrayReturn") // For API consistency and speed. getFrameTimelines()1092 public FrameTimeline[] getFrameTimelines() { 1093 return mFrameTimelines; 1094 } 1095 1096 /** The platform-preferred frame timeline. */ 1097 @NonNull getPreferredFrameTimeline()1098 public FrameTimeline getPreferredFrameTimeline() { 1099 return mPreferredFrameTimeline; 1100 } 1101 convertFrameTimelines( DisplayEventReceiver.VsyncEventData vsyncEventData)1102 private FrameTimeline[] convertFrameTimelines( 1103 DisplayEventReceiver.VsyncEventData vsyncEventData) { 1104 FrameTimeline[] frameTimelines = 1105 new FrameTimeline[vsyncEventData.frameTimelines.length]; 1106 for (int i = 0; i < vsyncEventData.frameTimelines.length; i++) { 1107 DisplayEventReceiver.VsyncEventData.FrameTimeline frameTimeline = 1108 vsyncEventData.frameTimelines[i]; 1109 frameTimelines[i] = new FrameTimeline(frameTimeline.vsyncId, 1110 frameTimeline.expectedPresentTime, frameTimeline.deadline); 1111 } 1112 return frameTimelines; 1113 } 1114 } 1115 1116 /** 1117 * Implement this interface to receive a callback to start the next frame. The callback is 1118 * invoked on the {@link Looper} thread to which the {@link Choreographer} is attached. The 1119 * callback payload contains information about multiple possible frames, allowing choice of 1120 * the appropriate frame based on latency requirements. 1121 * 1122 * @see FrameCallback 1123 */ 1124 public interface VsyncCallback { 1125 /** 1126 * Called when a new display frame is being rendered. 1127 * 1128 * @param data The payload which includes frame information. Divide nanosecond values by 1129 * {@code 1000000} to convert it to the {@link SystemClock#uptimeMillis()} 1130 * time base. 1131 * @see FrameCallback#doFrame 1132 **/ onVsync(@onNull FrameData data)1133 void onVsync(@NonNull FrameData data); 1134 } 1135 1136 private final class FrameHandler extends Handler { FrameHandler(Looper looper)1137 public FrameHandler(Looper looper) { 1138 super(looper); 1139 } 1140 1141 @Override handleMessage(Message msg)1142 public void handleMessage(Message msg) { 1143 switch (msg.what) { 1144 case MSG_DO_FRAME: 1145 doFrame(System.nanoTime(), 0, new DisplayEventReceiver.VsyncEventData()); 1146 break; 1147 case MSG_DO_SCHEDULE_VSYNC: 1148 doScheduleVsync(); 1149 break; 1150 case MSG_DO_SCHEDULE_CALLBACK: 1151 doScheduleCallback(msg.arg1); 1152 break; 1153 } 1154 } 1155 } 1156 1157 private final class FrameDisplayEventReceiver extends DisplayEventReceiver 1158 implements Runnable { 1159 private boolean mHavePendingVsync; 1160 private long mTimestampNanos; 1161 private int mFrame; 1162 private VsyncEventData mLastVsyncEventData = new VsyncEventData(); 1163 FrameDisplayEventReceiver(Looper looper, int vsyncSource)1164 public FrameDisplayEventReceiver(Looper looper, int vsyncSource) { 1165 super(looper, vsyncSource, 0); 1166 } 1167 1168 // TODO(b/116025192): physicalDisplayId is ignored because SF only emits VSYNC events for 1169 // the internal display and DisplayEventReceiver#scheduleVsync only allows requesting VSYNC 1170 // for the internal display implicitly. 1171 @Override onVsync(long timestampNanos, long physicalDisplayId, int frame, VsyncEventData vsyncEventData)1172 public void onVsync(long timestampNanos, long physicalDisplayId, int frame, 1173 VsyncEventData vsyncEventData) { 1174 try { 1175 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { 1176 Trace.traceBegin(Trace.TRACE_TAG_VIEW, 1177 "Choreographer#onVsync " 1178 + vsyncEventData.preferredFrameTimeline().vsyncId); 1179 } 1180 // Post the vsync event to the Handler. 1181 // The idea is to prevent incoming vsync events from completely starving 1182 // the message queue. If there are no messages in the queue with timestamps 1183 // earlier than the frame time, then the vsync event will be processed immediately. 1184 // Otherwise, messages that predate the vsync event will be handled first. 1185 long now = System.nanoTime(); 1186 if (timestampNanos > now) { 1187 Log.w(TAG, "Frame time is " + ((timestampNanos - now) * 0.000001f) 1188 + " ms in the future! Check that graphics HAL is generating vsync " 1189 + "timestamps using the correct timebase."); 1190 timestampNanos = now; 1191 } 1192 1193 if (mHavePendingVsync) { 1194 Log.w(TAG, "Already have a pending vsync event. There should only be " 1195 + "one at a time."); 1196 } else { 1197 mHavePendingVsync = true; 1198 } 1199 1200 mTimestampNanos = timestampNanos; 1201 mFrame = frame; 1202 mLastVsyncEventData = vsyncEventData; 1203 Message msg = Message.obtain(mHandler, this); 1204 msg.setAsynchronous(true); 1205 mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS); 1206 } finally { 1207 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 1208 } 1209 } 1210 1211 @Override run()1212 public void run() { 1213 mHavePendingVsync = false; 1214 doFrame(mTimestampNanos, mFrame, mLastVsyncEventData); 1215 } 1216 } 1217 1218 private static final class CallbackRecord { 1219 public CallbackRecord next; 1220 public long dueTime; 1221 /** Runnable or FrameCallback or VsyncCallback object. */ 1222 public Object action; 1223 /** Denotes the action type. */ 1224 public Object token; 1225 1226 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) run(long frameTimeNanos)1227 public void run(long frameTimeNanos) { 1228 if (token == FRAME_CALLBACK_TOKEN) { 1229 ((FrameCallback)action).doFrame(frameTimeNanos); 1230 } else { 1231 ((Runnable)action).run(); 1232 } 1233 } 1234 run(FrameData frameData)1235 void run(FrameData frameData) { 1236 if (token == VSYNC_CALLBACK_TOKEN) { 1237 ((VsyncCallback) action).onVsync(frameData); 1238 } else { 1239 run(frameData.getFrameTimeNanos()); 1240 } 1241 } 1242 } 1243 1244 private final class CallbackQueue { 1245 private CallbackRecord mHead; 1246 hasDueCallbacksLocked(long now)1247 public boolean hasDueCallbacksLocked(long now) { 1248 return mHead != null && mHead.dueTime <= now; 1249 } 1250 extractDueCallbacksLocked(long now)1251 public CallbackRecord extractDueCallbacksLocked(long now) { 1252 CallbackRecord callbacks = mHead; 1253 if (callbacks == null || callbacks.dueTime > now) { 1254 return null; 1255 } 1256 1257 CallbackRecord last = callbacks; 1258 CallbackRecord next = last.next; 1259 while (next != null) { 1260 if (next.dueTime > now) { 1261 last.next = null; 1262 break; 1263 } 1264 last = next; 1265 next = next.next; 1266 } 1267 mHead = next; 1268 return callbacks; 1269 } 1270 1271 @UnsupportedAppUsage addCallbackLocked(long dueTime, Object action, Object token)1272 public void addCallbackLocked(long dueTime, Object action, Object token) { 1273 CallbackRecord callback = obtainCallbackLocked(dueTime, action, token); 1274 CallbackRecord entry = mHead; 1275 if (entry == null) { 1276 mHead = callback; 1277 return; 1278 } 1279 if (dueTime < entry.dueTime) { 1280 callback.next = entry; 1281 mHead = callback; 1282 return; 1283 } 1284 while (entry.next != null) { 1285 if (dueTime < entry.next.dueTime) { 1286 callback.next = entry.next; 1287 break; 1288 } 1289 entry = entry.next; 1290 } 1291 entry.next = callback; 1292 } 1293 removeCallbacksLocked(Object action, Object token)1294 public void removeCallbacksLocked(Object action, Object token) { 1295 CallbackRecord predecessor = null; 1296 for (CallbackRecord callback = mHead; callback != null;) { 1297 final CallbackRecord next = callback.next; 1298 if ((action == null || callback.action == action) 1299 && (token == null || callback.token == token)) { 1300 if (predecessor != null) { 1301 predecessor.next = next; 1302 } else { 1303 mHead = next; 1304 } 1305 recycleCallbackLocked(callback); 1306 } else { 1307 predecessor = callback; 1308 } 1309 callback = next; 1310 } 1311 } 1312 } 1313 } 1314