Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 72295640 authored by Pascal Mütschard's avatar Pascal Mütschard Committed by Android (Google) Code Review
Browse files

Merge "Some code cleanup of InteractionJankMonitor." into main

parents f6b17da3 6c8bd65c
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -20,8 +20,8 @@ import static android.view.InsetsController.ANIMATION_TYPE_HIDE;
import static android.view.InsetsController.ANIMATION_TYPE_SHOW;

import static com.android.internal.inputmethod.InputMethodDebug.softInputDisplayReasonToString;
import static com.android.internal.jank.InteractionJankMonitor.CUJ_IME_INSETS_HIDE_ANIMATION;
import static com.android.internal.jank.InteractionJankMonitor.CUJ_IME_INSETS_SHOW_ANIMATION;
import static com.android.internal.jank.Cuj.CUJ_IME_INSETS_HIDE_ANIMATION;
import static com.android.internal.jank.Cuj.CUJ_IME_INSETS_SHOW_ANIMATION;
import static com.android.internal.util.LatencyTracker.ACTION_REQUEST_IME_HIDDEN;
import static com.android.internal.util.LatencyTracker.ACTION_REQUEST_IME_SHOWN;

@@ -758,7 +758,7 @@ public interface ImeTracker {
         * A helper method to translate animation type to CUJ type for IME animations.
         *
         * @param animType the animation type.
         * @return the integer in {@link com.android.internal.jank.InteractionJankMonitor.CujType},
         * @return the integer in {@link com.android.internal.jank.Cuj.CujType},
         * or {@code -1} if the animation type is not supported for tracking yet.
         */
        private static int getImeInsetsCujFromAnimation(@AnimationType int animType) {
+503 −0

File added.

Preview size limit exceeded, changes collapsed.

+53 −98
Original line number Diff line number Diff line
@@ -53,7 +53,6 @@ import android.view.WindowCallbacks;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.jank.DisplayRefreshRate.RefreshRate;
import com.android.internal.jank.InteractionJankMonitor.Configuration;
import com.android.internal.jank.InteractionJankMonitor.Session;
import com.android.internal.util.FrameworkStatsLog;

import java.lang.annotation.Retention;
@@ -67,7 +66,6 @@ import java.util.concurrent.TimeUnit;
public class FrameTracker extends SurfaceControl.OnJankDataListener
        implements HardwareRendererObserver.OnFrameMetricsAvailableListener {
    private static final String TAG = "FrameTracker";
    private static final boolean DEBUG = false;

    private static final long INVALID_ID = -1;
    public static final int NANOS_IN_MILLISECOND = 1_000_000;
@@ -93,20 +91,19 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
            REASON_CANCEL_NORMAL,
            REASON_CANCEL_NOT_BEGUN,
            REASON_CANCEL_SAME_VSYNC,
            REASON_CANCEL_TIMEOUT,
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface Reasons {
    }

    @VisibleForTesting
    public final InteractionJankMonitor mMonitor;
    private final HardwareRendererObserver mObserver;
    private final int mTraceThresholdMissedFrames;
    private final int mTraceThresholdFrameTimeMillis;
    private final ThreadedRendererWrapper mRendererWrapper;
    private final FrameMetricsWrapper mMetricsWrapper;
    private final SparseArray<JankInfo> mJankInfos = new SparseArray<>();
    private final Session mSession;
    private final Configuration mConfig;
    private final ViewRootWrapper mViewRoot;
    private final SurfaceControlWrapper mSurfaceControlWrapper;
    private final int mDisplayId;
@@ -197,19 +194,18 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
        }
    }

    public FrameTracker(@NonNull InteractionJankMonitor monitor, @NonNull Session session,
            @NonNull Handler handler, @Nullable ThreadedRendererWrapper renderer,
    public FrameTracker(@NonNull Configuration config,
            @Nullable ThreadedRendererWrapper renderer,
            @Nullable ViewRootWrapper viewRootWrapper,
            @NonNull SurfaceControlWrapper surfaceControlWrapper,
            @NonNull ChoreographerWrapper choreographer,
            @Nullable FrameMetricsWrapper metrics,
            @NonNull StatsLogWrapper statsLog,
            int traceThresholdMissedFrames, int traceThresholdFrameTimeMillis,
            @Nullable FrameTrackerListener listener, @NonNull Configuration config) {
        mMonitor = monitor;
            @Nullable FrameTrackerListener listener) {
        mSurfaceOnly = config.isSurfaceOnly();
        mSession = session;
        mHandler = handler;
        mConfig = config;
        mHandler = config.getHandler();
        mChoreographer = choreographer;
        mSurfaceControlWrapper = surfaceControlWrapper;
        mStatsLog = statsLog;
@@ -222,7 +218,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
        mObserver = mSurfaceOnly
                ? null
                : new HardwareRendererObserver(this, mMetricsWrapper.getTiming(),
                        handler, /* waitForPresentTime= */ false);
                        mHandler, /* waitForPresentTime= */ false);

        mTraceThresholdMissedFrames = traceThresholdMissedFrames;
        mTraceThresholdFrameTimeMillis = traceThresholdFrameTimeMillis;
@@ -242,7 +238,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
            mSurfaceChangedCallback = new ViewRootImpl.SurfaceChangedCallback() {
                @Override
                public void surfaceCreated(SurfaceControl.Transaction t) {
                    getHandler().runWithScissors(() -> {
                    mHandler.runWithScissors(() -> {
                        if (mSurfaceControl == null) {
                            mSurfaceControl = mViewRoot.getSurfaceControl();
                            if (mBeginVsyncId != INVALID_ID) {
@@ -262,13 +258,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener

                    // Wait a while to give the system a chance for the remaining
                    // frames to arrive, then force finish the session.
                    getHandler().postDelayed(() -> {
                        if (DEBUG) {
                            Log.d(TAG, "surfaceDestroyed: " + mSession.getName()
                                    + ", finalized=" + mMetricsFinalized
                                    + ", info=" + mJankInfos.size()
                                    + ", vsync=" + mBeginVsyncId);
                        }
                    mHandler.postDelayed(() -> {
                        if (!mMetricsFinalized) {
                            end(REASON_END_SURFACE_DESTROYED);
                            finish();
@@ -282,11 +272,6 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
        }
    }

    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
    public Handler getHandler() {
        return mHandler;
    }

    /**
     * Begin a trace session of the CUJ.
     */
@@ -300,10 +285,6 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
            mBeginVsyncId = mDeferMonitoring ? currentVsync + 1 : currentVsync;
        }
        if (mSurfaceControl != null) {
            if (DEBUG) {
                Log.d(TAG, "begin: " + mSession.getName() + ", begin=" + mBeginVsyncId
                        + ", defer=" + mDeferMonitoring + ", current=" + currentVsync);
            }
            if (mDeferMonitoring && currentVsync < mBeginVsyncId) {
                markEvent("FT#deferMonitoring", 0);
                // Normal case, we begin the instrument from the very beginning,
@@ -314,11 +295,6 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
                // there is no need to skip the frame where the begin invocation happens.
                beginInternal();
            }
        } else {
            if (DEBUG) {
                Log.d(TAG, "begin: defer beginning since the surface is not ready for CUJ="
                        + mSession.getName());
            }
        }
    }

@@ -336,8 +312,8 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
            return;
        }
        mTracingStarted = true;
        Trace.asyncTraceForTrackBegin(Trace.TRACE_TAG_APP, mSession.getName(), mSession.getName(),
                (int) mBeginVsyncId);
        String name = mConfig.getSessionName();
        Trace.asyncTraceForTrackBegin(Trace.TRACE_TAG_APP, name, name, (int) mBeginVsyncId);
        markEvent("FT#beginVsync", mBeginVsyncId);
        markEvent("FT#layerId", mSurfaceControl.getLayerId());
        mSurfaceControlWrapper.addJankStatsListener(this, mSurfaceControl);
@@ -361,15 +337,10 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
        } else if (mEndVsyncId <= mBeginVsyncId) {
            return cancel(REASON_CANCEL_SAME_VSYNC);
        } else {
            if (DEBUG) {
                Log.d(TAG, "end: " + mSession.getName()
                        + ", end=" + mEndVsyncId + ", reason=" + reason);
            }
            final String name = mConfig.getSessionName();
            markEvent("FT#end", reason);
            markEvent("FT#endVsync", mEndVsyncId);
            Trace.asyncTraceForTrackEnd(Trace.TRACE_TAG_APP, mSession.getName(),
                    (int) mBeginVsyncId);
            mSession.setReason(reason);
            Trace.asyncTraceForTrackEnd(Trace.TRACE_TAG_APP, name, (int) mBeginVsyncId);

            // We don't remove observer here,
            // will remove it when all the frame metrics in this duration are called back.
@@ -395,16 +366,16 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
                        mFlushAttempts++;
                    } else {
                        mWaitForFinishTimedOut = () -> {
                            Log.e(TAG, "force finish cuj, time out: " + mSession.getName());
                            Log.e(TAG, "force finish cuj, time out: " + name);
                            finish();
                        };
                        delay = TimeUnit.SECONDS.toMillis(10);
                    }
                    getHandler().postDelayed(mWaitForFinishTimedOut, delay);
                    mHandler.postDelayed(mWaitForFinishTimedOut, delay);
                }
            };
            getHandler().postDelayed(mWaitForFinishTimedOut, FLUSH_DELAY_MILLISECOND);
            notifyCujEvent(ACTION_SESSION_END);
            mHandler.postDelayed(mWaitForFinishTimedOut, FLUSH_DELAY_MILLISECOND);
            notifyCujEvent(ACTION_SESSION_END, reason);
            return true;
        }
    }
@@ -421,22 +392,16 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
        markEvent("FT#cancel", reason);
        // We don't need to end the trace section if it has never begun.
        if (mTracingStarted) {
            Trace.asyncTraceForTrackEnd(Trace.TRACE_TAG_APP, mSession.getName(),
                    (int) mBeginVsyncId);
            Trace.asyncTraceForTrackEnd(
                    Trace.TRACE_TAG_APP, mConfig.getSessionName(), (int) mBeginVsyncId);
        }

        // Always remove the observers in cancel call to avoid leakage.
        removeObservers();

        if (DEBUG) {
            Log.d(TAG, "cancel: " + mSession.getName() + ", begin=" + mBeginVsyncId
                    + ", end=" + mEndVsyncId + ", reason=" + reason);
        }

        mSession.setReason(reason);
        // Notify the listener the session has been cancelled.
        // We don't notify the listeners if the session never begun.
        notifyCujEvent(ACTION_SESSION_CANCEL);
        notifyCujEvent(ACTION_SESSION_CANCEL, reason);
        return true;
    }

@@ -455,13 +420,13 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
                        "The length of the trace event description <%s> exceeds %d",
                        event, MAX_LENGTH_EVENT_DESC));
            }
            Trace.instantForTrack(Trace.TRACE_TAG_APP, mSession.getName(), event);
            Trace.instantForTrack(Trace.TRACE_TAG_APP, mConfig.getSessionName(), event);
        }
    }

    private void notifyCujEvent(String action) {
    private void notifyCujEvent(String action, @Reasons int reason) {
        if (mListener == null) return;
        mListener.onCujEvents(mSession, action);
        mListener.onCujEvents(this, action, reason);
    }

    @Override
@@ -496,7 +461,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
     */
    @VisibleForTesting
    public void postCallback(Runnable callback) {
        getHandler().post(callback);
        mHandler.post(callback);
    }

    @Nullable
@@ -587,13 +552,15 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
        if (mMetricsFinalized || mCancelled) return;
        mMetricsFinalized = true;

        getHandler().removeCallbacks(mWaitForFinishTimedOut);
        mHandler.removeCallbacks(mWaitForFinishTimedOut);
        mWaitForFinishTimedOut = null;
        markEvent("FT#finish", mJankInfos.size());

        // The tracing has been ended, remove the observer, see if need to trigger perfetto.
        removeObservers();

        final String name = mConfig.getSessionName();

        int totalFramesCount = 0;
        long maxFrameTimeNanos = 0;
        int missedFramesCount = 0;
@@ -616,7 +583,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
                totalFramesCount++;
                boolean missedFrame = false;
                if ((info.jankType & JANK_APP_DEADLINE_MISSED) != 0) {
                    Log.w(TAG, "Missed App frame:" + info + ", CUJ=" + mSession.getName());
                    Log.w(TAG, "Missed App frame:" + info + ", CUJ=" + name);
                    missedAppFramesCount++;
                    missedFrame = true;
                }
@@ -625,7 +592,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
                        || (info.jankType & JANK_SURFACEFLINGER_GPU_DEADLINE_MISSED) != 0
                        || (info.jankType & SURFACE_FLINGER_SCHEDULING) != 0
                        || (info.jankType & PREDICTION_ERROR) != 0) {
                    Log.w(TAG, "Missed SF frame:" + info + ", CUJ=" + mSession.getName());
                    Log.w(TAG, "Missed SF frame:" + info + ", CUJ=" + name);
                    missedSfFramesCount++;
                    missedFrame = true;
                }
@@ -646,7 +613,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
                if (!mSurfaceOnly && !info.hwuiCallbackFired) {
                    markEvent("FT#MissedHWUICallback", info.frameVsyncId);
                    Log.w(TAG, "Missing HWUI jank callback for vsyncId: " + info.frameVsyncId
                            + ", CUJ=" + mSession.getName());
                            + ", CUJ=" + name);
                }
            }
            if (!mSurfaceOnly && info.hwuiCallbackFired) {
@@ -654,7 +621,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
                if (!info.surfaceControlCallbackFired) {
                    markEvent("FT#MissedSFCallback", info.frameVsyncId);
                    Log.w(TAG, "Missing SF jank callback for vsyncId: " + info.frameVsyncId
                            + ", CUJ=" + mSession.getName());
                            + ", CUJ=" + name);
                }
            }
        }
@@ -662,29 +629,26 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
                maxSuccessiveMissedFramesCount, successiveMissedFramesCount);

        // Log the frame stats as counters to make them easily accessible in traces.
        Trace.traceCounter(Trace.TRACE_TAG_APP, mSession.getName() + "#missedFrames",
                missedFramesCount);
        Trace.traceCounter(Trace.TRACE_TAG_APP, mSession.getName() + "#missedAppFrames",
                missedAppFramesCount);
        Trace.traceCounter(Trace.TRACE_TAG_APP, mSession.getName() + "#missedSfFrames",
                missedSfFramesCount);
        Trace.traceCounter(Trace.TRACE_TAG_APP, mSession.getName() + "#totalFrames",
                totalFramesCount);
        Trace.traceCounter(Trace.TRACE_TAG_APP, mSession.getName() + "#maxFrameTimeMillis",
        Trace.traceCounter(Trace.TRACE_TAG_APP, name + "#missedFrames", missedFramesCount);
        Trace.traceCounter(Trace.TRACE_TAG_APP, name + "#missedAppFrames", missedAppFramesCount);
        Trace.traceCounter(Trace.TRACE_TAG_APP, name + "#missedSfFrames", missedSfFramesCount);
        Trace.traceCounter(Trace.TRACE_TAG_APP, name + "#totalFrames", totalFramesCount);
        Trace.traceCounter(Trace.TRACE_TAG_APP, name + "#maxFrameTimeMillis",
                (int) (maxFrameTimeNanos / NANOS_IN_MILLISECOND));
        Trace.traceCounter(Trace.TRACE_TAG_APP, mSession.getName() + "#maxSuccessiveMissedFrames",
        Trace.traceCounter(Trace.TRACE_TAG_APP, name + "#maxSuccessiveMissedFrames",
                maxSuccessiveMissedFramesCount);

        // Trigger perfetto if necessary.
        if (shouldTriggerPerfetto(missedFramesCount, (int) maxFrameTimeNanos)) {
            triggerPerfetto();
        if (mListener != null
                && shouldTriggerPerfetto(missedFramesCount, (int) maxFrameTimeNanos)) {
            mListener.triggerPerfetto(mConfig);
        }
        if (mSession.logToStatsd()) {
        if (mConfig.logToStatsd()) {
            mStatsLog.write(
                    FrameworkStatsLog.UI_INTERACTION_FRAME_INFO_REPORTED,
                    mDisplayId,
                    refreshRate,
                    mSession.getStatsdInteractionType(),
                    mConfig.getStatsdInteractionType(),
                    totalFramesCount,
                    missedFramesCount,
                    maxFrameTimeNanos, /* will be 0 if mSurfaceOnly == true */
@@ -692,16 +656,6 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
                    missedAppFramesCount,
                    maxSuccessiveMissedFramesCount);
        }
        if (DEBUG) {
            Log.i(TAG, "finish: CUJ=" + mSession.getName()
                    + " (" + mBeginVsyncId + "," + mEndVsyncId + ")"
                    + " totalFrames=" + totalFramesCount
                    + " missedAppFrames=" + missedAppFramesCount
                    + " missedSfFrames=" + missedSfFramesCount
                    + " missedFrames=" + missedFramesCount
                    + " maxFrameTimeMillis=" + maxFrameTimeNanos / NANOS_IN_MILLISECOND
                    + " maxSuccessiveMissedFramesCount=" + maxSuccessiveMissedFramesCount);
        }
    }

    ThreadedRendererWrapper getThreadedRenderer() {
@@ -736,13 +690,6 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
        }
    }

    /**
     * Trigger the prefetto daemon.
     */
    public void triggerPerfetto() {
        mMonitor.trigger(mSession);
    }

    /**
     * A wrapper class that we can spy FrameMetrics (a final class) in unit tests.
     */
@@ -895,9 +842,17 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
        /**
         * Notify that the CUJ session was created.
         *
         * @param session the CUJ session
         * @param tracker the tracker
         * @param action the specific action
         * @param reason the reason for the action
         */
        void onCujEvents(FrameTracker tracker, String action, @Reasons int reason);

        /**
         * Notify that the Perfetto trace should be triggered.
         *
         * @param config the tracker configuration
         */
        void onCujEvents(Session session, String action);
        void triggerPerfetto(Configuration config);
    }
}
+273 −839

File changed.

Preview size limit exceeded, changes collapsed.

+45 −42
Original line number Diff line number Diff line
@@ -34,7 +34,6 @@ import android.view.WindowCallbacks;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.jank.FrameTracker.Reasons;
import com.android.internal.jank.InteractionJankMonitor.CujType;

/**
 * An overlay that uses WindowCallbacks to draw the names of all running CUJs to the window
@@ -94,14 +93,14 @@ class InteractionMonitorDebugOverlay implements WindowCallbacks {
    }

    @UiThread
    private boolean attachViewRootIfNeeded(FrameTracker tracker) {
        FrameTracker.ViewRootWrapper viewRoot = tracker.getViewRoot();
    private boolean attachViewRootIfNeeded(InteractionJankMonitor.RunningTracker tracker) {
        FrameTracker.ViewRootWrapper viewRoot = tracker.mTracker.getViewRoot();
        if (mViewRoot == null && viewRoot != null) {
            // Add a trace marker so we can identify traces that were captured while the debug
            // overlay was enabled. Traces that use the debug overlay should NOT be used for
            // performance analysis.
            Trace.asyncTraceForTrackBegin(Trace.TRACE_TAG_APP, TRACK_NAME, "DEBUG_OVERLAY_DRAW", 0);
            mHandler = tracker.getHandler();
            mHandler = tracker.mConfig.getHandler();
            mViewRoot = viewRoot;
            mHandler.runWithScissors(() -> viewRoot.addWindowCallbacks(this),
                    InteractionJankMonitor.EXECUTOR_TASK_TIMEOUT);
@@ -111,11 +110,12 @@ class InteractionMonitorDebugOverlay implements WindowCallbacks {
        return false;
    }

    @GuardedBy("mLock")
    private float getWidthOfLongestCujName(int cujFontSize) {
        mDebugPaint.setTextSize(cujFontSize);
        float maxLength = 0;
        for (int i = 0; i < mRunningCujs.size(); i++) {
            String cujName = InteractionJankMonitor.getNameOfCuj(mRunningCujs.keyAt(i));
            String cujName = Cuj.getNameOfCuj(mRunningCujs.keyAt(i));
            float textLength = mDebugPaint.measureText(cujName);
            if (textLength > maxLength) {
                maxLength = textLength;
@@ -149,8 +149,8 @@ class InteractionMonitorDebugOverlay implements WindowCallbacks {
    }

    @UiThread
    void onTrackerRemoved(@CujType int removedCuj, @Reasons int reason,
                          SparseArray<FrameTracker> runningTrackers) {
    void onTrackerRemoved(@Cuj.CujType int removedCuj, @Reasons int reason,
                          SparseArray<InteractionJankMonitor.RunningTracker> runningTrackers) {
        synchronized (mLock) {
            mRunningCujs.put(removedCuj, reason);
            // If REASON_STILL_RUNNING is not in mRunningCujs, then all CUJs have ended
@@ -164,7 +164,7 @@ class InteractionMonitorDebugOverlay implements WindowCallbacks {
                    // trackers
                    for (int i = 0; i < runningTrackers.size(); i++) {
                        if (mViewRoot.equals(
                                runningTrackers.valueAt(i).getViewRoot())) {
                                runningTrackers.valueAt(i).mTracker.getViewRoot())) {
                            needsNewViewRoot = false;
                            break;
                        }
@@ -185,7 +185,7 @@ class InteractionMonitorDebugOverlay implements WindowCallbacks {
    }

    @UiThread
    void onTrackerAdded(@CujType int addedCuj, FrameTracker tracker) {
    void onTrackerAdded(@Cuj.CujType int addedCuj, InteractionJankMonitor.RunningTracker tracker) {
        synchronized (mLock) {
            // Use REASON_STILL_RUNNING (not technically one of the '@Reasons') to indicate the CUJ
            // is still running
@@ -230,6 +230,8 @@ class InteractionMonitorDebugOverlay implements WindowCallbacks {
        int cujFontSize = dipToPx(18);
        final float cujNameTextHeight = getTextHeight(cujFontSize);
        final float packageNameTextHeight = getTextHeight(packageNameFontSize);

        synchronized (mLock) {
            float maxLength = getWidthOfLongestCujName(cujFontSize);

            final int dx = (int) ((w - maxLength) / 2f);
@@ -262,9 +264,10 @@ class InteractionMonitorDebugOverlay implements WindowCallbacks {
                    mDebugPaint.setColor(Color.RED);
                    mDebugPaint.setStrikeThruText(true);
                }
            String cujName = InteractionJankMonitor.getNameOfCuj(mRunningCujs.keyAt(i));
                String cujName = Cuj.getNameOfCuj(mRunningCujs.keyAt(i));
                canvas.translate(0, cujNameTextHeight);
                canvas.drawText(cujName, 0, 0, mDebugPaint);
            }
        }
    }
}
Loading