diff options
| author | Wu Ahan <ahanwu@google.com> | 2021-08-02 10:23:59 +0000 |
|---|---|---|
| committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2021-08-02 10:23:59 +0000 |
| commit | 60894eefb5022e1706b02a79f6cb5557ed0f8730 (patch) | |
| tree | e8303338d11c64bfd6f23f0a5b9aec23b6a2bd54 /core/java | |
| parent | 5fb80acea55a8bf619087996252ab8569907cc87 (diff) | |
| parent | d6d30bf7f6051371f5495438bae63aa1c68a4edc (diff) | |
Merge "Support surface only instrumentation" into sc-v2-dev am: d6d30bf7f6
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/15256893
Change-Id: I78d98f78086ace09d32fac4329c6b3357aed56b5
Diffstat (limited to 'core/java')
| -rw-r--r-- | core/java/com/android/internal/jank/FrameTracker.java | 159 | ||||
| -rw-r--r-- | core/java/com/android/internal/jank/InteractionJankMonitor.java | 229 |
2 files changed, 277 insertions, 111 deletions
diff --git a/core/java/com/android/internal/jank/FrameTracker.java b/core/java/com/android/internal/jank/FrameTracker.java index 8e7fae7aa061..aa7142eaa39d 100644 --- a/core/java/com/android/internal/jank/FrameTracker.java +++ b/core/java/com/android/internal/jank/FrameTracker.java @@ -45,6 +45,7 @@ import android.view.ThreadedRenderer; import android.view.ViewRootImpl; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.jank.InteractionJankMonitor.Configuration; import com.android.internal.jank.InteractionJankMonitor.Session; import com.android.internal.util.FrameworkStatsLog; @@ -69,6 +70,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener static final int REASON_CANCEL_NORMAL = 16; static final int REASON_CANCEL_NOT_BEGUN = 17; static final int REASON_CANCEL_SAME_VSYNC = 18; + static final int REASON_CANCEL_TIMEOUT = 19; /** @hide */ @IntDef({ @@ -97,6 +99,9 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener private final Handler mHandler; private final ChoreographerWrapper mChoreographer; + @VisibleForTesting + public final boolean mSurfaceOnly; + private long mBeginVsyncId = INVALID_ID; private long mEndVsyncId = INVALID_ID; private boolean mMetricsFinalized; @@ -136,71 +141,86 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener } public FrameTracker(@NonNull Session session, @NonNull Handler handler, - @NonNull ThreadedRendererWrapper renderer, @NonNull ViewRootWrapper viewRootWrapper, + @Nullable ThreadedRendererWrapper renderer, @Nullable ViewRootWrapper viewRootWrapper, @NonNull SurfaceControlWrapper surfaceControlWrapper, @NonNull ChoreographerWrapper choreographer, - @NonNull FrameMetricsWrapper metrics, int traceThresholdMissedFrames, - int traceThresholdFrameTimeMillis, @Nullable FrameTrackerListener listener) { + @Nullable FrameMetricsWrapper metrics, + int traceThresholdMissedFrames, int traceThresholdFrameTimeMillis, + @Nullable FrameTrackerListener listener, @NonNull Configuration config) { + mSurfaceOnly = config.isSurfaceOnly(); mSession = session; - mRendererWrapper = renderer; - mMetricsWrapper = metrics; - mViewRoot = viewRootWrapper; + mHandler = handler; mChoreographer = choreographer; mSurfaceControlWrapper = surfaceControlWrapper; - mHandler = handler; - mObserver = new HardwareRendererObserver( - this, mMetricsWrapper.getTiming(), handler, false /*waitForPresentTime*/); + + // HWUI instrumentation init. + mRendererWrapper = mSurfaceOnly ? null : renderer; + mMetricsWrapper = mSurfaceOnly ? null : metrics; + mViewRoot = mSurfaceOnly ? null : viewRootWrapper; + mObserver = mSurfaceOnly + ? null + : new HardwareRendererObserver(this, mMetricsWrapper.getTiming(), + handler, /* waitForPresentTime= */ false); + mTraceThresholdMissedFrames = traceThresholdMissedFrames; mTraceThresholdFrameTimeMillis = traceThresholdFrameTimeMillis; mListener = listener; - // If the surface isn't valid yet, wait until it's created. - if (viewRootWrapper.getSurfaceControl().isValid()) { - mSurfaceControl = viewRootWrapper.getSurfaceControl(); - } - mSurfaceChangedCallback = new ViewRootImpl.SurfaceChangedCallback() { - @Override - public void surfaceCreated(SurfaceControl.Transaction t) { - synchronized (FrameTracker.this) { - if (mSurfaceControl == null) { - mSurfaceControl = viewRootWrapper.getSurfaceControl(); - if (mBeginVsyncId != INVALID_ID) { - mSurfaceControlWrapper.addJankStatsListener( - FrameTracker.this, mSurfaceControl); - postTraceStartMarker(); + if (mSurfaceOnly) { + mSurfaceControl = config.getSurfaceControl(); + mSurfaceChangedCallback = null; + } else { + // HWUI instrumentation init. + // If the surface isn't valid yet, wait until it's created. + if (mViewRoot.getSurfaceControl().isValid()) { + mSurfaceControl = mViewRoot.getSurfaceControl(); + mSurfaceChangedCallback = null; + } else { + mSurfaceChangedCallback = new ViewRootImpl.SurfaceChangedCallback() { + @Override + public void surfaceCreated(SurfaceControl.Transaction t) { + synchronized (FrameTracker.this) { + if (mSurfaceControl == null) { + mSurfaceControl = mViewRoot.getSurfaceControl(); + if (mBeginVsyncId != INVALID_ID) { + mSurfaceControlWrapper.addJankStatsListener( + FrameTracker.this, mSurfaceControl); + postTraceStartMarker(); + } + } } } - } - } - @Override - public void surfaceReplaced(SurfaceControl.Transaction t) { - } + @Override + public void surfaceReplaced(SurfaceControl.Transaction t) { + } - @Override - public void surfaceDestroyed() { - - // Wait a while to give the system a chance for the remaining frames to arrive, then - // force finish the session. - mHandler.postDelayed(() -> { - synchronized (FrameTracker.this) { - if (DEBUG) { - Log.d(TAG, "surfaceDestroyed: " + mSession.getName() - + ", finalized=" + mMetricsFinalized - + ", info=" + mJankInfos.size() - + ", vsync=" + mBeginVsyncId + "-" + mEndVsyncId); - } - if (!mMetricsFinalized) { - end(REASON_END_SURFACE_DESTROYED); - finish(mJankInfos.size() - 1); - } + @Override + public void surfaceDestroyed() { + + // Wait a while to give the system a chance for the remaining + // frames to arrive, then force finish the session. + mHandler.postDelayed(() -> { + synchronized (FrameTracker.this) { + if (DEBUG) { + Log.d(TAG, "surfaceDestroyed: " + mSession.getName() + + ", finalized=" + mMetricsFinalized + + ", info=" + mJankInfos.size() + + ", vsync=" + mBeginVsyncId + "-" + mEndVsyncId); + } + if (!mMetricsFinalized) { + end(REASON_END_SURFACE_DESTROYED); + finish(mJankInfos.size() - 1); + } + } + }, 50); } - }, 50); + }; + // This callback has a reference to FrameTracker, + // remember to remove it to avoid leakage. + mViewRoot.addSurfaceChangedCallback(mSurfaceChangedCallback); } - }; - - // This callback has a reference to FrameTracker, remember to remove it to avoid leakage. - viewRootWrapper.addSurfaceChangedCallback(mSurfaceChangedCallback); + } } /** @@ -208,16 +228,16 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener */ public synchronized void begin() { mBeginVsyncId = mChoreographer.getVsyncId() + 1; - if (mSurfaceControl != null) { - postTraceStartMarker(); - } - mRendererWrapper.addObserver(mObserver); if (DEBUG) { Log.d(TAG, "begin: " + mSession.getName() + ", begin=" + mBeginVsyncId); } if (mSurfaceControl != null) { + postTraceStartMarker(); mSurfaceControlWrapper.addJankStatsListener(this, mSurfaceControl); } + if (!mSurfaceOnly) { + mRendererWrapper.addObserver(mObserver); + } if (mListener != null) { mListener.onCujEvents(mSession, ACTION_SESSION_BEGIN); } @@ -273,11 +293,12 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener * Cancel the trace session of the CUJ. */ public synchronized void cancel(@Reasons int reason) { + mCancelled = true; + // We don't need to end the trace section if it never begun. if (mTracingStarted) { Trace.endAsyncSection(mSession.getName(), (int) mBeginVsyncId); } - mCancelled = true; // Always remove the observers in cancel call to avoid leakage. removeObservers(); @@ -377,7 +398,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener for (int i = mJankInfos.size() - 1; i >= 0; i--) { JankInfo info = mJankInfos.valueAt(i); if (info.frameVsyncId >= mEndVsyncId) { - if (info.hwuiCallbackFired && info.surfaceControlCallbackFired) { + if (isLastIndexCandidate(info)) { lastIndex = i; } } else { @@ -395,6 +416,12 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener finish(indexOnOrAfterEnd); } + private boolean isLastIndexCandidate(JankInfo info) { + return mSurfaceOnly + ? info.surfaceControlCallbackFired + : info.hwuiCallbackFired && info.surfaceControlCallbackFired; + } + private void finish(int indexOnOrAfterEnd) { mMetricsFinalized = true; @@ -410,7 +437,8 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener for (int i = 0; i <= indexOnOrAfterEnd; i++) { JankInfo info = mJankInfos.valueAt(i); - if (info.isFirstFrame) { + final boolean isFirstDrawn = !mSurfaceOnly && info.isFirstFrame; + if (isFirstDrawn) { continue; } if (info.surfaceControlCallbackFired) { @@ -435,11 +463,11 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener } // TODO (b/174755489): Early latch currently gets fired way too often, so we have // to ignore it for now. - if (!info.hwuiCallbackFired) { + if (!mSurfaceOnly && !info.hwuiCallbackFired) { Log.w(TAG, "Missing HWUI jank callback for vsyncId: " + info.frameVsyncId); } } - if (info.hwuiCallbackFired) { + if (!mSurfaceOnly && info.hwuiCallbackFired) { maxFrameTimeNanos = Math.max(info.totalDurationNanos, maxFrameTimeNanos); if (!info.surfaceControlCallbackFired) { Log.w(TAG, "Missing SF jank callback for vsyncId: " + info.frameVsyncId); @@ -462,7 +490,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener // Trigger perfetto if necessary. boolean overMissedFramesThreshold = mTraceThresholdMissedFrames != -1 && missedFramesCount >= mTraceThresholdMissedFrames; - boolean overFrameTimeThreshold = mTraceThresholdFrameTimeMillis != -1 + boolean overFrameTimeThreshold = !mSurfaceOnly && mTraceThresholdFrameTimeMillis != -1 && maxFrameTimeNanos >= mTraceThresholdFrameTimeMillis * NANOS_IN_MILLISECOND; if (overMissedFramesThreshold || overFrameTimeThreshold) { triggerPerfetto(); @@ -473,7 +501,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener mSession.getStatsdInteractionType(), totalFramesCount, missedFramesCount, - maxFrameTimeNanos, + maxFrameTimeNanos, /* will be 0 if mSurfaceOnly == true */ missedSfFramesCount, missedAppFramesCount); if (mListener != null) { @@ -496,10 +524,13 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener */ @VisibleForTesting public void removeObservers() { - mRendererWrapper.removeObserver(mObserver); mSurfaceControlWrapper.removeJankStatsListener(this); - if (mSurfaceChangedCallback != null) { - mViewRoot.removeSurfaceChangedCallback(mSurfaceChangedCallback); + if (!mSurfaceOnly) { + // HWUI part. + mRendererWrapper.removeObserver(mObserver); + if (mSurfaceChangedCallback != null) { + mViewRoot.removeSurfaceChangedCallback(mSurfaceChangedCallback); + } } } diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java index aabcd7f82ac7..aae6f5016891 100644 --- a/core/java/com/android/internal/jank/InteractionJankMonitor.java +++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java @@ -18,11 +18,11 @@ package com.android.internal.jank; import static android.content.Intent.FLAG_RECEIVER_REGISTERED_ONLY; -import static com.android.internal.jank.FrameTracker.ChoreographerWrapper; import static com.android.internal.jank.FrameTracker.REASON_CANCEL_NORMAL; import static com.android.internal.jank.FrameTracker.REASON_CANCEL_NOT_BEGUN; +import static com.android.internal.jank.FrameTracker.REASON_CANCEL_TIMEOUT; import static com.android.internal.jank.FrameTracker.REASON_END_NORMAL; -import static com.android.internal.jank.FrameTracker.SurfaceControlWrapper; +import static com.android.internal.jank.FrameTracker.REASON_END_UNKNOWN; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_ALL_APPS_SCROLL; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_CLOSE_TO_HOME; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_CLOSE_TO_PIP; @@ -41,6 +41,7 @@ import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_IN import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_TRANSITION_TO_AOD; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_UNLOCK_ANIMATION; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__NOTIFICATION_SHADE_SWIPE; +import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__PIP_TRANSITION; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SETTINGS_PAGE_SCROLL; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_APP_LAUNCH; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_APP_LAUNCH_FROM_HISTORY_BUTTON; @@ -58,6 +59,7 @@ import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_IN import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_ROW_SWIPE; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_SCROLL_FLING; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__STATUS_BAR_APP_LAUNCH_FROM_CALL_CHIP; +import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__WALLPAPER_TRANSITION; import android.annotation.IntDef; import android.annotation.NonNull; @@ -72,11 +74,15 @@ import android.text.TextUtils; import android.util.Log; import android.util.SparseArray; import android.view.Choreographer; +import android.view.SurfaceControl; import android.view.View; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.jank.FrameTracker.ChoreographerWrapper; import com.android.internal.jank.FrameTracker.FrameMetricsWrapper; import com.android.internal.jank.FrameTracker.FrameTrackerListener; +import com.android.internal.jank.FrameTracker.Reasons; +import com.android.internal.jank.FrameTracker.SurfaceControlWrapper; import com.android.internal.jank.FrameTracker.ThreadedRendererWrapper; import com.android.internal.jank.FrameTracker.ViewRootWrapper; import com.android.internal.util.PerfettoTrigger; @@ -103,7 +109,7 @@ public class InteractionJankMonitor { private static final String ACTION_PREFIX = InteractionJankMonitor.class.getCanonicalName(); private static final String DEFAULT_WORKER_NAME = TAG + "-Worker"; - private static final long DEFAULT_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(5L); + private static final long DEFAULT_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(2L); private static final String SETTINGS_ENABLED_KEY = "enabled"; private static final String SETTINGS_SAMPLING_INTERVAL_KEY = "sampling_interval"; private static final String SETTINGS_THRESHOLD_MISSED_FRAMES_KEY = @@ -163,6 +169,8 @@ public class InteractionJankMonitor { public static final int CUJ_SHADE_APP_LAUNCH_FROM_QS_TILE = 32; public static final int CUJ_SHADE_APP_LAUNCH_FROM_SETTINGS_BUTTON = 33; public static final int CUJ_STATUS_BAR_APP_LAUNCH_FROM_CALL_CHIP = 34; + public static final int CUJ_PIP_TRANSITION = 35; + public static final int CUJ_WALLPAPER_TRANSITION = 36; private static final int NO_STATSD_LOGGING = -1; @@ -206,6 +214,8 @@ public class InteractionJankMonitor { UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_APP_LAUNCH_FROM_QS_TILE, UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_APP_LAUNCH_FROM_SETTINGS_BUTTON, UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__STATUS_BAR_APP_LAUNCH_FROM_CALL_CHIP, + UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__PIP_TRANSITION, + UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__WALLPAPER_TRANSITION, }; private static volatile InteractionJankMonitor sInstance; @@ -213,10 +223,10 @@ public class InteractionJankMonitor { private final DeviceConfig.OnPropertiesChangedListener mPropertiesChangedListener = this::updateProperties; - private FrameMetricsWrapper mMetrics; - private SparseArray<FrameTracker> mRunningTrackers; - private SparseArray<Runnable> mTimeoutActions; - private HandlerThread mWorker; + private final FrameMetricsWrapper mMetrics; + private final SparseArray<FrameTracker> mRunningTrackers; + private final SparseArray<Runnable> mTimeoutActions; + private final HandlerThread mWorker; private boolean mEnabled = DEFAULT_ENABLED; private int mSamplingInterval = DEFAULT_SAMPLING_INTERVAL; @@ -260,6 +270,8 @@ public class InteractionJankMonitor { CUJ_SHADE_APP_LAUNCH_FROM_QS_TILE, CUJ_SHADE_APP_LAUNCH_FROM_SETTINGS_BUTTON, CUJ_STATUS_BAR_APP_LAUNCH_FROM_CALL_CHIP, + CUJ_PIP_TRANSITION, + CUJ_WALLPAPER_TRANSITION, }) @Retention(RetentionPolicy.SOURCE) public @interface CujType { @@ -310,24 +322,31 @@ public class InteractionJankMonitor { } /** - * Create a {@link FrameTracker} instance. + * Creates a {@link FrameTracker} instance. * + * @param config the config used in instrumenting * @param session the session associates with this tracker * @return instance of the FrameTracker */ @VisibleForTesting - public FrameTracker createFrameTracker(Configuration conf, Session session) { - final View v = conf.mView; - final Context c = v.getContext().getApplicationContext(); - final ThreadedRendererWrapper r = new ThreadedRendererWrapper(v.getThreadedRenderer()); - final ViewRootWrapper vr = new ViewRootWrapper(v.getViewRootImpl()); - final SurfaceControlWrapper sc = new SurfaceControlWrapper(); - final ChoreographerWrapper cg = new ChoreographerWrapper(Choreographer.getInstance()); + public FrameTracker createFrameTracker(Configuration config, Session session) { + final View view = config.mView; + final ThreadedRendererWrapper threadedRenderer = + view == null ? null : new ThreadedRendererWrapper(view.getThreadedRenderer()); + final ViewRootWrapper viewRoot = + view == null ? null : new ViewRootWrapper(view.getViewRootImpl()); + + final SurfaceControlWrapper surfaceControl = new SurfaceControlWrapper(); + final ChoreographerWrapper choreographer = + new ChoreographerWrapper(Choreographer.getInstance()); synchronized (this) { - FrameTrackerListener eventsListener = (s, act) -> handleCujEvents(c, act, s); - return new FrameTracker(session, mWorker.getThreadHandler(), r, vr, sc, cg, mMetrics, - mTraceThresholdMissedFrames, mTraceThresholdFrameTimeMillis, eventsListener); + FrameTrackerListener eventsListener = + (s, act) -> handleCujEvents(config.getContext(), act, s); + return new FrameTracker(session, mWorker.getThreadHandler(), + threadedRenderer, viewRoot, surfaceControl, choreographer, mMetrics, + mTraceThresholdMissedFrames, mTraceThresholdFrameTimeMillis, + eventsListener, config); } } @@ -376,7 +395,7 @@ public class InteractionJankMonitor { } /** - * Begin a trace session. + * Begins a trace session. * * @param v an attached view. * @param cujType the specific {@link InteractionJankMonitor.CujType}. @@ -385,8 +404,7 @@ public class InteractionJankMonitor { public boolean begin(View v, @CujType int cujType) { try { return beginInternal( - new Configuration.Builder(cujType) - .setView(v) + Configuration.Builder.withView(cujType, v) .build()); } catch (IllegalArgumentException ex) { Log.d(TAG, "Build configuration failed!", ex); @@ -395,7 +413,7 @@ public class InteractionJankMonitor { } /** - * Begin a trace session. + * Begins a trace session. * * @param builder the builder of the configurations for instrumenting the CUJ. * @return boolean true if the tracker is started successfully, false otherwise. @@ -431,48 +449,60 @@ public class InteractionJankMonitor { tracker.begin(); // Cancel the trace if we don't get an end() call in specified duration. - Runnable timeoutAction = () -> cancel(cujType); - mTimeoutActions.put(cujType, timeoutAction); - mWorker.getThreadHandler().postDelayed(timeoutAction, conf.mTimeout); + scheduleTimeoutAction( + cujType, conf.mTimeout, () -> cancel(cujType, REASON_CANCEL_TIMEOUT)); return true; } } /** - * End a trace session. + * Schedules a timeout action. + * @param cuj cuj type + * @param timeout duration to timeout + * @param action action once timeout + */ + @VisibleForTesting + public void scheduleTimeoutAction(@CujType int cuj, long timeout, Runnable action) { + mTimeoutActions.put(cuj, action); + mWorker.getThreadHandler().postDelayed(action, timeout); + } + + /** + * Ends a trace session. * * @param cujType the specific {@link InteractionJankMonitor.CujType}. * @return boolean true if the tracker is ended successfully, false otherwise. */ public boolean end(@CujType int cujType) { - //TODO (163505250): This should be no-op if not in droid food rom. synchronized (this) { - // remove the timeout action first. removeTimeout(cujType); FrameTracker tracker = getTracker(cujType); // Skip this call since we haven't started a trace yet. if (tracker == null) return false; - tracker.end(FrameTracker.REASON_END_NORMAL); + tracker.end(REASON_END_NORMAL); removeTracker(cujType); return true; } } /** - * Cancel the trace session. + * Cancels the trace session. * * @return boolean true if the tracker is cancelled successfully, false otherwise. */ public boolean cancel(@CujType int cujType) { - //TODO (163505250): This should be no-op if not in droid food rom. + return cancel(cujType, REASON_CANCEL_NORMAL); + } + + boolean cancel(@CujType int cujType, @Reasons int reason) { synchronized (this) { // remove the timeout action first. removeTimeout(cujType); FrameTracker tracker = getTracker(cujType); // Skip this call since we haven't started a trace yet. if (tracker == null) return false; - tracker.cancel(FrameTracker.REASON_CANCEL_NORMAL); + tracker.cancel(reason); removeTracker(cujType); return true; } @@ -509,7 +539,7 @@ public class InteractionJankMonitor { } /** - * Trigger the perfetto daemon to collect and upload data. + * Triggers the perfetto daemon to collect and upload data. */ @VisibleForTesting public void trigger(Session session) { @@ -608,6 +638,10 @@ public class InteractionJankMonitor { return "SHADE_APP_LAUNCH_FROM_SETTINGS_BUTTON"; case CUJ_STATUS_BAR_APP_LAUNCH_FROM_CALL_CHIP: return "STATUS_BAR_APP_LAUNCH_FROM_CALL_CHIP"; + case CUJ_PIP_TRANSITION: + return "PIP_TRANSITION"; + case CUJ_WALLPAPER_TRANSITION: + return "WALLPAPER_TRANSITION"; } return "UNKNOWN"; } @@ -618,32 +652,64 @@ public class InteractionJankMonitor { */ public static class Configuration { private final View mView; + private final Context mContext; private final long mTimeout; private final String mTag; + private final boolean mSurfaceOnly; + private final SurfaceControl mSurfaceControl; private final @CujType int mCujType; /** - * A builder for building Configuration. <br/> + * A builder for building Configuration. {@link #setView(View)} is essential + * if {@link #setSurfaceOnly(boolean)} is not set, otherwise both + * {@link #setSurfaceControl(SurfaceControl)} and {@link #setContext(Context)} + * are necessary<br/> * <b>It may refer to an attached view, don't use static reference for any purpose.</b> */ public static class Builder { private View mAttrView = null; + private Context mAttrContext = null; private long mAttrTimeout = DEFAULT_TIMEOUT_MS; private String mAttrTag = ""; + private boolean mAttrSurfaceOnly; + private SurfaceControl mAttrSurfaceControl; private @CujType int mAttrCujType; /** + * Creates a builder which instruments only surface. * @param cuj The enum defined in {@link InteractionJankMonitor.CujType}. + * @param context context + * @param surfaceControl surface control + * @return builder */ - public Builder(@CujType int cuj) { + public static Builder withSurface(@CujType int cuj, @NonNull Context context, + @NonNull SurfaceControl surfaceControl) { + return new Builder(cuj) + .setContext(context) + .setSurfaceControl(surfaceControl) + .setSurfaceOnly(true); + } + + /** + * Creates a builder which instruments both surface and view. + * @param cuj The enum defined in {@link InteractionJankMonitor.CujType}. + * @param view view + * @return builder + */ + public static Builder withView(@CujType int cuj, @NonNull View view) { + return new Builder(cuj).setView(view); + } + + private Builder(@CujType int cuj) { mAttrCujType = cuj; } /** + * Specifies a view, must be set if {@link #setSurfaceOnly(boolean)} is set to false. * @param view an attached view * @return builder */ - public Builder setView(@NonNull View view) { + private Builder setView(@NonNull View view) { mAttrView = view; return this; } @@ -669,20 +735,56 @@ public class InteractionJankMonitor { } /** - * Build the {@link Configuration} instance + * Indicates if only instrument with surface, + * if true, must also setup with {@link #setContext(Context)} + * and {@link #setSurfaceControl(SurfaceControl)}. + * @param surfaceOnly true if only instrument with surface, false otherwise + * @return builder Surface only builder. + */ + private Builder setSurfaceOnly(boolean surfaceOnly) { + mAttrSurfaceOnly = surfaceOnly; + return this; + } + + /** + * Specifies a context, must set if {@link #setSurfaceOnly(boolean)} is set. + */ + private Builder setContext(Context context) { + mAttrContext = context; + return this; + } + + /** + * Specifies a surface control, must be set if {@link #setSurfaceOnly(boolean)} is set. + */ + private Builder setSurfaceControl(SurfaceControl surfaceControl) { + mAttrSurfaceControl = surfaceControl; + return this; + } + + /** + * Builds the {@link Configuration} instance * @return the instance of {@link Configuration} * @throws IllegalArgumentException if any invalid attribute is set */ public Configuration build() throws IllegalArgumentException { - return new Configuration(mAttrCujType, mAttrView, mAttrTag, mAttrTimeout); + return new Configuration( + mAttrCujType, mAttrView, mAttrTag, mAttrTimeout, + mAttrSurfaceOnly, mAttrContext, mAttrSurfaceControl); } } - private Configuration(@CujType int cuj, View view, String tag, long timeout) { + private Configuration(@CujType int cuj, View view, String tag, long timeout, + boolean surfaceOnly, Context context, SurfaceControl surfaceControl) { mCujType = cuj; mTag = tag; mTimeout = timeout; mView = view; + mSurfaceOnly = surfaceOnly; + mContext = context != null + ? context + : (view != null ? view.getContext().getApplicationContext() : null); + mSurfaceControl = surfaceControl; validate(); } @@ -698,14 +800,47 @@ public class InteractionJankMonitor { shouldThrow = true; msg.append("Invalid timeout value; "); } - if (mView == null || !mView.isAttachedToWindow()) { - shouldThrow = true; - msg.append("Null view or view is not attached yet; "); + if (mSurfaceOnly) { + if (mContext == null) { + shouldThrow = true; + msg.append("Must pass in a context if only instrument surface; "); + } + if (mSurfaceControl == null || !mSurfaceControl.isValid()) { + shouldThrow = true; + msg.append("Must pass in a valid surface control if only instrument surface; "); + } + } else { + if (mView == null || !mView.isAttachedToWindow()) { + shouldThrow = true; + msg.append("Null view or unattached view while instrumenting view; "); + } } if (shouldThrow) { throw new IllegalArgumentException(msg.toString()); } } + + /** + * @return true if only instrumenting surface, false otherwise + */ + public boolean isSurfaceOnly() { + return mSurfaceOnly; + } + + /** + * @return the surafce control which is instrumenting + */ + public SurfaceControl getSurfaceControl() { + return mSurfaceControl; + } + + View getView() { + return mView; + } + + Context getContext() { + return mContext; + } } /** @@ -715,8 +850,8 @@ public class InteractionJankMonitor { @CujType private final int mCujType; private final long mTimeStamp; - @FrameTracker.Reasons - private int mReason = FrameTracker.REASON_END_UNKNOWN; + @Reasons + private int mReason = REASON_END_UNKNOWN; private final boolean mShouldNotify; private final String mName; @@ -756,15 +891,15 @@ public class InteractionJankMonitor { return mTimeStamp; } - public void setReason(@FrameTracker.Reasons int reason) { + public void setReason(@Reasons int reason) { mReason = reason; } - public int getReason() { + public @Reasons int getReason() { return mReason; } - /** Determine if should notify the receivers of cuj events */ + /** Determines if should notify the receivers of cuj events */ public boolean shouldNotify() { return mShouldNotify; } |
