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