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     /** Destroys the calling thread's choreographer
    236      * @hide
    237      */
    238     public static void releaseInstance() {
    239         Choreographer old = sThreadInstance.get();
    240         sThreadInstance.remove();
    241         old.dispose();
    242     }
    243 
    244     private void dispose() {
    245         mDisplayEventReceiver.dispose();
    246     }
    247 
    248     /**
    249      * The amount of time, in milliseconds, between each frame of the animation.
    250      * <p>
    251      * This is a requested time that the animation will attempt to honor, but the actual delay
    252      * between frames may be different, depending on system load and capabilities. This is a static
    253      * function because the same delay will be applied to all animations, since they are all
    254      * run off of a single timing loop.
    255      * </p><p>
    256      * The frame delay may be ignored when the animation system uses an external timing
    257      * source, such as the display refresh rate (vsync), to govern animations.
    258      * </p>
    259      *
    260      * @return the requested time between frames, in milliseconds
    261      * @hide
    262      */
    263     public static long getFrameDelay() {
    264         return sFrameDelay;
    265     }
    266 
    267     /**
    268      * The amount of time, in milliseconds, between each frame of the animation.
    269      * <p>
    270      * This is a requested time that the animation will attempt to honor, but the actual delay
    271      * between frames may be different, depending on system load and capabilities. This is a static
    272      * function because the same delay will be applied to all animations, since they are all
    273      * run off of a single timing loop.
    274      * </p><p>
    275      * The frame delay may be ignored when the animation system uses an external timing
    276      * source, such as the display refresh rate (vsync), to govern animations.
    277      * </p>
    278      *
    279      * @param frameDelay the requested time between frames, in milliseconds
    280      * @hide
    281      */
    282     public static void setFrameDelay(long frameDelay) {
    283         sFrameDelay = frameDelay;
    284     }
    285 
    286     /**
    287      * Subtracts typical frame delay time from a delay interval in milliseconds.
    288      * <p>
    289      * This method can be used to compensate for animation delay times that have baked
    290      * in assumptions about the frame delay.  For example, it's quite common for code to
    291      * assume a 60Hz frame time and bake in a 16ms delay.  When we call
    292      * {@link #postAnimationCallbackDelayed} we want to know how long to wait before
    293      * posting the animation callback but let the animation timer take care of the remaining
    294      * frame delay time.
    295      * </p><p>
    296      * This method is somewhat conservative about how much of the frame delay it
    297      * subtracts.  It uses the same value returned by {@link #getFrameDelay} which by
    298      * default is 10ms even though many parts of the system assume 16ms.  Consequently,
    299      * we might still wait 6ms before posting an animation callback that we want to run
    300      * on the next frame, but this is much better than waiting a whole 16ms and likely
    301      * missing the deadline.
    302      * </p>
    303      *
    304      * @param delayMillis The original delay time including an assumed frame delay.
    305      * @return The adjusted delay time with the assumed frame delay subtracted out.
    306      * @hide
    307      */
    308     public static long subtractFrameDelay(long delayMillis) {
    309         final long frameDelay = sFrameDelay;
    310         return delayMillis <= frameDelay ? 0 : delayMillis - frameDelay;
    311     }
    312 
    313     /**
    314      * @return The refresh rate as the nanoseconds between frames
    315      * @hide
    316      */
    317     public long getFrameIntervalNanos() {
    318         return mFrameIntervalNanos;
    319     }
    320 
    321     void dump(String prefix, PrintWriter writer) {
    322         String innerPrefix = prefix + "  ";
    323         writer.print(prefix); writer.println("Choreographer:");
    324         writer.print(innerPrefix); writer.print("mFrameScheduled=");
    325                 writer.println(mFrameScheduled);
    326         writer.print(innerPrefix); writer.print("mLastFrameTime=");
    327                 writer.println(TimeUtils.formatUptime(mLastFrameTimeNanos / 1000000));
    328     }
    329 
    330     /**
    331      * Posts a callback to run on the next frame.
    332      * <p>
    333      * The callback runs once then is automatically removed.
    334      * </p>
    335      *
    336      * @param callbackType The callback type.
    337      * @param action The callback action to run during the next frame.
    338      * @param token The callback token, or null if none.
    339      *
    340      * @see #removeCallbacks
    341      * @hide
    342      */
    343     public void postCallback(int callbackType, Runnable action, Object token) {
    344         postCallbackDelayed(callbackType, action, token, 0);
    345     }
    346 
    347     /**
    348      * Posts a callback to run on the next frame after the specified delay.
    349      * <p>
    350      * The callback runs once then is automatically removed.
    351      * </p>
    352      *
    353      * @param callbackType The callback type.
    354      * @param action The callback action to run during the next frame after the specified delay.
    355      * @param token The callback token, or null if none.
    356      * @param delayMillis The delay time in milliseconds.
    357      *
    358      * @see #removeCallback
    359      * @hide
    360      */
    361     public void postCallbackDelayed(int callbackType,
    362             Runnable action, Object token, long delayMillis) {
    363         if (action == null) {
    364             throw new IllegalArgumentException("action must not be null");
    365         }
    366         if (callbackType < 0 || callbackType > CALLBACK_LAST) {
    367             throw new IllegalArgumentException("callbackType is invalid");
    368         }
    369 
    370         postCallbackDelayedInternal(callbackType, action, token, delayMillis);
    371     }
    372 
    373     private void postCallbackDelayedInternal(int callbackType,
    374             Object action, Object token, long delayMillis) {
    375         if (DEBUG_FRAMES) {
    376             Log.d(TAG, "PostCallback: type=" + callbackType
    377                     + ", action=" + action + ", token=" + token
    378                     + ", delayMillis=" + delayMillis);
    379         }
    380 
    381         synchronized (mLock) {
    382             final long now = SystemClock.uptimeMillis();
    383             final long dueTime = now + delayMillis;
    384             mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
    385 
    386             if (dueTime <= now) {
    387                 scheduleFrameLocked(now);
    388             } else {
    389                 Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
    390                 msg.arg1 = callbackType;
    391                 msg.setAsynchronous(true);
    392                 mHandler.sendMessageAtTime(msg, dueTime);
    393             }
    394         }
    395     }
    396 
    397     /**
    398      * Removes callbacks that have the specified action and token.
    399      *
    400      * @param callbackType The callback type.
    401      * @param action The action property of the callbacks to remove, or null to remove
    402      * callbacks with any action.
    403      * @param token The token property of the callbacks to remove, or null to remove
    404      * callbacks with any token.
    405      *
    406      * @see #postCallback
    407      * @see #postCallbackDelayed
    408      * @hide
    409      */
    410     public void removeCallbacks(int callbackType, Runnable action, Object token) {
    411         if (callbackType < 0 || callbackType > CALLBACK_LAST) {
    412             throw new IllegalArgumentException("callbackType is invalid");
    413         }
    414 
    415         removeCallbacksInternal(callbackType, action, token);
    416     }
    417 
    418     private void removeCallbacksInternal(int callbackType, Object action, Object token) {
    419         if (DEBUG_FRAMES) {
    420             Log.d(TAG, "RemoveCallbacks: type=" + callbackType
    421                     + ", action=" + action + ", token=" + token);
    422         }
    423 
    424         synchronized (mLock) {
    425             mCallbackQueues[callbackType].removeCallbacksLocked(action, token);
    426             if (action != null && token == null) {
    427                 mHandler.removeMessages(MSG_DO_SCHEDULE_CALLBACK, action);
    428             }
    429         }
    430     }
    431 
    432     /**
    433      * Posts a frame callback to run on the next frame.
    434      * <p>
    435      * The callback runs once then is automatically removed.
    436      * </p>
    437      *
    438      * @param callback The frame callback to run during the next frame.
    439      *
    440      * @see #postFrameCallbackDelayed
    441      * @see #removeFrameCallback
    442      */
    443     public void postFrameCallback(FrameCallback callback) {
    444         postFrameCallbackDelayed(callback, 0);
    445     }
    446 
    447     /**
    448      * Posts a frame callback to run on the next frame after the specified delay.
    449      * <p>
    450      * The callback runs once then is automatically removed.
    451      * </p>
    452      *
    453      * @param callback The frame callback to run during the next frame.
    454      * @param delayMillis The delay time in milliseconds.
    455      *
    456      * @see #postFrameCallback
    457      * @see #removeFrameCallback
    458      */
    459     public void postFrameCallbackDelayed(FrameCallback callback, long delayMillis) {
    460         if (callback == null) {
    461             throw new IllegalArgumentException("callback must not be null");
    462         }
    463 
    464         postCallbackDelayedInternal(CALLBACK_ANIMATION,
    465                 callback, FRAME_CALLBACK_TOKEN, delayMillis);
    466     }
    467 
    468     /**
    469      * Removes a previously posted frame callback.
    470      *
    471      * @param callback The frame callback to remove.
    472      *
    473      * @see #postFrameCallback
    474      * @see #postFrameCallbackDelayed
    475      */
    476     public void removeFrameCallback(FrameCallback callback) {
    477         if (callback == null) {
    478             throw new IllegalArgumentException("callback must not be null");
    479         }
    480 
    481         removeCallbacksInternal(CALLBACK_ANIMATION, callback, FRAME_CALLBACK_TOKEN);
    482     }
    483 
    484     /**
    485      * Gets the time when the current frame started.
    486      * <p>
    487      * This method provides the time in milliseconds when the frame started being rendered.
    488      * The frame time provides a stable time base for synchronizing animations
    489      * and drawing.  It should be used instead of {@link SystemClock#uptimeMillis()}
    490      * or {@link System#nanoTime()} for animations and drawing in the UI.  Using the frame
    491      * time helps to reduce inter-frame jitter because the frame time is fixed at the time
    492      * the frame was scheduled to start, regardless of when the animations or drawing
    493      * callback actually runs.  All callbacks that run as part of rendering a frame will
    494      * observe the same frame time so using the frame time also helps to synchronize effects
    495      * that are performed by different callbacks.
    496      * </p><p>
    497      * Please note that the framework already takes care to process animations and
    498      * drawing using the frame time as a stable time base.  Most applications should
    499      * not need to use the frame time information directly.
    500      * </p><p>
    501      * This method should only be called from within a callback.
    502      * </p>
    503      *
    504      * @return The frame start time, in the {@link SystemClock#uptimeMillis()} time base.
    505      *
    506      * @throws IllegalStateException if no frame is in progress.
    507      * @hide
    508      */
    509     public long getFrameTime() {
    510         return getFrameTimeNanos() / TimeUtils.NANOS_PER_MS;
    511     }
    512 
    513     /**
    514      * Same as {@link #getFrameTime()} but with nanosecond precision.
    515      *
    516      * @return The frame start time, in the {@link System#nanoTime()} time base.
    517      *
    518      * @throws IllegalStateException if no frame is in progress.
    519      * @hide
    520      */
    521     public long getFrameTimeNanos() {
    522         synchronized (mLock) {
    523             if (!mCallbacksRunning) {
    524                 throw new IllegalStateException("This method must only be called as "
    525                         + "part of a callback while a frame is in progress.");
    526             }
    527             return USE_FRAME_TIME ? mLastFrameTimeNanos : System.nanoTime();
    528         }
    529     }
    530 
    531     private void scheduleFrameLocked(long now) {
    532         if (!mFrameScheduled) {
    533             mFrameScheduled = true;
    534             if (USE_VSYNC) {
    535                 if (DEBUG_FRAMES) {
    536                     Log.d(TAG, "Scheduling next frame on vsync.");
    537                 }
    538 
    539                 // If running on the Looper thread, then schedule the vsync immediately,
    540                 // otherwise post a message to schedule the vsync from the UI thread
    541                 // as soon as possible.
    542                 if (isRunningOnLooperThreadLocked()) {
    543                     scheduleVsyncLocked();
    544                 } else {
    545                     Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
    546                     msg.setAsynchronous(true);
    547                     mHandler.sendMessageAtFrontOfQueue(msg);
    548                 }
    549             } else {
    550                 final long nextFrameTime = Math.max(
    551                         mLastFrameTimeNanos / TimeUtils.NANOS_PER_MS + sFrameDelay, now);
    552                 if (DEBUG_FRAMES) {
    553                     Log.d(TAG, "Scheduling next frame in " + (nextFrameTime - now) + " ms.");
    554                 }
    555                 Message msg = mHandler.obtainMessage(MSG_DO_FRAME);
    556                 msg.setAsynchronous(true);
    557                 mHandler.sendMessageAtTime(msg, nextFrameTime);
    558             }
    559         }
    560     }
    561 
    562     void doFrame(long frameTimeNanos, int frame) {
    563         final long startNanos;
    564         synchronized (mLock) {
    565             if (!mFrameScheduled) {
    566                 return; // no work to do
    567             }
    568 
    569             if (DEBUG_JANK && mDebugPrintNextFrameTimeDelta) {
    570                 mDebugPrintNextFrameTimeDelta = false;
    571                 Log.d(TAG, "Frame time delta: "
    572                         + ((frameTimeNanos - mLastFrameTimeNanos) * 0.000001f) + " ms");
    573             }
    574 
    575             long intendedFrameTimeNanos = frameTimeNanos;
    576             startNanos = System.nanoTime();
    577             final long jitterNanos = startNanos - frameTimeNanos;
    578             if (jitterNanos >= mFrameIntervalNanos) {
    579                 final long skippedFrames = jitterNanos / mFrameIntervalNanos;
    580                 if (skippedFrames >= SKIPPED_FRAME_WARNING_LIMIT) {
    581                     Log.i(TAG, "Skipped " + skippedFrames + " frames!  "
    582                             + "The application may be doing too much work on its main thread.");
    583                 }
    584                 final long lastFrameOffset = jitterNanos % mFrameIntervalNanos;
    585                 if (DEBUG_JANK) {
    586                     Log.d(TAG, "Missed vsync by " + (jitterNanos * 0.000001f) + " ms "
    587                             + "which is more than the frame interval of "
    588                             + (mFrameIntervalNanos * 0.000001f) + " ms!  "
    589                             + "Skipping " + skippedFrames + " frames and setting frame "
    590                             + "time to " + (lastFrameOffset * 0.000001f) + " ms in the past.");
    591                 }
    592                 frameTimeNanos = startNanos - lastFrameOffset;
    593             }
    594 
    595             if (frameTimeNanos < mLastFrameTimeNanos) {
    596                 if (DEBUG_JANK) {
    597                     Log.d(TAG, "Frame time appears to be going backwards.  May be due to a "
    598                             + "previously skipped frame.  Waiting for next vsync.");
    599                 }
    600                 scheduleVsyncLocked();
    601                 return;
    602             }
    603 
    604             mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos);
    605             mFrameScheduled = false;
    606             mLastFrameTimeNanos = frameTimeNanos;
    607         }
    608 
    609         try {
    610             Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#doFrame");
    611 
    612             mFrameInfo.markInputHandlingStart();
    613             doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
    614 
    615             mFrameInfo.markAnimationsStart();
    616             doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
    617 
    618             mFrameInfo.markPerformTraversalsStart();
    619             doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
    620 
    621             doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
    622         } finally {
    623             Trace.traceEnd(Trace.TRACE_TAG_VIEW);
    624         }
    625 
    626         if (DEBUG_FRAMES) {
    627             final long endNanos = System.nanoTime();
    628             Log.d(TAG, "Frame " + frame + ": Finished, took "
    629                     + (endNanos - startNanos) * 0.000001f + " ms, latency "
    630                     + (startNanos - frameTimeNanos) * 0.000001f + " ms.");
    631         }
    632     }
    633 
    634     void doCallbacks(int callbackType, long frameTimeNanos) {
    635         CallbackRecord callbacks;
    636         synchronized (mLock) {
    637             // We use "now" to determine when callbacks become due because it's possible
    638             // for earlier processing phases in a frame to post callbacks that should run
    639             // in a following phase, such as an input event that causes an animation to start.
    640             final long now = System.nanoTime();
    641             callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(
    642                     now / TimeUtils.NANOS_PER_MS);
    643             if (callbacks == null) {
    644                 return;
    645             }
    646             mCallbacksRunning = true;
    647 
    648             // Update the frame time if necessary when committing the frame.
    649             // We only update the frame time if we are more than 2 frames late reaching
    650             // the commit phase.  This ensures that the frame time which is observed by the
    651             // callbacks will always increase from one frame to the next and never repeat.
    652             // We never want the next frame's starting frame time to end up being less than
    653             // or equal to the previous frame's commit frame time.  Keep in mind that the
    654             // next frame has most likely already been scheduled by now so we play it
    655             // safe by ensuring the commit time is always at least one frame behind.
    656             if (callbackType == Choreographer.CALLBACK_COMMIT) {
    657                 final long jitterNanos = now - frameTimeNanos;
    658                 Trace.traceCounter(Trace.TRACE_TAG_VIEW, "jitterNanos", (int) jitterNanos);
    659                 if (jitterNanos >= 2 * mFrameIntervalNanos) {
    660                     final long lastFrameOffset = jitterNanos % mFrameIntervalNanos
    661                             + mFrameIntervalNanos;
    662                     if (DEBUG_JANK) {
    663                         Log.d(TAG, "Commit callback delayed by " + (jitterNanos * 0.000001f)
    664                                 + " ms which is more than twice the frame interval of "
    665                                 + (mFrameIntervalNanos * 0.000001f) + " ms!  "
    666                                 + "Setting frame time to " + (lastFrameOffset * 0.000001f)
    667                                 + " ms in the past.");
    668                         mDebugPrintNextFrameTimeDelta = true;
    669                     }
    670                     frameTimeNanos = now - lastFrameOffset;
    671                     mLastFrameTimeNanos = frameTimeNanos;
    672                 }
    673             }
    674         }
    675         try {
    676             Trace.traceBegin(Trace.TRACE_TAG_VIEW, CALLBACK_TRACE_TITLES[callbackType]);
    677             for (CallbackRecord c = callbacks; c != null; c = c.next) {
    678                 if (DEBUG_FRAMES) {
    679                     Log.d(TAG, "RunCallback: type=" + callbackType
    680                             + ", action=" + c.action + ", token=" + c.token
    681                             + ", latencyMillis=" + (SystemClock.uptimeMillis() - c.dueTime));
    682                 }
    683                 c.run(frameTimeNanos);
    684             }
    685         } finally {
    686             synchronized (mLock) {
    687                 mCallbacksRunning = false;
    688                 do {
    689                     final CallbackRecord next = callbacks.next;
    690                     recycleCallbackLocked(callbacks);
    691                     callbacks = next;
    692                 } while (callbacks != null);
    693             }
    694             Trace.traceEnd(Trace.TRACE_TAG_VIEW);
    695         }
    696     }
    697 
    698     void doScheduleVsync() {
    699         synchronized (mLock) {
    700             if (mFrameScheduled) {
    701                 scheduleVsyncLocked();
    702             }
    703         }
    704     }
    705 
    706     void doScheduleCallback(int callbackType) {
    707         synchronized (mLock) {
    708             if (!mFrameScheduled) {
    709                 final long now = SystemClock.uptimeMillis();
    710                 if (mCallbackQueues[callbackType].hasDueCallbacksLocked(now)) {
    711                     scheduleFrameLocked(now);
    712                 }
    713             }
    714         }
    715     }
    716 
    717     private void scheduleVsyncLocked() {
    718         mDisplayEventReceiver.scheduleVsync();
    719     }
    720 
    721     private boolean isRunningOnLooperThreadLocked() {
    722         return Looper.myLooper() == mLooper;
    723     }
    724 
    725     private CallbackRecord obtainCallbackLocked(long dueTime, Object action, Object token) {
    726         CallbackRecord callback = mCallbackPool;
    727         if (callback == null) {
    728             callback = new CallbackRecord();
    729         } else {
    730             mCallbackPool = callback.next;
    731             callback.next = null;
    732         }
    733         callback.dueTime = dueTime;
    734         callback.action = action;
    735         callback.token = token;
    736         return callback;
    737     }
    738 
    739     private void recycleCallbackLocked(CallbackRecord callback) {
    740         callback.action = null;
    741         callback.token = null;
    742         callback.next = mCallbackPool;
    743         mCallbackPool = callback;
    744     }
    745 
    746     /**
    747      * Implement this interface to receive a callback when a new display frame is
    748      * being rendered.  The callback is invoked on the {@link Looper} thread to
    749      * which the {@link Choreographer} is attached.
    750      */
    751     public interface FrameCallback {
    752         /**
    753          * Called when a new display frame is being rendered.
    754          * <p>
    755          * This method provides the time in nanoseconds when the frame started being rendered.
    756          * The frame time provides a stable time base for synchronizing animations
    757          * and drawing.  It should be used instead of {@link SystemClock#uptimeMillis()}
    758          * or {@link System#nanoTime()} for animations and drawing in the UI.  Using the frame
    759          * time helps to reduce inter-frame jitter because the frame time is fixed at the time
    760          * the frame was scheduled to start, regardless of when the animations or drawing
    761          * callback actually runs.  All callbacks that run as part of rendering a frame will
    762          * observe the same frame time so using the frame time also helps to synchronize effects
    763          * that are performed by different callbacks.
    764          * </p><p>
    765          * Please note that the framework already takes care to process animations and
    766          * drawing using the frame time as a stable time base.  Most applications should
    767          * not need to use the frame time information directly.
    768          * </p>
    769          *
    770          * @param frameTimeNanos The time in nanoseconds when the frame started being rendered,
    771          * in the {@link System#nanoTime()} timebase.  Divide this value by {@code 1000000}
    772          * to convert it to the {@link SystemClock#uptimeMillis()} time base.
    773          */
    774         public void doFrame(long frameTimeNanos);
    775     }
    776 
    777     private final class FrameHandler extends Handler {
    778         public FrameHandler(Looper looper) {
    779             super(looper);
    780         }
    781 
    782         @Override
    783         public void handleMessage(Message msg) {
    784             switch (msg.what) {
    785                 case MSG_DO_FRAME:
    786                     doFrame(System.nanoTime(), 0);
    787                     break;
    788                 case MSG_DO_SCHEDULE_VSYNC:
    789                     doScheduleVsync();
    790                     break;
    791                 case MSG_DO_SCHEDULE_CALLBACK:
    792                     doScheduleCallback(msg.arg1);
    793                     break;
    794             }
    795         }
    796     }
    797 
    798     private final class FrameDisplayEventReceiver extends DisplayEventReceiver
    799             implements Runnable {
    800         private boolean mHavePendingVsync;
    801         private long mTimestampNanos;
    802         private int mFrame;
    803 
    804         public FrameDisplayEventReceiver(Looper looper) {
    805             super(looper);
    806         }
    807 
    808         @Override
    809         public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {
    810             // Ignore vsync from secondary display.
    811             // This can be problematic because the call to scheduleVsync() is a one-shot.
    812             // We need to ensure that we will still receive the vsync from the primary
    813             // display which is the one we really care about.  Ideally we should schedule
    814             // vsync for a particular display.
    815             // At this time Surface Flinger won't send us vsyncs for secondary displays
    816             // but that could change in the future so let's log a message to help us remember
    817             // that we need to fix this.
    818             if (builtInDisplayId != SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN) {
    819                 Log.d(TAG, "Received vsync from secondary display, but we don't support "
    820                         + "this case yet.  Choreographer needs a way to explicitly request "
    821                         + "vsync for a specific display to ensure it doesn't lose track "
    822                         + "of its scheduled vsync.");
    823                 scheduleVsync();
    824                 return;
    825             }
    826 
    827             // Post the vsync event to the Handler.
    828             // The idea is to prevent incoming vsync events from completely starving
    829             // the message queue.  If there are no messages in the queue with timestamps
    830             // earlier than the frame time, then the vsync event will be processed immediately.
    831             // Otherwise, messages that predate the vsync event will be handled first.
    832             long now = System.nanoTime();
    833             if (timestampNanos > now) {
    834                 Log.w(TAG, "Frame time is " + ((timestampNanos - now) * 0.000001f)
    835                         + " ms in the future!  Check that graphics HAL is generating vsync "
    836                         + "timestamps using the correct timebase.");
    837                 timestampNanos = now;
    838             }
    839 
    840             if (mHavePendingVsync) {
    841                 Log.w(TAG, "Already have a pending vsync event.  There should only be "
    842                         + "one at a time.");
    843             } else {
    844                 mHavePendingVsync = true;
    845             }
    846 
    847             mTimestampNanos = timestampNanos;
    848             mFrame = frame;
    849             Message msg = Message.obtain(mHandler, this);
    850             msg.setAsynchronous(true);
    851             mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
    852         }
    853 
    854         @Override
    855         public void run() {
    856             mHavePendingVsync = false;
    857             doFrame(mTimestampNanos, mFrame);
    858         }
    859     }
    860 
    861     private static final class CallbackRecord {
    862         public CallbackRecord next;
    863         public long dueTime;
    864         public Object action; // Runnable or FrameCallback
    865         public Object token;
    866 
    867         public void run(long frameTimeNanos) {
    868             if (token == FRAME_CALLBACK_TOKEN) {
    869                 ((FrameCallback)action).doFrame(frameTimeNanos);
    870             } else {
    871                 ((Runnable)action).run();
    872             }
    873         }
    874     }
    875 
    876     private final class CallbackQueue {
    877         private CallbackRecord mHead;
    878 
    879         public boolean hasDueCallbacksLocked(long now) {
    880             return mHead != null && mHead.dueTime <= now;
    881         }
    882 
    883         public CallbackRecord extractDueCallbacksLocked(long now) {
    884             CallbackRecord callbacks = mHead;
    885             if (callbacks == null || callbacks.dueTime > now) {
    886                 return null;
    887             }
    888 
    889             CallbackRecord last = callbacks;
    890             CallbackRecord next = last.next;
    891             while (next != null) {
    892                 if (next.dueTime > now) {
    893                     last.next = null;
    894                     break;
    895                 }
    896                 last = next;
    897                 next = next.next;
    898             }
    899             mHead = next;
    900             return callbacks;
    901         }
    902 
    903         public void addCallbackLocked(long dueTime, Object action, Object token) {
    904             CallbackRecord callback = obtainCallbackLocked(dueTime, action, token);
    905             CallbackRecord entry = mHead;
    906             if (entry == null) {
    907                 mHead = callback;
    908                 return;
    909             }
    910             if (dueTime < entry.dueTime) {
    911                 callback.next = entry;
    912                 mHead = callback;
    913                 return;
    914             }
    915             while (entry.next != null) {
    916                 if (dueTime < entry.next.dueTime) {
    917                     callback.next = entry.next;
    918                     break;
    919                 }
    920                 entry = entry.next;
    921             }
    922             entry.next = callback;
    923         }
    924 
    925         public void removeCallbacksLocked(Object action, Object token) {
    926             CallbackRecord predecessor = null;
    927             for (CallbackRecord callback = mHead; callback != null;) {
    928                 final CallbackRecord next = callback.next;
    929                 if ((action == null || callback.action == action)
    930                         && (token == null || callback.token == token)) {
    931                     if (predecessor != null) {
    932                         predecessor.next = next;
    933                     } else {
    934                         mHead = next;
    935                     }
    936                     recycleCallbackLocked(callback);
    937                 } else {
    938                     predecessor = callback;
    939                 }
    940                 callback = next;
    941             }
    942         }
    943     }
    944 }
    945