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