Home | History | Annotate | Download | only in view
      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.TestApi;
     23 import android.hardware.display.DisplayManagerGlobal;
     24 import android.os.Handler;
     25 import android.os.Looper;
     26 import android.os.Message;
     27 import android.os.SystemClock;
     28 import android.os.SystemProperties;
     29 import android.os.Trace;
     30 import android.util.Log;
     31 import android.util.TimeUtils;
     32 import android.view.animation.AnimationUtils;
     33 
     34 import java.io.PrintWriter;
     35 
     36 /**
     37  * Coordinates the timing of animations, input and drawing.
     38  * <p>
     39  * The choreographer receives timing pulses (such as vertical synchronization)
     40  * from the display subsystem then schedules work to occur as part of rendering
     41  * the next display frame.
     42  * </p><p>
     43  * Applications typically interact with the choreographer indirectly using
     44  * higher level abstractions in the animation framework or the view hierarchy.
     45  * Here are some examples of things you can do using the higher-level APIs.
     46  * </p>
     47  * <ul>
     48  * <li>To post an animation to be processed on a regular time basis synchronized with
     49  * display frame rendering, use {@link android.animation.ValueAnimator#start}.</li>
     50  * <li>To post a {@link Runnable} to be invoked once at the beginning of the next display
     51  * frame, use {@link View#postOnAnimation}.</li>
     52  * <li>To post a {@link Runnable} to be invoked once at the beginning of the next display
     53  * frame after a delay, use {@link View#postOnAnimationDelayed}.</li>
     54  * <li>To post a call to {@link View#invalidate()} to occur once at the beginning of the
     55  * next display frame, use {@link View#postInvalidateOnAnimation()} or
     56  * {@link View#postInvalidateOnAnimation(int, int, int, int)}.</li>
     57  * <li>To ensure that the contents of a {@link View} scroll smoothly and are drawn in
     58  * sync with display frame rendering, do nothing.  This already happens automatically.
     59  * {@link View#onDraw} will be called at the appropriate time.</li>
     60  * </ul>
     61  * <p>
     62  * However, there are a few cases where you might want to use the functions of the
     63  * choreographer directly in your application.  Here are some examples.
     64  * </p>
     65  * <ul>
     66  * <li>If your application does its rendering in a different thread, possibly using GL,
     67  * or does not use the animation framework or view hierarchy at all
     68  * and you want to ensure that it is appropriately synchronized with the display, then use
     69  * {@link Choreographer#postFrameCallback}.</li>
     70  * <li>... and that's about it.</li>
     71  * </ul>
     72  * <p>
     73  * Each {@link Looper} thread has its own choreographer.  Other threads can
     74  * post callbacks to run on the choreographer but they will run on the {@link Looper}
     75  * to which the choreographer belongs.
     76  * </p>
     77  */
     78 public final class Choreographer {
     79     private static final String TAG = "Choreographer";
     80 
     81     // Prints debug messages about jank which was detected (low volume).
     82     private static final boolean DEBUG_JANK = false;
     83 
     84     // Prints debug messages about every frame and callback registered (high volume).
     85     private static final boolean DEBUG_FRAMES = false;
     86 
     87     // The default amount of time in ms between animation frames.
     88     // When vsync is not enabled, we want to have some idea of how long we should
     89     // wait before posting the next animation message.  It is important that the
     90     // default value be less than the true inter-frame delay on all devices to avoid
     91     // situations where we might skip frames by waiting too long (we must compensate
     92     // for jitter and hardware variations).  Regardless of this value, the animation
     93     // and display loop is ultimately rate-limited by how fast new graphics buffers can
     94     // be dequeued.
     95     private static final long DEFAULT_FRAME_DELAY = 10;
     96 
     97     // The number of milliseconds between animation frames.
     98     private static volatile long sFrameDelay = DEFAULT_FRAME_DELAY;
     99 
    100     // Thread local storage for the choreographer.
    101     private static final ThreadLocal<Choreographer> sThreadInstance =
    102             new ThreadLocal<Choreographer>() {
    103         @Override
    104         protected Choreographer initialValue() {
    105             Looper looper = Looper.myLooper();
    106             if (looper == null) {
    107                 throw new IllegalStateException("The current thread must have a looper!");
    108             }
    109             Choreographer choreographer = new Choreographer(looper, VSYNC_SOURCE_APP);
    110             if (looper == Looper.getMainLooper()) {
    111                 mMainInstance = choreographer;
    112             }
    113             return choreographer;
    114         }
    115     };
    116 
    117     private static volatile Choreographer mMainInstance;
    118 
    119     // Thread local storage for the SF choreographer.
    120     private static final ThreadLocal<Choreographer> sSfThreadInstance =
    121             new ThreadLocal<Choreographer>() {
    122                 @Override
    123                 protected Choreographer initialValue() {
    124                     Looper looper = Looper.myLooper();
    125                     if (looper == null) {
    126                         throw new IllegalStateException("The current thread must have a looper!");
    127                     }
    128                     return new Choreographer(looper, VSYNC_SOURCE_SURFACE_FLINGER);
    129                 }
    130             };
    131 
    132     // Enable/disable vsync for animations and drawing.
    133     private static final boolean USE_VSYNC = SystemProperties.getBoolean(
    134             "debug.choreographer.vsync", true);
    135 
    136     // Enable/disable using the frame time instead of returning now.
    137     private static final boolean USE_FRAME_TIME = SystemProperties.getBoolean(
    138             "debug.choreographer.frametime", true);
    139 
    140     // Set a limit to warn about skipped frames.
    141     // Skipped frames imply jank.
    142     private static final int SKIPPED_FRAME_WARNING_LIMIT = SystemProperties.getInt(
    143             "debug.choreographer.skipwarning", 30);
    144 
    145     private static final int MSG_DO_FRAME = 0;
    146     private static final int MSG_DO_SCHEDULE_VSYNC = 1;
    147     private static final int MSG_DO_SCHEDULE_CALLBACK = 2;
    148 
    149     // All frame callbacks posted by applications have this token.
    150     private static final Object FRAME_CALLBACK_TOKEN = new Object() {
    151         public String toString() { return "FRAME_CALLBACK_TOKEN"; }
    152     };
    153 
    154     private final Object mLock = new Object();
    155 
    156     private final Looper mLooper;
    157     private final FrameHandler mHandler;
    158 
    159     // The display event receiver can only be accessed by the looper thread to which
    160     // it is attached.  We take care to ensure that we post message to the looper
    161     // if appropriate when interacting with the display event receiver.
    162     private final FrameDisplayEventReceiver mDisplayEventReceiver;
    163 
    164     private CallbackRecord mCallbackPool;
    165 
    166     private final CallbackQueue[] mCallbackQueues;
    167 
    168     private boolean mFrameScheduled;
    169     private boolean mCallbacksRunning;
    170     private long mLastFrameTimeNanos;
    171     private long mFrameIntervalNanos;
    172     private boolean mDebugPrintNextFrameTimeDelta;
    173     private int mFPSDivisor = 1;
    174 
    175     /**
    176      * Contains information about the current frame for jank-tracking,
    177      * mainly timings of key events along with a bit of metadata about
    178      * view tree state
    179      *
    180      * TODO: Is there a better home for this? Currently Choreographer
    181      * is the only one with CALLBACK_ANIMATION start time, hence why this
    182      * resides here.
    183      *
    184      * @hide
    185      */
    186     FrameInfo mFrameInfo = new FrameInfo();
    187 
    188     /**
    189      * Must be kept in sync with CALLBACK_* ints below, used to index into this array.
    190      * @hide
    191      */
    192     private static final String[] CALLBACK_TRACE_TITLES = {
    193             "input", "animation", "traversal", "commit"
    194     };
    195 
    196     /**
    197      * Callback type: Input callback.  Runs first.
    198      * @hide
    199      */
    200     public static final int CALLBACK_INPUT = 0;
    201 
    202     /**
    203      * Callback type: Animation callback.  Runs before traversals.
    204      * @hide
    205      */
    206     @TestApi
    207     public static final int CALLBACK_ANIMATION = 1;
    208 
    209     /**
    210      * Callback type: Traversal callback.  Handles layout and draw.  Runs
    211      * after all other asynchronous messages have been handled.
    212      * @hide
    213      */
    214     public static final int CALLBACK_TRAVERSAL = 2;
    215 
    216     /**
    217      * Callback type: Commit callback.  Handles post-draw operations for the frame.
    218      * Runs after traversal completes.  The {@link #getFrameTime() frame time} reported
    219      * during this callback may be updated to reflect delays that occurred while
    220      * traversals were in progress in case heavy layout operations caused some frames
    221      * to be skipped.  The frame time reported during this callback provides a better
    222      * estimate of the start time of the frame in which animations (and other updates
    223      * to the view hierarchy state) actually took effect.
    224      * @hide
    225      */
    226     public static final int CALLBACK_COMMIT = 3;
    227 
    228     private static final int CALLBACK_LAST = CALLBACK_COMMIT;
    229 
    230     private Choreographer(Looper looper, int vsyncSource) {
    231         mLooper = looper;
    232         mHandler = new FrameHandler(looper);
    233         mDisplayEventReceiver = USE_VSYNC
    234                 ? new FrameDisplayEventReceiver(looper, vsyncSource)
    235                 : null;
    236         mLastFrameTimeNanos = Long.MIN_VALUE;
    237 
    238         mFrameIntervalNanos = (long)(1000000000 / getRefreshRate());
    239 
    240         mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1];
    241         for (int i = 0; i <= CALLBACK_LAST; i++) {
    242             mCallbackQueues[i] = new CallbackQueue();
    243         }
    244         // b/68769804: For low FPS experiments.
    245         setFPSDivisor(SystemProperties.getInt(ThreadedRenderer.DEBUG_FPS_DIVISOR, 1));
    246     }
    247 
    248     private static float getRefreshRate() {
    249         DisplayInfo di = DisplayManagerGlobal.getInstance().getDisplayInfo(
    250                 Display.DEFAULT_DISPLAY);
    251         return di.getMode().getRefreshRate();
    252     }
    253 
    254     /**
    255      * Gets the choreographer for the calling thread.  Must be called from
    256      * a thread that already has a {@link android.os.Looper} associated with it.
    257      *
    258      * @return The choreographer for this thread.
    259      * @throws IllegalStateException if the thread does not have a looper.
    260      */
    261     public static Choreographer getInstance() {
    262         return sThreadInstance.get();
    263     }
    264 
    265     /**
    266      * @hide
    267      */
    268     public static Choreographer getSfInstance() {
    269         return sSfThreadInstance.get();
    270     }
    271 
    272     /**
    273      * @return The Choreographer of the main thread, if it exists, or {@code null} otherwise.
    274      * @hide
    275      */
    276     public static Choreographer getMainThreadInstance() {
    277         return mMainInstance;
    278     }
    279 
    280     /** Destroys the calling thread's choreographer
    281      * @hide
    282      */
    283     public static void releaseInstance() {
    284         Choreographer old = sThreadInstance.get();
    285         sThreadInstance.remove();
    286         old.dispose();
    287     }
    288 
    289     private void dispose() {
    290         mDisplayEventReceiver.dispose();
    291     }
    292 
    293     /**
    294      * The amount of time, in milliseconds, between each frame of the animation.
    295      * <p>
    296      * This is a requested time that the animation will attempt to honor, but the actual delay
    297      * between frames may be different, depending on system load and capabilities. This is a static
    298      * function because the same delay will be applied to all animations, since they are all
    299      * run off of a single timing loop.
    300      * </p><p>
    301      * The frame delay may be ignored when the animation system uses an external timing
    302      * source, such as the display refresh rate (vsync), to govern animations.
    303      * </p>
    304      *
    305      * @return the requested time between frames, in milliseconds
    306      * @hide
    307      */
    308     @TestApi
    309     public static long getFrameDelay() {
    310         return sFrameDelay;
    311     }
    312 
    313     /**
    314      * The amount of time, in milliseconds, between each frame of the animation.
    315      * <p>
    316      * This is a requested time that the animation will attempt to honor, but the actual delay
    317      * between frames may be different, depending on system load and capabilities. This is a static
    318      * function because the same delay will be applied to all animations, since they are all
    319      * run off of a single timing loop.
    320      * </p><p>
    321      * The frame delay may be ignored when the animation system uses an external timing
    322      * source, such as the display refresh rate (vsync), to govern animations.
    323      * </p>
    324      *
    325      * @param frameDelay the requested time between frames, in milliseconds
    326      * @hide
    327      */
    328     @TestApi
    329     public static void setFrameDelay(long frameDelay) {
    330         sFrameDelay = frameDelay;
    331     }
    332 
    333     /**
    334      * Subtracts typical frame delay time from a delay interval in milliseconds.
    335      * <p>
    336      * This method can be used to compensate for animation delay times that have baked
    337      * in assumptions about the frame delay.  For example, it's quite common for code to
    338      * assume a 60Hz frame time and bake in a 16ms delay.  When we call
    339      * {@link #postAnimationCallbackDelayed} we want to know how long to wait before
    340      * posting the animation callback but let the animation timer take care of the remaining
    341      * frame delay time.
    342      * </p><p>
    343      * This method is somewhat conservative about how much of the frame delay it
    344      * subtracts.  It uses the same value returned by {@link #getFrameDelay} which by
    345      * default is 10ms even though many parts of the system assume 16ms.  Consequently,
    346      * we might still wait 6ms before posting an animation callback that we want to run
    347      * on the next frame, but this is much better than waiting a whole 16ms and likely
    348      * missing the deadline.
    349      * </p>
    350      *
    351      * @param delayMillis The original delay time including an assumed frame delay.
    352      * @return The adjusted delay time with the assumed frame delay subtracted out.
    353      * @hide
    354      */
    355     public static long subtractFrameDelay(long delayMillis) {
    356         final long frameDelay = sFrameDelay;
    357         return delayMillis <= frameDelay ? 0 : delayMillis - frameDelay;
    358     }
    359 
    360     /**
    361      * @return The refresh rate as the nanoseconds between frames
    362      * @hide
    363      */
    364     public long getFrameIntervalNanos() {
    365         return mFrameIntervalNanos;
    366     }
    367 
    368     void dump(String prefix, PrintWriter writer) {
    369         String innerPrefix = prefix + "  ";
    370         writer.print(prefix); writer.println("Choreographer:");
    371         writer.print(innerPrefix); writer.print("mFrameScheduled=");
    372                 writer.println(mFrameScheduled);
    373         writer.print(innerPrefix); writer.print("mLastFrameTime=");
    374                 writer.println(TimeUtils.formatUptime(mLastFrameTimeNanos / 1000000));
    375     }
    376 
    377     /**
    378      * Posts a callback to run on the next frame.
    379      * <p>
    380      * The callback runs once then is automatically removed.
    381      * </p>
    382      *
    383      * @param callbackType The callback type.
    384      * @param action The callback action to run during the next frame.
    385      * @param token The callback token, or null if none.
    386      *
    387      * @see #removeCallbacks
    388      * @hide
    389      */
    390     @TestApi
    391     public void postCallback(int callbackType, Runnable action, Object token) {
    392         postCallbackDelayed(callbackType, action, token, 0);
    393     }
    394 
    395     /**
    396      * Posts a callback to run on the next frame after the specified delay.
    397      * <p>
    398      * The callback runs once then is automatically removed.
    399      * </p>
    400      *
    401      * @param callbackType The callback type.
    402      * @param action The callback action to run during the next frame after the specified delay.
    403      * @param token The callback token, or null if none.
    404      * @param delayMillis The delay time in milliseconds.
    405      *
    406      * @see #removeCallback
    407      * @hide
    408      */
    409     @TestApi
    410     public void postCallbackDelayed(int callbackType,
    411             Runnable action, Object token, long delayMillis) {
    412         if (action == null) {
    413             throw new IllegalArgumentException("action must not be null");
    414         }
    415         if (callbackType < 0 || callbackType > CALLBACK_LAST) {
    416             throw new IllegalArgumentException("callbackType is invalid");
    417         }
    418 
    419         postCallbackDelayedInternal(callbackType, action, token, delayMillis);
    420     }
    421 
    422     private void postCallbackDelayedInternal(int callbackType,
    423             Object action, Object token, long delayMillis) {
    424         if (DEBUG_FRAMES) {
    425             Log.d(TAG, "PostCallback: type=" + callbackType
    426                     + ", action=" + action + ", token=" + token
    427                     + ", delayMillis=" + delayMillis);
    428         }
    429 
    430         synchronized (mLock) {
    431             final long now = SystemClock.uptimeMillis();
    432             final long dueTime = now + delayMillis;
    433             mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
    434 
    435             if (dueTime <= now) {
    436                 scheduleFrameLocked(now);
    437             } else {
    438                 Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
    439                 msg.arg1 = callbackType;
    440                 msg.setAsynchronous(true);
    441                 mHandler.sendMessageAtTime(msg, dueTime);
    442             }
    443         }
    444     }
    445 
    446     /**
    447      * Removes callbacks that have the specified action and token.
    448      *
    449      * @param callbackType The callback type.
    450      * @param action The action property of the callbacks to remove, or null to remove
    451      * callbacks with any action.
    452      * @param token The token property of the callbacks to remove, or null to remove
    453      * callbacks with any token.
    454      *
    455      * @see #postCallback
    456      * @see #postCallbackDelayed
    457      * @hide
    458      */
    459     @TestApi
    460     public void removeCallbacks(int callbackType, Runnable action, Object token) {
    461         if (callbackType < 0 || callbackType > CALLBACK_LAST) {
    462             throw new IllegalArgumentException("callbackType is invalid");
    463         }
    464 
    465         removeCallbacksInternal(callbackType, action, token);
    466     }
    467 
    468     private void removeCallbacksInternal(int callbackType, Object action, Object token) {
    469         if (DEBUG_FRAMES) {
    470             Log.d(TAG, "RemoveCallbacks: type=" + callbackType
    471                     + ", action=" + action + ", token=" + token);
    472         }
    473 
    474         synchronized (mLock) {
    475             mCallbackQueues[callbackType].removeCallbacksLocked(action, token);
    476             if (action != null && token == null) {
    477                 mHandler.removeMessages(MSG_DO_SCHEDULE_CALLBACK, action);
    478             }
    479         }
    480     }
    481 
    482     /**
    483      * Posts a frame callback to run on the next frame.
    484      * <p>
    485      * The callback runs once then is automatically removed.
    486      * </p>
    487      *
    488      * @param callback The frame callback to run during the next frame.
    489      *
    490      * @see #postFrameCallbackDelayed
    491      * @see #removeFrameCallback
    492      */
    493     public void postFrameCallback(FrameCallback callback) {
    494         postFrameCallbackDelayed(callback, 0);
    495     }
    496 
    497     /**
    498      * Posts a frame callback to run on the next frame after the specified delay.
    499      * <p>
    500      * The callback runs once then is automatically removed.
    501      * </p>
    502      *
    503      * @param callback The frame callback to run during the next frame.
    504      * @param delayMillis The delay time in milliseconds.
    505      *
    506      * @see #postFrameCallback
    507      * @see #removeFrameCallback
    508      */
    509     public void postFrameCallbackDelayed(FrameCallback callback, long delayMillis) {
    510         if (callback == null) {
    511             throw new IllegalArgumentException("callback must not be null");
    512         }
    513 
    514         postCallbackDelayedInternal(CALLBACK_ANIMATION,
    515                 callback, FRAME_CALLBACK_TOKEN, delayMillis);
    516     }
    517 
    518     /**
    519      * Removes a previously posted frame callback.
    520      *
    521      * @param callback The frame callback to remove.
    522      *
    523      * @see #postFrameCallback
    524      * @see #postFrameCallbackDelayed
    525      */
    526     public void removeFrameCallback(FrameCallback callback) {
    527         if (callback == null) {
    528             throw new IllegalArgumentException("callback must not be null");
    529         }
    530 
    531         removeCallbacksInternal(CALLBACK_ANIMATION, callback, FRAME_CALLBACK_TOKEN);
    532     }
    533 
    534     /**
    535      * Gets the time when the current frame started.
    536      * <p>
    537      * This method provides the time in milliseconds when the frame started being rendered.
    538      * The frame time provides a stable time base for synchronizing animations
    539      * and drawing.  It should be used instead of {@link SystemClock#uptimeMillis()}
    540      * or {@link System#nanoTime()} for animations and drawing in the UI.  Using the frame
    541      * time helps to reduce inter-frame jitter because the frame time is fixed at the time
    542      * the frame was scheduled to start, regardless of when the animations or drawing
    543      * callback actually runs.  All callbacks that run as part of rendering a frame will
    544      * observe the same frame time so using the frame time also helps to synchronize effects
    545      * that are performed by different callbacks.
    546      * </p><p>
    547      * Please note that the framework already takes care to process animations and
    548      * drawing using the frame time as a stable time base.  Most applications should
    549      * not need to use the frame time information directly.
    550      * </p><p>
    551      * This method should only be called from within a callback.
    552      * </p>
    553      *
    554      * @return The frame start time, in the {@link SystemClock#uptimeMillis()} time base.
    555      *
    556      * @throws IllegalStateException if no frame is in progress.
    557      * @hide
    558      */
    559     public long getFrameTime() {
    560         return getFrameTimeNanos() / TimeUtils.NANOS_PER_MS;
    561     }
    562 
    563     /**
    564      * Same as {@link #getFrameTime()} but with nanosecond precision.
    565      *
    566      * @return The frame start time, in the {@link System#nanoTime()} time base.
    567      *
    568      * @throws IllegalStateException if no frame is in progress.
    569      * @hide
    570      */
    571     public long getFrameTimeNanos() {
    572         synchronized (mLock) {
    573             if (!mCallbacksRunning) {
    574                 throw new IllegalStateException("This method must only be called as "
    575                         + "part of a callback while a frame is in progress.");
    576             }
    577             return USE_FRAME_TIME ? mLastFrameTimeNanos : System.nanoTime();
    578         }
    579     }
    580 
    581     /**
    582      * Like {@link #getLastFrameTimeNanos}, but always returns the last frame time, not matter
    583      * whether callbacks are currently running.
    584      * @return The frame start time of the last frame, in the {@link System#nanoTime()} time base.
    585      * @hide
    586      */
    587     public long getLastFrameTimeNanos() {
    588         synchronized (mLock) {
    589             return USE_FRAME_TIME ? mLastFrameTimeNanos : System.nanoTime();
    590         }
    591     }
    592 
    593     private void scheduleFrameLocked(long now) {
    594         if (!mFrameScheduled) {
    595             mFrameScheduled = true;
    596             if (USE_VSYNC) {
    597                 if (DEBUG_FRAMES) {
    598                     Log.d(TAG, "Scheduling next frame on vsync.");
    599                 }
    600 
    601                 // If running on the Looper thread, then schedule the vsync immediately,
    602                 // otherwise post a message to schedule the vsync from the UI thread
    603                 // as soon as possible.
    604                 if (isRunningOnLooperThreadLocked()) {
    605                     scheduleVsyncLocked();
    606                 } else {
    607                     Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
    608                     msg.setAsynchronous(true);
    609                     mHandler.sendMessageAtFrontOfQueue(msg);
    610                 }
    611             } else {
    612                 final long nextFrameTime = Math.max(
    613                         mLastFrameTimeNanos / TimeUtils.NANOS_PER_MS + sFrameDelay, now);
    614                 if (DEBUG_FRAMES) {
    615                     Log.d(TAG, "Scheduling next frame in " + (nextFrameTime - now) + " ms.");
    616                 }
    617                 Message msg = mHandler.obtainMessage(MSG_DO_FRAME);
    618                 msg.setAsynchronous(true);
    619                 mHandler.sendMessageAtTime(msg, nextFrameTime);
    620             }
    621         }
    622     }
    623 
    624     void setFPSDivisor(int divisor) {
    625         if (divisor <= 0) divisor = 1;
    626         mFPSDivisor = divisor;
    627         ThreadedRenderer.setFPSDivisor(divisor);
    628     }
    629 
    630     void doFrame(long frameTimeNanos, int frame) {
    631         final long startNanos;
    632         synchronized (mLock) {
    633             if (!mFrameScheduled) {
    634                 return; // no work to do
    635             }
    636 
    637             if (DEBUG_JANK && mDebugPrintNextFrameTimeDelta) {
    638                 mDebugPrintNextFrameTimeDelta = false;
    639                 Log.d(TAG, "Frame time delta: "
    640                         + ((frameTimeNanos - mLastFrameTimeNanos) * 0.000001f) + " ms");
    641             }
    642 
    643             long intendedFrameTimeNanos = frameTimeNanos;
    644             startNanos = System.nanoTime();
    645             final long jitterNanos = startNanos - frameTimeNanos;
    646             if (jitterNanos >= mFrameIntervalNanos) {
    647                 final long skippedFrames = jitterNanos / mFrameIntervalNanos;
    648                 if (skippedFrames >= SKIPPED_FRAME_WARNING_LIMIT) {
    649                     Log.i(TAG, "Skipped " + skippedFrames + " frames!  "
    650                             + "The application may be doing too much work on its main thread.");
    651                 }
    652                 final long lastFrameOffset = jitterNanos % mFrameIntervalNanos;
    653                 if (DEBUG_JANK) {
    654                     Log.d(TAG, "Missed vsync by " + (jitterNanos * 0.000001f) + " ms "
    655                             + "which is more than the frame interval of "
    656                             + (mFrameIntervalNanos * 0.000001f) + " ms!  "
    657                             + "Skipping " + skippedFrames + " frames and setting frame "
    658                             + "time to " + (lastFrameOffset * 0.000001f) + " ms in the past.");
    659                 }
    660                 frameTimeNanos = startNanos - lastFrameOffset;
    661             }
    662 
    663             if (frameTimeNanos < mLastFrameTimeNanos) {
    664                 if (DEBUG_JANK) {
    665                     Log.d(TAG, "Frame time appears to be going backwards.  May be due to a "
    666                             + "previously skipped frame.  Waiting for next vsync.");
    667                 }
    668                 scheduleVsyncLocked();
    669                 return;
    670             }
    671 
    672             if (mFPSDivisor > 1) {
    673                 long timeSinceVsync = frameTimeNanos - mLastFrameTimeNanos;
    674                 if (timeSinceVsync < (mFrameIntervalNanos * mFPSDivisor) && timeSinceVsync > 0) {
    675                     scheduleVsyncLocked();
    676                     return;
    677                 }
    678             }
    679 
    680             mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos);
    681             mFrameScheduled = false;
    682             mLastFrameTimeNanos = frameTimeNanos;
    683         }
    684 
    685         try {
    686             Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#doFrame");
    687             AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS);
    688 
    689             mFrameInfo.markInputHandlingStart();
    690             doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
    691 
    692             mFrameInfo.markAnimationsStart();
    693             doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
    694 
    695             mFrameInfo.markPerformTraversalsStart();
    696             doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
    697 
    698             doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
    699         } finally {
    700             AnimationUtils.unlockAnimationClock();
    701             Trace.traceEnd(Trace.TRACE_TAG_VIEW);
    702         }
    703 
    704         if (DEBUG_FRAMES) {
    705             final long endNanos = System.nanoTime();
    706             Log.d(TAG, "Frame " + frame + ": Finished, took "
    707                     + (endNanos - startNanos) * 0.000001f + " ms, latency "
    708                     + (startNanos - frameTimeNanos) * 0.000001f + " ms.");
    709         }
    710     }
    711 
    712     void doCallbacks(int callbackType, long frameTimeNanos) {
    713         CallbackRecord callbacks;
    714         synchronized (mLock) {
    715             // We use "now" to determine when callbacks become due because it's possible
    716             // for earlier processing phases in a frame to post callbacks that should run
    717             // in a following phase, such as an input event that causes an animation to start.
    718             final long now = System.nanoTime();
    719             callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(
    720                     now / TimeUtils.NANOS_PER_MS);
    721             if (callbacks == null) {
    722                 return;
    723             }
    724             mCallbacksRunning = true;
    725 
    726             // Update the frame time if necessary when committing the frame.
    727             // We only update the frame time if we are more than 2 frames late reaching
    728             // the commit phase.  This ensures that the frame time which is observed by the
    729             // callbacks will always increase from one frame to the next and never repeat.
    730             // We never want the next frame's starting frame time to end up being less than
    731             // or equal to the previous frame's commit frame time.  Keep in mind that the
    732             // next frame has most likely already been scheduled by now so we play it
    733             // safe by ensuring the commit time is always at least one frame behind.
    734             if (callbackType == Choreographer.CALLBACK_COMMIT) {
    735                 final long jitterNanos = now - frameTimeNanos;
    736                 Trace.traceCounter(Trace.TRACE_TAG_VIEW, "jitterNanos", (int) jitterNanos);
    737                 if (jitterNanos >= 2 * mFrameIntervalNanos) {
    738                     final long lastFrameOffset = jitterNanos % mFrameIntervalNanos
    739                             + mFrameIntervalNanos;
    740                     if (DEBUG_JANK) {
    741                         Log.d(TAG, "Commit callback delayed by " + (jitterNanos * 0.000001f)
    742                                 + " ms which is more than twice the frame interval of "
    743                                 + (mFrameIntervalNanos * 0.000001f) + " ms!  "
    744                                 + "Setting frame time to " + (lastFrameOffset * 0.000001f)
    745                                 + " ms in the past.");
    746                         mDebugPrintNextFrameTimeDelta = true;
    747                     }
    748                     frameTimeNanos = now - lastFrameOffset;
    749                     mLastFrameTimeNanos = frameTimeNanos;
    750                 }
    751             }
    752         }
    753         try {
    754             Trace.traceBegin(Trace.TRACE_TAG_VIEW, CALLBACK_TRACE_TITLES[callbackType]);
    755             for (CallbackRecord c = callbacks; c != null; c = c.next) {
    756                 if (DEBUG_FRAMES) {
    757                     Log.d(TAG, "RunCallback: type=" + callbackType
    758                             + ", action=" + c.action + ", token=" + c.token
    759                             + ", latencyMillis=" + (SystemClock.uptimeMillis() - c.dueTime));
    760                 }
    761                 c.run(frameTimeNanos);
    762             }
    763         } finally {
    764             synchronized (mLock) {
    765                 mCallbacksRunning = false;
    766                 do {
    767                     final CallbackRecord next = callbacks.next;
    768                     recycleCallbackLocked(callbacks);
    769                     callbacks = next;
    770                 } while (callbacks != null);
    771             }
    772             Trace.traceEnd(Trace.TRACE_TAG_VIEW);
    773         }
    774     }
    775 
    776     void doScheduleVsync() {
    777         synchronized (mLock) {
    778             if (mFrameScheduled) {
    779                 scheduleVsyncLocked();
    780             }
    781         }
    782     }
    783 
    784     void doScheduleCallback(int callbackType) {
    785         synchronized (mLock) {
    786             if (!mFrameScheduled) {
    787                 final long now = SystemClock.uptimeMillis();
    788                 if (mCallbackQueues[callbackType].hasDueCallbacksLocked(now)) {
    789                     scheduleFrameLocked(now);
    790                 }
    791             }
    792         }
    793     }
    794 
    795     private void scheduleVsyncLocked() {
    796         mDisplayEventReceiver.scheduleVsync();
    797     }
    798 
    799     private boolean isRunningOnLooperThreadLocked() {
    800         return Looper.myLooper() == mLooper;
    801     }
    802 
    803     private CallbackRecord obtainCallbackLocked(long dueTime, Object action, Object token) {
    804         CallbackRecord callback = mCallbackPool;
    805         if (callback == null) {
    806             callback = new CallbackRecord();
    807         } else {
    808             mCallbackPool = callback.next;
    809             callback.next = null;
    810         }
    811         callback.dueTime = dueTime;
    812         callback.action = action;
    813         callback.token = token;
    814         return callback;
    815     }
    816 
    817     private void recycleCallbackLocked(CallbackRecord callback) {
    818         callback.action = null;
    819         callback.token = null;
    820         callback.next = mCallbackPool;
    821         mCallbackPool = callback;
    822     }
    823 
    824     /**
    825      * Implement this interface to receive a callback when a new display frame is
    826      * being rendered.  The callback is invoked on the {@link Looper} thread to
    827      * which the {@link Choreographer} is attached.
    828      */
    829     public interface FrameCallback {
    830         /**
    831          * Called when a new display frame is being rendered.
    832          * <p>
    833          * This method provides the time in nanoseconds when the frame started being rendered.
    834          * The frame time provides a stable time base for synchronizing animations
    835          * and drawing.  It should be used instead of {@link SystemClock#uptimeMillis()}
    836          * or {@link System#nanoTime()} for animations and drawing in the UI.  Using the frame
    837          * time helps to reduce inter-frame jitter because the frame time is fixed at the time
    838          * the frame was scheduled to start, regardless of when the animations or drawing
    839          * callback actually runs.  All callbacks that run as part of rendering a frame will
    840          * observe the same frame time so using the frame time also helps to synchronize effects
    841          * that are performed by different callbacks.
    842          * </p><p>
    843          * Please note that the framework already takes care to process animations and
    844          * drawing using the frame time as a stable time base.  Most applications should
    845          * not need to use the frame time information directly.
    846          * </p>
    847          *
    848          * @param frameTimeNanos The time in nanoseconds when the frame started being rendered,
    849          * in the {@link System#nanoTime()} timebase.  Divide this value by {@code 1000000}
    850          * to convert it to the {@link SystemClock#uptimeMillis()} time base.
    851          */
    852         public void doFrame(long frameTimeNanos);
    853     }
    854 
    855     private final class FrameHandler extends Handler {
    856         public FrameHandler(Looper looper) {
    857             super(looper);
    858         }
    859 
    860         @Override
    861         public void handleMessage(Message msg) {
    862             switch (msg.what) {
    863                 case MSG_DO_FRAME:
    864                     doFrame(System.nanoTime(), 0);
    865                     break;
    866                 case MSG_DO_SCHEDULE_VSYNC:
    867                     doScheduleVsync();
    868                     break;
    869                 case MSG_DO_SCHEDULE_CALLBACK:
    870                     doScheduleCallback(msg.arg1);
    871                     break;
    872             }
    873         }
    874     }
    875 
    876     private final class FrameDisplayEventReceiver extends DisplayEventReceiver
    877             implements Runnable {
    878         private boolean mHavePendingVsync;
    879         private long mTimestampNanos;
    880         private int mFrame;
    881 
    882         public FrameDisplayEventReceiver(Looper looper, int vsyncSource) {
    883             super(looper, vsyncSource);
    884         }
    885 
    886         @Override
    887         public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {
    888             // Ignore vsync from secondary display.
    889             // This can be problematic because the call to scheduleVsync() is a one-shot.
    890             // We need to ensure that we will still receive the vsync from the primary
    891             // display which is the one we really care about.  Ideally we should schedule
    892             // vsync for a particular display.
    893             // At this time Surface Flinger won't send us vsyncs for secondary displays
    894             // but that could change in the future so let's log a message to help us remember
    895             // that we need to fix this.
    896             if (builtInDisplayId != SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN) {
    897                 Log.d(TAG, "Received vsync from secondary display, but we don't support "
    898                         + "this case yet.  Choreographer needs a way to explicitly request "
    899                         + "vsync for a specific display to ensure it doesn't lose track "
    900                         + "of its scheduled vsync.");
    901                 scheduleVsync();
    902                 return;
    903             }
    904 
    905             // Post the vsync event to the Handler.
    906             // The idea is to prevent incoming vsync events from completely starving
    907             // the message queue.  If there are no messages in the queue with timestamps
    908             // earlier than the frame time, then the vsync event will be processed immediately.
    909             // Otherwise, messages that predate the vsync event will be handled first.
    910             long now = System.nanoTime();
    911             if (timestampNanos > now) {
    912                 Log.w(TAG, "Frame time is " + ((timestampNanos - now) * 0.000001f)
    913                         + " ms in the future!  Check that graphics HAL is generating vsync "
    914                         + "timestamps using the correct timebase.");
    915                 timestampNanos = now;
    916             }
    917 
    918             if (mHavePendingVsync) {
    919                 Log.w(TAG, "Already have a pending vsync event.  There should only be "
    920                         + "one at a time.");
    921             } else {
    922                 mHavePendingVsync = true;
    923             }
    924 
    925             mTimestampNanos = timestampNanos;
    926             mFrame = frame;
    927             Message msg = Message.obtain(mHandler, this);
    928             msg.setAsynchronous(true);
    929             mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
    930         }
    931 
    932         @Override
    933         public void run() {
    934             mHavePendingVsync = false;
    935             doFrame(mTimestampNanos, mFrame);
    936         }
    937     }
    938 
    939     private static final class CallbackRecord {
    940         public CallbackRecord next;
    941         public long dueTime;
    942         public Object action; // Runnable or FrameCallback
    943         public Object token;
    944 
    945         public void run(long frameTimeNanos) {
    946             if (token == FRAME_CALLBACK_TOKEN) {
    947                 ((FrameCallback)action).doFrame(frameTimeNanos);
    948             } else {
    949                 ((Runnable)action).run();
    950             }
    951         }
    952     }
    953 
    954     private final class CallbackQueue {
    955         private CallbackRecord mHead;
    956 
    957         public boolean hasDueCallbacksLocked(long now) {
    958             return mHead != null && mHead.dueTime <= now;
    959         }
    960 
    961         public CallbackRecord extractDueCallbacksLocked(long now) {
    962             CallbackRecord callbacks = mHead;
    963             if (callbacks == null || callbacks.dueTime > now) {
    964                 return null;
    965             }
    966 
    967             CallbackRecord last = callbacks;
    968             CallbackRecord next = last.next;
    969             while (next != null) {
    970                 if (next.dueTime > now) {
    971                     last.next = null;
    972                     break;
    973                 }
    974                 last = next;
    975                 next = next.next;
    976             }
    977             mHead = next;
    978             return callbacks;
    979         }
    980 
    981         public void addCallbackLocked(long dueTime, Object action, Object token) {
    982             CallbackRecord callback = obtainCallbackLocked(dueTime, action, token);
    983             CallbackRecord entry = mHead;
    984             if (entry == null) {
    985                 mHead = callback;
    986                 return;
    987             }
    988             if (dueTime < entry.dueTime) {
    989                 callback.next = entry;
    990                 mHead = callback;
    991                 return;
    992             }
    993             while (entry.next != null) {
    994                 if (dueTime < entry.next.dueTime) {
    995                     callback.next = entry.next;
    996                     break;
    997                 }
    998                 entry = entry.next;
    999             }
   1000             entry.next = callback;
   1001         }
   1002 
   1003         public void removeCallbacksLocked(Object action, Object token) {
   1004             CallbackRecord predecessor = null;
   1005             for (CallbackRecord callback = mHead; callback != null;) {
   1006                 final CallbackRecord next = callback.next;
   1007                 if ((action == null || callback.action == action)
   1008                         && (token == null || callback.token == token)) {
   1009                     if (predecessor != null) {
   1010                         predecessor.next = next;
   1011                     } else {
   1012                         mHead = next;
   1013                     }
   1014                     recycleCallbackLocked(callback);
   1015                 } else {
   1016                     predecessor = callback;
   1017                 }
   1018                 callback = next;
   1019             }
   1020         }
   1021     }
   1022 }
   1023