Loading core/java/android/view/Choreographer.java +29 −18 Original line number Diff line number Diff line Loading @@ -177,8 +177,14 @@ public final class Choreographer { private boolean mCallbacksRunning; @UnsupportedAppUsage private long mLastFrameTimeNanos; @UnsupportedAppUsage /** DO NOT USE since this will not updated when screen refresh changes. */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, publicAlternatives = "Use {@link android.view.Display#getRefreshRate} instead") @Deprecated private long mFrameIntervalNanos; private long mLastFrameIntervalNanos; private boolean mDebugPrintNextFrameTimeDelta; private int mFPSDivisor = 1; private DisplayEventReceiver.VsyncEventData mLastVsyncEventData = Loading Loading @@ -392,7 +398,9 @@ public final class Choreographer { * @hide */ public long getFrameIntervalNanos() { return mFrameIntervalNanos; synchronized (mLock) { return mLastFrameIntervalNanos; } } void dump(String prefix, PrintWriter writer) { Loading Loading @@ -688,6 +696,7 @@ public final class Choreographer { void doFrame(long frameTimeNanos, int frame, DisplayEventReceiver.VsyncEventData vsyncEventData) { final long startNanos; final long frameIntervalNanos = vsyncEventData.frameInterval; synchronized (mLock) { if (!mFrameScheduled) { return; // no work to do Loading @@ -702,17 +711,17 @@ public final class Choreographer { long intendedFrameTimeNanos = frameTimeNanos; startNanos = System.nanoTime(); final long jitterNanos = startNanos - frameTimeNanos; if (jitterNanos >= mFrameIntervalNanos) { final long skippedFrames = jitterNanos / mFrameIntervalNanos; if (jitterNanos >= frameIntervalNanos) { final long skippedFrames = jitterNanos / frameIntervalNanos; if (skippedFrames >= SKIPPED_FRAME_WARNING_LIMIT) { Log.i(TAG, "Skipped " + skippedFrames + " frames! " + "The application may be doing too much work on its main thread."); } final long lastFrameOffset = jitterNanos % mFrameIntervalNanos; final long lastFrameOffset = jitterNanos % frameIntervalNanos; if (DEBUG_JANK) { Log.d(TAG, "Missed vsync by " + (jitterNanos * 0.000001f) + " ms " + "which is more than the frame interval of " + (mFrameIntervalNanos * 0.000001f) + " ms! " + (frameIntervalNanos * 0.000001f) + " ms! " + "Skipping " + skippedFrames + " frames and setting frame " + "time to " + (lastFrameOffset * 0.000001f) + " ms in the past."); } Loading @@ -730,16 +739,17 @@ public final class Choreographer { if (mFPSDivisor > 1) { long timeSinceVsync = frameTimeNanos - mLastFrameTimeNanos; if (timeSinceVsync < (mFrameIntervalNanos * mFPSDivisor) && timeSinceVsync > 0) { if (timeSinceVsync < (frameIntervalNanos * mFPSDivisor) && timeSinceVsync > 0) { scheduleVsyncLocked(); return; } } mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos, vsyncEventData.id, vsyncEventData.frameDeadline, startNanos); vsyncEventData.frameDeadline, startNanos, vsyncEventData.frameInterval); mFrameScheduled = false; mLastFrameTimeNanos = frameTimeNanos; mLastFrameIntervalNanos = frameIntervalNanos; mLastVsyncEventData = vsyncEventData; } Loading @@ -751,16 +761,17 @@ public final class Choreographer { AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS); mFrameInfo.markInputHandlingStart(); doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos); doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos, frameIntervalNanos); mFrameInfo.markAnimationsStart(); doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos); doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameTimeNanos); doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos, frameIntervalNanos); doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameTimeNanos, frameIntervalNanos); mFrameInfo.markPerformTraversalsStart(); doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos); doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos, frameIntervalNanos); doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos); doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos, frameIntervalNanos); } finally { AnimationUtils.unlockAnimationClock(); Trace.traceEnd(Trace.TRACE_TAG_VIEW); Loading @@ -774,7 +785,7 @@ public final class Choreographer { } } void doCallbacks(int callbackType, long frameTimeNanos) { void doCallbacks(int callbackType, long frameTimeNanos, long frameIntervalNanos) { CallbackRecord callbacks; synchronized (mLock) { // We use "now" to determine when callbacks become due because it's possible Loading @@ -799,13 +810,13 @@ public final class Choreographer { if (callbackType == Choreographer.CALLBACK_COMMIT) { final long jitterNanos = now - frameTimeNanos; Trace.traceCounter(Trace.TRACE_TAG_VIEW, "jitterNanos", (int) jitterNanos); if (jitterNanos >= 2 * mFrameIntervalNanos) { final long lastFrameOffset = jitterNanos % mFrameIntervalNanos + mFrameIntervalNanos; if (jitterNanos >= 2 * frameIntervalNanos) { final long lastFrameOffset = jitterNanos % frameIntervalNanos + frameIntervalNanos; if (DEBUG_JANK) { Log.d(TAG, "Commit callback delayed by " + (jitterNanos * 0.000001f) + " ms which is more than twice the frame interval of " + (mFrameIntervalNanos * 0.000001f) + " ms! " + (frameIntervalNanos * 0.000001f) + " ms! " + "Setting frame time to " + (lastFrameOffset * 0.000001f) + " ms in the past."); mDebugPrintNextFrameTimeDelta = true; Loading core/java/android/view/DisplayEventReceiver.java +12 −3 Original line number Diff line number Diff line Loading @@ -146,14 +146,23 @@ public abstract class DisplayEventReceiver { // allotted for the frame to be completed. public final long frameDeadline; VsyncEventData(long id, long frameDeadline) { /** * The current interval between frames in ns. This will be used to align * {@link FrameInfo#VSYNC} to the current vsync in case Choreographer callback was heavily * delayed by the app. */ public final long frameInterval; VsyncEventData(long id, long frameDeadline, long frameInterval) { this.id = id; this.frameDeadline = frameDeadline; this.frameInterval = frameInterval; } VsyncEventData() { this.id = FrameInfo.INVALID_VSYNC_ID; this.frameDeadline = Long.MAX_VALUE; this.frameInterval = -1; } } Loading Loading @@ -247,9 +256,9 @@ public abstract class DisplayEventReceiver { // Called from native code. @SuppressWarnings("unused") private void dispatchVsync(long timestampNanos, long physicalDisplayId, int frame, long frameTimelineVsyncId, long frameDeadline) { long frameTimelineVsyncId, long frameDeadline, long frameInterval) { onVsync(timestampNanos, physicalDisplayId, frame, new VsyncEventData(frameTimelineVsyncId, frameDeadline)); new VsyncEventData(frameTimelineVsyncId, frameDeadline, frameInterval)); } // Called from native code. Loading core/java/android/view/FrameMetrics.java +12 −11 Original line number Diff line number Diff line Loading @@ -243,18 +243,19 @@ public final class FrameMetrics { int DRAW_START = 8; int FRAME_DEADLINE = 9; int FRAME_START_TIME = 10; int SYNC_QUEUED = 11; int SYNC_START = 12; int ISSUE_DRAW_COMMANDS_START = 13; int SWAP_BUFFERS = 14; int FRAME_COMPLETED = 15; int DEQUEUE_BUFFER_DURATION = 16; int QUEUE_BUFFER_DURATION = 17; int GPU_COMPLETED = 18; int SWAP_BUFFERS_COMPLETED = 19; int DISPLAY_PRESENT_TIME = 20; int FRAME_INTERVAL = 11; int SYNC_QUEUED = 12; int SYNC_START = 13; int ISSUE_DRAW_COMMANDS_START = 14; int SWAP_BUFFERS = 15; int FRAME_COMPLETED = 16; int DEQUEUE_BUFFER_DURATION = 17; int QUEUE_BUFFER_DURATION = 18; int GPU_COMPLETED = 19; int SWAP_BUFFERS_COMPLETED = 20; int DISPLAY_PRESENT_TIME = 21; int FRAME_STATS_COUNT = 21; // must always be last and in sync with int FRAME_STATS_COUNT = 22; // must always be last and in sync with // FrameInfoIndex::NumIndexes in libs/hwui/FrameInfo.h } Loading core/jni/android_view_DisplayEventReceiver.cpp +2 −2 Original line number Diff line number Diff line Loading @@ -107,7 +107,7 @@ void NativeDisplayEventReceiver::dispatchVsync(nsecs_t timestamp, PhysicalDispla ALOGV("receiver %p ~ Invoking vsync handler.", this); env->CallVoidMethod(receiverObj.get(), gDisplayEventReceiverClassInfo.dispatchVsync, timestamp, displayId.value, count, vsyncEventData.id, vsyncEventData.deadlineTimestamp); vsyncEventData.deadlineTimestamp, vsyncEventData.frameInterval); ALOGV("receiver %p ~ Returned from vsync handler.", this); } Loading Loading @@ -239,7 +239,7 @@ int register_android_view_DisplayEventReceiver(JNIEnv* env) { gDisplayEventReceiverClassInfo.dispatchVsync = GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.clazz, "dispatchVsync", "(JJIJJ)V"); "(JJIJJJ)V"); gDisplayEventReceiverClassInfo.dispatchHotplug = GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.clazz, "dispatchHotplug", "(JJZ)V"); gDisplayEventReceiverClassInfo.dispatchModeChanged = Loading graphics/java/android/graphics/FrameInfo.java +6 −2 Original line number Diff line number Diff line Loading @@ -90,19 +90,23 @@ public final class FrameInfo { // When frame actually started. public static final int FRAME_START_TIME = 10; // Interval between two consecutive frames public static final int FRAME_INTERVAL = 11; // Must be the last one // This value must be in sync with `UI_THREAD_FRAME_INFO_SIZE` in FrameInfo.h private static final int FRAME_INFO_SIZE = FRAME_START_TIME + 1; private static final int FRAME_INFO_SIZE = FRAME_INTERVAL + 1; /** checkstyle */ public void setVsync(long intendedVsync, long usedVsync, long frameTimelineVsyncId, long frameDeadline, long frameStartTime) { long frameDeadline, long frameStartTime, long frameInterval) { frameInfo[FRAME_TIMELINE_VSYNC_ID] = frameTimelineVsyncId; frameInfo[INTENDED_VSYNC] = intendedVsync; frameInfo[VSYNC] = usedVsync; frameInfo[FLAGS] = 0; frameInfo[FRAME_DEADLINE] = frameDeadline; frameInfo[FRAME_START_TIME] = frameStartTime; frameInfo[FRAME_INTERVAL] = frameInterval; } /** checkstyle */ Loading Loading
core/java/android/view/Choreographer.java +29 −18 Original line number Diff line number Diff line Loading @@ -177,8 +177,14 @@ public final class Choreographer { private boolean mCallbacksRunning; @UnsupportedAppUsage private long mLastFrameTimeNanos; @UnsupportedAppUsage /** DO NOT USE since this will not updated when screen refresh changes. */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, publicAlternatives = "Use {@link android.view.Display#getRefreshRate} instead") @Deprecated private long mFrameIntervalNanos; private long mLastFrameIntervalNanos; private boolean mDebugPrintNextFrameTimeDelta; private int mFPSDivisor = 1; private DisplayEventReceiver.VsyncEventData mLastVsyncEventData = Loading Loading @@ -392,7 +398,9 @@ public final class Choreographer { * @hide */ public long getFrameIntervalNanos() { return mFrameIntervalNanos; synchronized (mLock) { return mLastFrameIntervalNanos; } } void dump(String prefix, PrintWriter writer) { Loading Loading @@ -688,6 +696,7 @@ public final class Choreographer { void doFrame(long frameTimeNanos, int frame, DisplayEventReceiver.VsyncEventData vsyncEventData) { final long startNanos; final long frameIntervalNanos = vsyncEventData.frameInterval; synchronized (mLock) { if (!mFrameScheduled) { return; // no work to do Loading @@ -702,17 +711,17 @@ public final class Choreographer { long intendedFrameTimeNanos = frameTimeNanos; startNanos = System.nanoTime(); final long jitterNanos = startNanos - frameTimeNanos; if (jitterNanos >= mFrameIntervalNanos) { final long skippedFrames = jitterNanos / mFrameIntervalNanos; if (jitterNanos >= frameIntervalNanos) { final long skippedFrames = jitterNanos / frameIntervalNanos; if (skippedFrames >= SKIPPED_FRAME_WARNING_LIMIT) { Log.i(TAG, "Skipped " + skippedFrames + " frames! " + "The application may be doing too much work on its main thread."); } final long lastFrameOffset = jitterNanos % mFrameIntervalNanos; final long lastFrameOffset = jitterNanos % frameIntervalNanos; if (DEBUG_JANK) { Log.d(TAG, "Missed vsync by " + (jitterNanos * 0.000001f) + " ms " + "which is more than the frame interval of " + (mFrameIntervalNanos * 0.000001f) + " ms! " + (frameIntervalNanos * 0.000001f) + " ms! " + "Skipping " + skippedFrames + " frames and setting frame " + "time to " + (lastFrameOffset * 0.000001f) + " ms in the past."); } Loading @@ -730,16 +739,17 @@ public final class Choreographer { if (mFPSDivisor > 1) { long timeSinceVsync = frameTimeNanos - mLastFrameTimeNanos; if (timeSinceVsync < (mFrameIntervalNanos * mFPSDivisor) && timeSinceVsync > 0) { if (timeSinceVsync < (frameIntervalNanos * mFPSDivisor) && timeSinceVsync > 0) { scheduleVsyncLocked(); return; } } mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos, vsyncEventData.id, vsyncEventData.frameDeadline, startNanos); vsyncEventData.frameDeadline, startNanos, vsyncEventData.frameInterval); mFrameScheduled = false; mLastFrameTimeNanos = frameTimeNanos; mLastFrameIntervalNanos = frameIntervalNanos; mLastVsyncEventData = vsyncEventData; } Loading @@ -751,16 +761,17 @@ public final class Choreographer { AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS); mFrameInfo.markInputHandlingStart(); doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos); doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos, frameIntervalNanos); mFrameInfo.markAnimationsStart(); doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos); doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameTimeNanos); doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos, frameIntervalNanos); doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameTimeNanos, frameIntervalNanos); mFrameInfo.markPerformTraversalsStart(); doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos); doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos, frameIntervalNanos); doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos); doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos, frameIntervalNanos); } finally { AnimationUtils.unlockAnimationClock(); Trace.traceEnd(Trace.TRACE_TAG_VIEW); Loading @@ -774,7 +785,7 @@ public final class Choreographer { } } void doCallbacks(int callbackType, long frameTimeNanos) { void doCallbacks(int callbackType, long frameTimeNanos, long frameIntervalNanos) { CallbackRecord callbacks; synchronized (mLock) { // We use "now" to determine when callbacks become due because it's possible Loading @@ -799,13 +810,13 @@ public final class Choreographer { if (callbackType == Choreographer.CALLBACK_COMMIT) { final long jitterNanos = now - frameTimeNanos; Trace.traceCounter(Trace.TRACE_TAG_VIEW, "jitterNanos", (int) jitterNanos); if (jitterNanos >= 2 * mFrameIntervalNanos) { final long lastFrameOffset = jitterNanos % mFrameIntervalNanos + mFrameIntervalNanos; if (jitterNanos >= 2 * frameIntervalNanos) { final long lastFrameOffset = jitterNanos % frameIntervalNanos + frameIntervalNanos; if (DEBUG_JANK) { Log.d(TAG, "Commit callback delayed by " + (jitterNanos * 0.000001f) + " ms which is more than twice the frame interval of " + (mFrameIntervalNanos * 0.000001f) + " ms! " + (frameIntervalNanos * 0.000001f) + " ms! " + "Setting frame time to " + (lastFrameOffset * 0.000001f) + " ms in the past."); mDebugPrintNextFrameTimeDelta = true; Loading
core/java/android/view/DisplayEventReceiver.java +12 −3 Original line number Diff line number Diff line Loading @@ -146,14 +146,23 @@ public abstract class DisplayEventReceiver { // allotted for the frame to be completed. public final long frameDeadline; VsyncEventData(long id, long frameDeadline) { /** * The current interval between frames in ns. This will be used to align * {@link FrameInfo#VSYNC} to the current vsync in case Choreographer callback was heavily * delayed by the app. */ public final long frameInterval; VsyncEventData(long id, long frameDeadline, long frameInterval) { this.id = id; this.frameDeadline = frameDeadline; this.frameInterval = frameInterval; } VsyncEventData() { this.id = FrameInfo.INVALID_VSYNC_ID; this.frameDeadline = Long.MAX_VALUE; this.frameInterval = -1; } } Loading Loading @@ -247,9 +256,9 @@ public abstract class DisplayEventReceiver { // Called from native code. @SuppressWarnings("unused") private void dispatchVsync(long timestampNanos, long physicalDisplayId, int frame, long frameTimelineVsyncId, long frameDeadline) { long frameTimelineVsyncId, long frameDeadline, long frameInterval) { onVsync(timestampNanos, physicalDisplayId, frame, new VsyncEventData(frameTimelineVsyncId, frameDeadline)); new VsyncEventData(frameTimelineVsyncId, frameDeadline, frameInterval)); } // Called from native code. Loading
core/java/android/view/FrameMetrics.java +12 −11 Original line number Diff line number Diff line Loading @@ -243,18 +243,19 @@ public final class FrameMetrics { int DRAW_START = 8; int FRAME_DEADLINE = 9; int FRAME_START_TIME = 10; int SYNC_QUEUED = 11; int SYNC_START = 12; int ISSUE_DRAW_COMMANDS_START = 13; int SWAP_BUFFERS = 14; int FRAME_COMPLETED = 15; int DEQUEUE_BUFFER_DURATION = 16; int QUEUE_BUFFER_DURATION = 17; int GPU_COMPLETED = 18; int SWAP_BUFFERS_COMPLETED = 19; int DISPLAY_PRESENT_TIME = 20; int FRAME_INTERVAL = 11; int SYNC_QUEUED = 12; int SYNC_START = 13; int ISSUE_DRAW_COMMANDS_START = 14; int SWAP_BUFFERS = 15; int FRAME_COMPLETED = 16; int DEQUEUE_BUFFER_DURATION = 17; int QUEUE_BUFFER_DURATION = 18; int GPU_COMPLETED = 19; int SWAP_BUFFERS_COMPLETED = 20; int DISPLAY_PRESENT_TIME = 21; int FRAME_STATS_COUNT = 21; // must always be last and in sync with int FRAME_STATS_COUNT = 22; // must always be last and in sync with // FrameInfoIndex::NumIndexes in libs/hwui/FrameInfo.h } Loading
core/jni/android_view_DisplayEventReceiver.cpp +2 −2 Original line number Diff line number Diff line Loading @@ -107,7 +107,7 @@ void NativeDisplayEventReceiver::dispatchVsync(nsecs_t timestamp, PhysicalDispla ALOGV("receiver %p ~ Invoking vsync handler.", this); env->CallVoidMethod(receiverObj.get(), gDisplayEventReceiverClassInfo.dispatchVsync, timestamp, displayId.value, count, vsyncEventData.id, vsyncEventData.deadlineTimestamp); vsyncEventData.deadlineTimestamp, vsyncEventData.frameInterval); ALOGV("receiver %p ~ Returned from vsync handler.", this); } Loading Loading @@ -239,7 +239,7 @@ int register_android_view_DisplayEventReceiver(JNIEnv* env) { gDisplayEventReceiverClassInfo.dispatchVsync = GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.clazz, "dispatchVsync", "(JJIJJ)V"); "(JJIJJJ)V"); gDisplayEventReceiverClassInfo.dispatchHotplug = GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.clazz, "dispatchHotplug", "(JJZ)V"); gDisplayEventReceiverClassInfo.dispatchModeChanged = Loading
graphics/java/android/graphics/FrameInfo.java +6 −2 Original line number Diff line number Diff line Loading @@ -90,19 +90,23 @@ public final class FrameInfo { // When frame actually started. public static final int FRAME_START_TIME = 10; // Interval between two consecutive frames public static final int FRAME_INTERVAL = 11; // Must be the last one // This value must be in sync with `UI_THREAD_FRAME_INFO_SIZE` in FrameInfo.h private static final int FRAME_INFO_SIZE = FRAME_START_TIME + 1; private static final int FRAME_INFO_SIZE = FRAME_INTERVAL + 1; /** checkstyle */ public void setVsync(long intendedVsync, long usedVsync, long frameTimelineVsyncId, long frameDeadline, long frameStartTime) { long frameDeadline, long frameStartTime, long frameInterval) { frameInfo[FRAME_TIMELINE_VSYNC_ID] = frameTimelineVsyncId; frameInfo[INTENDED_VSYNC] = intendedVsync; frameInfo[VSYNC] = usedVsync; frameInfo[FLAGS] = 0; frameInfo[FRAME_DEADLINE] = frameDeadline; frameInfo[FRAME_START_TIME] = frameStartTime; frameInfo[FRAME_INTERVAL] = frameInterval; } /** checkstyle */ Loading