Loading core/java/android/view/HardwareRenderer.java +14 −1 Original line number Diff line number Diff line Loading @@ -646,7 +646,20 @@ public abstract class HardwareRenderer { attachInfo.mIgnoreDirtyState = false; final long swapBuffersStartTime; if (ViewDebug.DEBUG_LATENCY) { swapBuffersStartTime = System.nanoTime(); } sEgl.eglSwapBuffers(sEglDisplay, mEglSurface); if (ViewDebug.DEBUG_LATENCY) { long now = System.nanoTime(); Log.d(LOG_TAG, "Latency: Spent " + ((now - swapBuffersStartTime) * 0.000001f) + "ms waiting for eglSwapBuffers()"); } checkEglErrors(); } } Loading core/java/android/view/InputEvent.java +7 −0 Original line number Diff line number Diff line Loading @@ -106,6 +106,13 @@ public abstract class InputEvent implements Parcelable { */ public abstract void setTainted(boolean tainted); /** * Returns the time (in ns) when this specific event was generated. * The value is in nanosecond precision but it may not have nanosecond accuracy. * @hide */ public abstract long getEventTimeNano(); public int describeContents() { return 0; } Loading core/java/android/view/KeyEvent.java +6 −0 Original line number Diff line number Diff line Loading @@ -2340,6 +2340,12 @@ public class KeyEvent extends InputEvent implements Parcelable { return mEventTime; } /** @hide */ @Override public final long getEventTimeNano() { return mEventTime * 1000000L; } /** * Renamed to {@link #getDeviceId}. * Loading core/java/android/view/ViewDebug.java +16 −0 Original line number Diff line number Diff line Loading @@ -140,6 +140,22 @@ public class ViewDebug { */ public static final boolean DEBUG_DRAG = false; /** * Enables logging of factors that affect the latency and responsiveness of an application. * * Logs the relative difference between the time an event was created and the time it * was delivered. * * Logs the time spent waiting for Surface.lockCanvas() or eglSwapBuffers(). * This is time that the event loop spends blocked and unresponsive. Ideally, drawing * and animations should be perfectly synchronized with VSYNC so that swap buffers * is instantaneous. * * Logs the time spent in ViewRoot.performTraversals() or ViewRoot.draw(). * @hide */ public static final boolean DEBUG_LATENCY = false; /** * <p>Enables or disables views consistency check. Even when this property is enabled, * view consistency checks happen only if {@link android.util.Config#DEBUG} is set Loading core/java/android/view/ViewRoot.java +124 −10 Original line number Diff line number Diff line Loading @@ -186,6 +186,8 @@ public final class ViewRoot extends Handler implements ViewParent, final Rect mVisRect; // used to retrieve visible rect of focused view. boolean mTraversalScheduled; long mLastTraversalFinishedTimeNanos; long mLastDrawDurationNanos; boolean mWillDrawSoon; boolean mLayoutRequested; boolean mFirst; Loading Loading @@ -671,6 +673,14 @@ public final class ViewRoot extends Handler implements ViewParent, public void scheduleTraversals() { if (!mTraversalScheduled) { mTraversalScheduled = true; if (ViewDebug.DEBUG_LATENCY && mLastTraversalFinishedTimeNanos != 0) { final long now = System.nanoTime(); Log.d(TAG, "Latency: Scheduled traversal, it has been " + ((now - mLastTraversalFinishedTimeNanos) * 0.000001f) + "ms since the last traversal finished."); } sendEmptyMessage(DO_TRAVERSAL); } } Loading Loading @@ -1389,8 +1399,18 @@ public final class ViewRoot extends Handler implements ViewParent, if (!cancelDraw && !newSurface) { mFullRedrawNeeded = false; final long drawStartTime; if (ViewDebug.DEBUG_LATENCY) { drawStartTime = System.nanoTime(); } draw(fullRedrawNeeded); if (ViewDebug.DEBUG_LATENCY) { mLastDrawDurationNanos = System.nanoTime() - drawStartTime; } if ((relayoutResult&WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0 || mReportNextDraw) { if (LOCAL_LOGV) { Loading Loading @@ -1601,8 +1621,20 @@ public final class ViewRoot extends Handler implements ViewParent, int right = dirty.right; int bottom = dirty.bottom; final long lockCanvasStartTime; if (ViewDebug.DEBUG_LATENCY) { lockCanvasStartTime = System.nanoTime(); } canvas = surface.lockCanvas(dirty); if (ViewDebug.DEBUG_LATENCY) { long now = System.nanoTime(); Log.d(TAG, "Latency: Spent " + ((now - lockCanvasStartTime) * 0.000001f) + "ms waiting for surface.lockCanvas()"); } if (left != dirty.left || top != dirty.top || right != dirty.right || bottom != dirty.bottom) { mAttachInfo.mIgnoreDirtyState = true; Loading Loading @@ -2011,8 +2043,24 @@ public final class ViewRoot extends Handler implements ViewParent, Debug.startMethodTracing("ViewRoot"); } final long traversalStartTime; if (ViewDebug.DEBUG_LATENCY) { traversalStartTime = System.nanoTime(); mLastDrawDurationNanos = 0; } performTraversals(); if (ViewDebug.DEBUG_LATENCY) { long now = System.nanoTime(); Log.d(TAG, "Latency: Spent " + ((now - traversalStartTime) * 0.000001f) + "ms in performTraversals(), with " + (mLastDrawDurationNanos * 0.000001f) + "ms of that time in draw()"); mLastTraversalFinishedTimeNanos = now; } if (mProfile) { Debug.stopMethodTracing(); mProfile = false; Loading Loading @@ -2180,25 +2228,68 @@ public final class ViewRoot extends Handler implements ViewParent, } } private void startInputEvent(InputQueue.FinishedCallback finishedCallback) { private void startInputEvent(InputEvent event, InputQueue.FinishedCallback finishedCallback) { if (mFinishedCallback != null) { Slog.w(TAG, "Received a new input event from the input queue but there is " + "already an unfinished input event in progress."); } if (ViewDebug.DEBUG_LATENCY) { mInputEventReceiveTimeNanos = System.nanoTime(); mInputEventDeliverTimeNanos = 0; mInputEventDeliverPostImeTimeNanos = 0; } mFinishedCallback = finishedCallback; } private void finishInputEvent(boolean handled) { private void finishInputEvent(InputEvent event, boolean handled) { if (LOCAL_LOGV) Log.v(TAG, "Telling window manager input event is finished"); if (mFinishedCallback != null) { mFinishedCallback.finished(handled); mFinishedCallback = null; } else { if (mFinishedCallback == null) { Slog.w(TAG, "Attempted to tell the input queue that the current input event " + "is finished but there is no input event actually in progress."); return; } if (ViewDebug.DEBUG_LATENCY) { final long now = System.nanoTime(); final long eventTime = event.getEventTimeNano(); final StringBuilder msg = new StringBuilder(); msg.append("Latency: Spent "); msg.append((now - mInputEventReceiveTimeNanos) * 0.000001f); msg.append("ms processing "); if (event instanceof KeyEvent) { final KeyEvent keyEvent = (KeyEvent)event; msg.append("key event, action="); msg.append(KeyEvent.actionToString(keyEvent.getAction())); } else { final MotionEvent motionEvent = (MotionEvent)event; msg.append("motion event, action="); msg.append(MotionEvent.actionToString(motionEvent.getAction())); msg.append(", historySize="); msg.append(motionEvent.getHistorySize()); } msg.append(", handled="); msg.append(handled); msg.append(", received at +"); msg.append((mInputEventReceiveTimeNanos - eventTime) * 0.000001f); if (mInputEventDeliverTimeNanos != 0) { msg.append("ms, delivered at +"); msg.append((mInputEventDeliverTimeNanos - eventTime) * 0.000001f); } if (mInputEventDeliverPostImeTimeNanos != 0) { msg.append("ms, delivered post IME at +"); msg.append((mInputEventDeliverPostImeTimeNanos - eventTime) * 0.000001f); } msg.append("ms, finished at +"); msg.append((now - eventTime) * 0.000001f); msg.append("ms."); Log.d(TAG, msg.toString()); } mFinishedCallback.finished(handled); mFinishedCallback = null; } /** Loading Loading @@ -2323,6 +2414,10 @@ public final class ViewRoot extends Handler implements ViewParent, } private void deliverPointerEvent(MotionEvent event, boolean sendDone) { if (ViewDebug.DEBUG_LATENCY) { mInputEventDeliverTimeNanos = System.nanoTime(); } if (mInputEventConsistencyVerifier != null) { if (event.isTouchEvent()) { mInputEventConsistencyVerifier.onTouchEvent(event, 0); Loading Loading @@ -2425,7 +2520,7 @@ public final class ViewRoot extends Handler implements ViewParent, private void finishMotionEvent(MotionEvent event, boolean sendDone, boolean handled) { event.recycle(); if (sendDone) { finishInputEvent(handled); finishInputEvent(event, handled); } if (LOCAL_LOGV || WATCH_POINTER) { if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) { Loading @@ -2435,6 +2530,10 @@ public final class ViewRoot extends Handler implements ViewParent, } private void deliverTrackballEvent(MotionEvent event, boolean sendDone) { if (ViewDebug.DEBUG_LATENCY) { mInputEventDeliverTimeNanos = System.nanoTime(); } if (DEBUG_TRACKBALL) Log.v(TAG, "Motion event:" + event); if (mInputEventConsistencyVerifier != null) { Loading Loading @@ -2569,6 +2668,10 @@ public final class ViewRoot extends Handler implements ViewParent, } private void deliverGenericMotionEvent(MotionEvent event, boolean sendDone) { if (ViewDebug.DEBUG_LATENCY) { mInputEventDeliverTimeNanos = System.nanoTime(); } if (mInputEventConsistencyVerifier != null) { mInputEventConsistencyVerifier.onGenericMotionEvent(event, 0); } Loading Loading @@ -2808,6 +2911,10 @@ public final class ViewRoot extends Handler implements ViewParent, } private void deliverKeyEvent(KeyEvent event, boolean sendDone) { if (ViewDebug.DEBUG_LATENCY) { mInputEventDeliverTimeNanos = System.nanoTime(); } if (mInputEventConsistencyVerifier != null) { mInputEventConsistencyVerifier.onKeyEvent(event, 0); } Loading Loading @@ -2858,6 +2965,10 @@ public final class ViewRoot extends Handler implements ViewParent, } private void deliverKeyEventPostIme(KeyEvent event, boolean sendDone) { if (ViewDebug.DEBUG_LATENCY) { mInputEventDeliverPostImeTimeNanos = System.nanoTime(); } // If the view went away, then the event will not be handled. if (mView == null || !mAdded) { finishKeyEvent(event, sendDone, false); Loading Loading @@ -2971,7 +3082,7 @@ public final class ViewRoot extends Handler implements ViewParent, private void finishKeyEvent(KeyEvent event, boolean sendDone, boolean handled) { if (sendDone) { finishInputEvent(handled); finishInputEvent(event, handled); } } Loading Loading @@ -3262,16 +3373,19 @@ public final class ViewRoot extends Handler implements ViewParent, sendMessage(msg); } private long mInputEventReceiveTimeNanos; private long mInputEventDeliverTimeNanos; private long mInputEventDeliverPostImeTimeNanos; private InputQueue.FinishedCallback mFinishedCallback; private final InputHandler mInputHandler = new InputHandler() { public void handleKey(KeyEvent event, InputQueue.FinishedCallback finishedCallback) { startInputEvent(finishedCallback); startInputEvent(event, finishedCallback); dispatchKey(event, true); } public void handleMotion(MotionEvent event, InputQueue.FinishedCallback finishedCallback) { startInputEvent(finishedCallback); startInputEvent(event, finishedCallback); dispatchMotion(event, true); } }; Loading Loading
core/java/android/view/HardwareRenderer.java +14 −1 Original line number Diff line number Diff line Loading @@ -646,7 +646,20 @@ public abstract class HardwareRenderer { attachInfo.mIgnoreDirtyState = false; final long swapBuffersStartTime; if (ViewDebug.DEBUG_LATENCY) { swapBuffersStartTime = System.nanoTime(); } sEgl.eglSwapBuffers(sEglDisplay, mEglSurface); if (ViewDebug.DEBUG_LATENCY) { long now = System.nanoTime(); Log.d(LOG_TAG, "Latency: Spent " + ((now - swapBuffersStartTime) * 0.000001f) + "ms waiting for eglSwapBuffers()"); } checkEglErrors(); } } Loading
core/java/android/view/InputEvent.java +7 −0 Original line number Diff line number Diff line Loading @@ -106,6 +106,13 @@ public abstract class InputEvent implements Parcelable { */ public abstract void setTainted(boolean tainted); /** * Returns the time (in ns) when this specific event was generated. * The value is in nanosecond precision but it may not have nanosecond accuracy. * @hide */ public abstract long getEventTimeNano(); public int describeContents() { return 0; } Loading
core/java/android/view/KeyEvent.java +6 −0 Original line number Diff line number Diff line Loading @@ -2340,6 +2340,12 @@ public class KeyEvent extends InputEvent implements Parcelable { return mEventTime; } /** @hide */ @Override public final long getEventTimeNano() { return mEventTime * 1000000L; } /** * Renamed to {@link #getDeviceId}. * Loading
core/java/android/view/ViewDebug.java +16 −0 Original line number Diff line number Diff line Loading @@ -140,6 +140,22 @@ public class ViewDebug { */ public static final boolean DEBUG_DRAG = false; /** * Enables logging of factors that affect the latency and responsiveness of an application. * * Logs the relative difference between the time an event was created and the time it * was delivered. * * Logs the time spent waiting for Surface.lockCanvas() or eglSwapBuffers(). * This is time that the event loop spends blocked and unresponsive. Ideally, drawing * and animations should be perfectly synchronized with VSYNC so that swap buffers * is instantaneous. * * Logs the time spent in ViewRoot.performTraversals() or ViewRoot.draw(). * @hide */ public static final boolean DEBUG_LATENCY = false; /** * <p>Enables or disables views consistency check. Even when this property is enabled, * view consistency checks happen only if {@link android.util.Config#DEBUG} is set Loading
core/java/android/view/ViewRoot.java +124 −10 Original line number Diff line number Diff line Loading @@ -186,6 +186,8 @@ public final class ViewRoot extends Handler implements ViewParent, final Rect mVisRect; // used to retrieve visible rect of focused view. boolean mTraversalScheduled; long mLastTraversalFinishedTimeNanos; long mLastDrawDurationNanos; boolean mWillDrawSoon; boolean mLayoutRequested; boolean mFirst; Loading Loading @@ -671,6 +673,14 @@ public final class ViewRoot extends Handler implements ViewParent, public void scheduleTraversals() { if (!mTraversalScheduled) { mTraversalScheduled = true; if (ViewDebug.DEBUG_LATENCY && mLastTraversalFinishedTimeNanos != 0) { final long now = System.nanoTime(); Log.d(TAG, "Latency: Scheduled traversal, it has been " + ((now - mLastTraversalFinishedTimeNanos) * 0.000001f) + "ms since the last traversal finished."); } sendEmptyMessage(DO_TRAVERSAL); } } Loading Loading @@ -1389,8 +1399,18 @@ public final class ViewRoot extends Handler implements ViewParent, if (!cancelDraw && !newSurface) { mFullRedrawNeeded = false; final long drawStartTime; if (ViewDebug.DEBUG_LATENCY) { drawStartTime = System.nanoTime(); } draw(fullRedrawNeeded); if (ViewDebug.DEBUG_LATENCY) { mLastDrawDurationNanos = System.nanoTime() - drawStartTime; } if ((relayoutResult&WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0 || mReportNextDraw) { if (LOCAL_LOGV) { Loading Loading @@ -1601,8 +1621,20 @@ public final class ViewRoot extends Handler implements ViewParent, int right = dirty.right; int bottom = dirty.bottom; final long lockCanvasStartTime; if (ViewDebug.DEBUG_LATENCY) { lockCanvasStartTime = System.nanoTime(); } canvas = surface.lockCanvas(dirty); if (ViewDebug.DEBUG_LATENCY) { long now = System.nanoTime(); Log.d(TAG, "Latency: Spent " + ((now - lockCanvasStartTime) * 0.000001f) + "ms waiting for surface.lockCanvas()"); } if (left != dirty.left || top != dirty.top || right != dirty.right || bottom != dirty.bottom) { mAttachInfo.mIgnoreDirtyState = true; Loading Loading @@ -2011,8 +2043,24 @@ public final class ViewRoot extends Handler implements ViewParent, Debug.startMethodTracing("ViewRoot"); } final long traversalStartTime; if (ViewDebug.DEBUG_LATENCY) { traversalStartTime = System.nanoTime(); mLastDrawDurationNanos = 0; } performTraversals(); if (ViewDebug.DEBUG_LATENCY) { long now = System.nanoTime(); Log.d(TAG, "Latency: Spent " + ((now - traversalStartTime) * 0.000001f) + "ms in performTraversals(), with " + (mLastDrawDurationNanos * 0.000001f) + "ms of that time in draw()"); mLastTraversalFinishedTimeNanos = now; } if (mProfile) { Debug.stopMethodTracing(); mProfile = false; Loading Loading @@ -2180,25 +2228,68 @@ public final class ViewRoot extends Handler implements ViewParent, } } private void startInputEvent(InputQueue.FinishedCallback finishedCallback) { private void startInputEvent(InputEvent event, InputQueue.FinishedCallback finishedCallback) { if (mFinishedCallback != null) { Slog.w(TAG, "Received a new input event from the input queue but there is " + "already an unfinished input event in progress."); } if (ViewDebug.DEBUG_LATENCY) { mInputEventReceiveTimeNanos = System.nanoTime(); mInputEventDeliverTimeNanos = 0; mInputEventDeliverPostImeTimeNanos = 0; } mFinishedCallback = finishedCallback; } private void finishInputEvent(boolean handled) { private void finishInputEvent(InputEvent event, boolean handled) { if (LOCAL_LOGV) Log.v(TAG, "Telling window manager input event is finished"); if (mFinishedCallback != null) { mFinishedCallback.finished(handled); mFinishedCallback = null; } else { if (mFinishedCallback == null) { Slog.w(TAG, "Attempted to tell the input queue that the current input event " + "is finished but there is no input event actually in progress."); return; } if (ViewDebug.DEBUG_LATENCY) { final long now = System.nanoTime(); final long eventTime = event.getEventTimeNano(); final StringBuilder msg = new StringBuilder(); msg.append("Latency: Spent "); msg.append((now - mInputEventReceiveTimeNanos) * 0.000001f); msg.append("ms processing "); if (event instanceof KeyEvent) { final KeyEvent keyEvent = (KeyEvent)event; msg.append("key event, action="); msg.append(KeyEvent.actionToString(keyEvent.getAction())); } else { final MotionEvent motionEvent = (MotionEvent)event; msg.append("motion event, action="); msg.append(MotionEvent.actionToString(motionEvent.getAction())); msg.append(", historySize="); msg.append(motionEvent.getHistorySize()); } msg.append(", handled="); msg.append(handled); msg.append(", received at +"); msg.append((mInputEventReceiveTimeNanos - eventTime) * 0.000001f); if (mInputEventDeliverTimeNanos != 0) { msg.append("ms, delivered at +"); msg.append((mInputEventDeliverTimeNanos - eventTime) * 0.000001f); } if (mInputEventDeliverPostImeTimeNanos != 0) { msg.append("ms, delivered post IME at +"); msg.append((mInputEventDeliverPostImeTimeNanos - eventTime) * 0.000001f); } msg.append("ms, finished at +"); msg.append((now - eventTime) * 0.000001f); msg.append("ms."); Log.d(TAG, msg.toString()); } mFinishedCallback.finished(handled); mFinishedCallback = null; } /** Loading Loading @@ -2323,6 +2414,10 @@ public final class ViewRoot extends Handler implements ViewParent, } private void deliverPointerEvent(MotionEvent event, boolean sendDone) { if (ViewDebug.DEBUG_LATENCY) { mInputEventDeliverTimeNanos = System.nanoTime(); } if (mInputEventConsistencyVerifier != null) { if (event.isTouchEvent()) { mInputEventConsistencyVerifier.onTouchEvent(event, 0); Loading Loading @@ -2425,7 +2520,7 @@ public final class ViewRoot extends Handler implements ViewParent, private void finishMotionEvent(MotionEvent event, boolean sendDone, boolean handled) { event.recycle(); if (sendDone) { finishInputEvent(handled); finishInputEvent(event, handled); } if (LOCAL_LOGV || WATCH_POINTER) { if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) { Loading @@ -2435,6 +2530,10 @@ public final class ViewRoot extends Handler implements ViewParent, } private void deliverTrackballEvent(MotionEvent event, boolean sendDone) { if (ViewDebug.DEBUG_LATENCY) { mInputEventDeliverTimeNanos = System.nanoTime(); } if (DEBUG_TRACKBALL) Log.v(TAG, "Motion event:" + event); if (mInputEventConsistencyVerifier != null) { Loading Loading @@ -2569,6 +2668,10 @@ public final class ViewRoot extends Handler implements ViewParent, } private void deliverGenericMotionEvent(MotionEvent event, boolean sendDone) { if (ViewDebug.DEBUG_LATENCY) { mInputEventDeliverTimeNanos = System.nanoTime(); } if (mInputEventConsistencyVerifier != null) { mInputEventConsistencyVerifier.onGenericMotionEvent(event, 0); } Loading Loading @@ -2808,6 +2911,10 @@ public final class ViewRoot extends Handler implements ViewParent, } private void deliverKeyEvent(KeyEvent event, boolean sendDone) { if (ViewDebug.DEBUG_LATENCY) { mInputEventDeliverTimeNanos = System.nanoTime(); } if (mInputEventConsistencyVerifier != null) { mInputEventConsistencyVerifier.onKeyEvent(event, 0); } Loading Loading @@ -2858,6 +2965,10 @@ public final class ViewRoot extends Handler implements ViewParent, } private void deliverKeyEventPostIme(KeyEvent event, boolean sendDone) { if (ViewDebug.DEBUG_LATENCY) { mInputEventDeliverPostImeTimeNanos = System.nanoTime(); } // If the view went away, then the event will not be handled. if (mView == null || !mAdded) { finishKeyEvent(event, sendDone, false); Loading Loading @@ -2971,7 +3082,7 @@ public final class ViewRoot extends Handler implements ViewParent, private void finishKeyEvent(KeyEvent event, boolean sendDone, boolean handled) { if (sendDone) { finishInputEvent(handled); finishInputEvent(event, handled); } } Loading Loading @@ -3262,16 +3373,19 @@ public final class ViewRoot extends Handler implements ViewParent, sendMessage(msg); } private long mInputEventReceiveTimeNanos; private long mInputEventDeliverTimeNanos; private long mInputEventDeliverPostImeTimeNanos; private InputQueue.FinishedCallback mFinishedCallback; private final InputHandler mInputHandler = new InputHandler() { public void handleKey(KeyEvent event, InputQueue.FinishedCallback finishedCallback) { startInputEvent(finishedCallback); startInputEvent(event, finishedCallback); dispatchKey(event, true); } public void handleMotion(MotionEvent event, InputQueue.FinishedCallback finishedCallback) { startInputEvent(finishedCallback); startInputEvent(event, finishedCallback); dispatchMotion(event, true); } }; Loading