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