Merge "Send broadcast to notify the events of a CUJ session" into sc-dev
This commit is contained in:
@@ -25,6 +25,9 @@ import static android.view.SurfaceControl.JankData.JANK_SURFACEFLINGER_GPU_DEADL
|
||||
import static android.view.SurfaceControl.JankData.PREDICTION_ERROR;
|
||||
import static android.view.SurfaceControl.JankData.SURFACE_FLINGER_SCHEDULING;
|
||||
|
||||
import static com.android.internal.jank.InteractionJankMonitor.ACTION_METRICS_LOGGED;
|
||||
import static com.android.internal.jank.InteractionJankMonitor.ACTION_SESSION_BEGIN;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.graphics.HardwareRendererObserver;
|
||||
@@ -72,6 +75,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
|
||||
private long mEndVsyncId = INVALID_ID;
|
||||
private boolean mMetricsFinalized;
|
||||
private boolean mCancelled = false;
|
||||
private FrameTrackerListener mListener;
|
||||
|
||||
private static class JankInfo {
|
||||
long frameVsyncId;
|
||||
@@ -109,7 +113,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
|
||||
@NonNull SurfaceControlWrapper surfaceControlWrapper,
|
||||
@NonNull ChoreographerWrapper choreographer,
|
||||
@NonNull FrameMetricsWrapper metrics, int traceThresholdMissedFrames,
|
||||
int traceThresholdFrameTimeMillis) {
|
||||
int traceThresholdFrameTimeMillis, @Nullable FrameTrackerListener listener) {
|
||||
mSession = session;
|
||||
mRendererWrapper = renderer;
|
||||
mMetricsWrapper = metrics;
|
||||
@@ -120,6 +124,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
|
||||
mObserver = new HardwareRendererObserver(this, mMetricsWrapper.getTiming(), handler);
|
||||
mTraceThresholdMissedFrames = traceThresholdMissedFrames;
|
||||
mTraceThresholdFrameTimeMillis = traceThresholdFrameTimeMillis;
|
||||
mListener = listener;
|
||||
|
||||
// If the surface isn't valid yet, wait until it's created.
|
||||
if (viewRootWrapper.getSurfaceControl().isValid()) {
|
||||
@@ -165,11 +170,15 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
|
||||
*/
|
||||
public synchronized void begin() {
|
||||
mBeginVsyncId = mChoreographer.getVsyncId() + 1;
|
||||
mSession.setTimeStamp(System.nanoTime());
|
||||
Trace.beginAsyncSection(mSession.getName(), (int) mBeginVsyncId);
|
||||
mRendererWrapper.addObserver(mObserver);
|
||||
if (mSurfaceControl != null) {
|
||||
mSurfaceControlWrapper.addJankStatsListener(this, mSurfaceControl);
|
||||
}
|
||||
if (mListener != null) {
|
||||
mListener.onNotifyCujEvents(mSession, ACTION_SESSION_BEGIN);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -224,7 +233,6 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
|
||||
}
|
||||
|
||||
private boolean isInRange(long vsyncId) {
|
||||
|
||||
// It's possible that we may miss a callback for the frame with vsyncId == mEndVsyncId.
|
||||
// Because of that, we collect all frames even if they happen after the end so we eventually
|
||||
// have a frame after the end with both callbacks present.
|
||||
@@ -371,6 +379,9 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
|
||||
missedAppFramesCount + missedSfFramesCounts,
|
||||
maxFrameTimeNanos,
|
||||
missedSfFramesCounts);
|
||||
if (mListener != null) {
|
||||
mListener.onNotifyCujEvents(mSession, ACTION_METRICS_LOGGED);
|
||||
}
|
||||
}
|
||||
if (DEBUG) {
|
||||
Log.i(TAG, "FrameTracker: CUJ=" + mSession.getName()
|
||||
@@ -495,4 +506,17 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
|
||||
return mChoreographer.getVsyncId();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A listener that notifies cuj events.
|
||||
*/
|
||||
public interface FrameTrackerListener {
|
||||
/**
|
||||
* Notify that the CUJ session was created.
|
||||
*
|
||||
* @param session the CUJ session
|
||||
* @param action the specific action
|
||||
*/
|
||||
void onNotifyCujEvents(Session session, String action);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
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.SurfaceControlWrapper;
|
||||
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_ALL_APPS_SCROLL;
|
||||
@@ -48,9 +50,12 @@ import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_IN
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.os.HandlerExecutor;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.SystemProperties;
|
||||
import android.provider.DeviceConfig;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
@@ -59,6 +64,7 @@ import android.view.View;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.jank.FrameTracker.FrameMetricsWrapper;
|
||||
import com.android.internal.jank.FrameTracker.FrameTrackerListener;
|
||||
import com.android.internal.jank.FrameTracker.ThreadedRendererWrapper;
|
||||
import com.android.internal.jank.FrameTracker.ViewRootWrapper;
|
||||
import com.android.internal.util.PerfettoTrigger;
|
||||
@@ -74,6 +80,8 @@ import java.util.concurrent.TimeUnit;
|
||||
*/
|
||||
public class InteractionJankMonitor {
|
||||
private static final String TAG = InteractionJankMonitor.class.getSimpleName();
|
||||
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 String SETTINGS_ENABLED_KEY = "enabled";
|
||||
@@ -90,6 +98,14 @@ public class InteractionJankMonitor {
|
||||
private static final int DEFAULT_TRACE_THRESHOLD_MISSED_FRAMES = 3;
|
||||
private static final int DEFAULT_TRACE_THRESHOLD_FRAME_TIME_MILLIS = 64;
|
||||
|
||||
public static final String ACTION_SESSION_BEGIN = ACTION_PREFIX + ".ACTION_SESSION_BEGIN";
|
||||
public static final String ACTION_SESSION_END = ACTION_PREFIX + ".ACTION_SESSION_END";
|
||||
public static final String ACTION_METRICS_LOGGED = ACTION_PREFIX + ".ACTION_METRICS_LOGGED";
|
||||
public static final String BUNDLE_KEY_CUJ_NAME = ACTION_PREFIX + ".CUJ_NAME";
|
||||
public static final String BUNDLE_KEY_TIMESTAMP = ACTION_PREFIX + ".TIMESTAMP";
|
||||
@VisibleForTesting
|
||||
public static final String PROP_NOTIFY_CUJ_EVENT = "debug.notify_cuj_events";
|
||||
|
||||
// Every value must have a corresponding entry in CUJ_STATSD_INTERACTION_TYPE.
|
||||
public static final int CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE = 0;
|
||||
public static final int CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE_LOCK = 1;
|
||||
@@ -256,15 +272,28 @@ public class InteractionJankMonitor {
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public FrameTracker createFrameTracker(View v, Session session) {
|
||||
final Context c = v.getContext().getApplicationContext();
|
||||
synchronized (this) {
|
||||
boolean needListener = SystemProperties.getBoolean(PROP_NOTIFY_CUJ_EVENT, false);
|
||||
FrameTrackerListener eventsListener =
|
||||
!needListener ? null : (s, act) -> notifyEvents(c, act, s);
|
||||
|
||||
return new FrameTracker(session, mWorker.getThreadHandler(),
|
||||
new ThreadedRendererWrapper(v.getThreadedRenderer()),
|
||||
new ViewRootWrapper(v.getViewRootImpl()), new SurfaceControlWrapper(),
|
||||
new ChoreographerWrapper(Choreographer.getInstance()), mMetrics,
|
||||
mTraceThresholdMissedFrames, mTraceThresholdFrameTimeMillis);
|
||||
mTraceThresholdMissedFrames, mTraceThresholdFrameTimeMillis, eventsListener);
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyEvents(Context context, String action, Session session) {
|
||||
Intent intent = new Intent(action);
|
||||
intent.putExtra(BUNDLE_KEY_CUJ_NAME, getNameOfCuj(session.getCuj()));
|
||||
intent.putExtra(BUNDLE_KEY_TIMESTAMP, session.getTimeStamp());
|
||||
intent.addFlags(FLAG_RECEIVER_REGISTERED_ONLY);
|
||||
context.sendBroadcast(intent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Begin a trace session.
|
||||
*
|
||||
@@ -479,6 +508,7 @@ public class InteractionJankMonitor {
|
||||
public static class Session {
|
||||
@CujType
|
||||
private int mCujType;
|
||||
private long mTimeStamp;
|
||||
|
||||
public Session(@CujType int cujType) {
|
||||
mCujType = cujType;
|
||||
@@ -505,5 +535,13 @@ public class InteractionJankMonitor {
|
||||
public String getName() {
|
||||
return "J<" + getNameOfCuj(mCujType) + ">";
|
||||
}
|
||||
|
||||
public void setTimeStamp(long timeStamp) {
|
||||
mTimeStamp = timeStamp;
|
||||
}
|
||||
|
||||
public long getTimeStamp() {
|
||||
return mTimeStamp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,7 +105,8 @@ public class FrameTrackerTest {
|
||||
mTracker = Mockito.spy(
|
||||
new FrameTracker(session, handler, mRenderer, mViewRootWrapper,
|
||||
mSurfaceControlWrapper, mChoreographer, mWrapper,
|
||||
/*traceThresholdMissedFrames=*/ 1, /*traceThresholdFrameTimeMillis=*/ -1));
|
||||
/*traceThresholdMissedFrames=*/ 1, /*traceThresholdFrameTimeMillis=*/ -1,
|
||||
null));
|
||||
doNothing().when(mTracker).triggerPerfetto();
|
||||
}
|
||||
|
||||
|
||||
@@ -96,7 +96,7 @@ public class InteractionJankMonitorTest {
|
||||
new ViewRootWrapper(mView.getViewRootImpl()), new SurfaceControlWrapper(),
|
||||
mock(FrameTracker.ChoreographerWrapper.class),
|
||||
new FrameMetricsWrapper(), /*traceThresholdMissedFrames=*/ 1,
|
||||
/*traceThresholdFrameTimeMillis=*/ -1));
|
||||
/*traceThresholdFrameTimeMillis=*/ -1, null));
|
||||
doReturn(tracker).when(monitor).createFrameTracker(any(), any());
|
||||
|
||||
// Simulate a trace session and see if begin / end are invoked.
|
||||
@@ -123,21 +123,12 @@ public class InteractionJankMonitorTest {
|
||||
@Test
|
||||
public void testCheckInitState() {
|
||||
InteractionJankMonitor monitor = new InteractionJankMonitor(mWorker);
|
||||
View view = new View(mActivity);
|
||||
assertThat(view.isAttachedToWindow()).isFalse();
|
||||
|
||||
// Should return false if invoking begin / end without init invocation.
|
||||
assertThat(monitor.begin(mView, CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE)).isFalse();
|
||||
// Should return false if the view passed in is not attached to window yet.
|
||||
assertThat(monitor.begin(view, CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE)).isFalse();
|
||||
assertThat(monitor.end(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE)).isFalse();
|
||||
|
||||
// Everything should be fine if invoking init first.
|
||||
boolean thrown = false;
|
||||
try {
|
||||
assertThat(monitor.begin(mView, CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE)).isTrue();
|
||||
assertThat(monitor.end(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE)).isTrue();
|
||||
} catch (Exception ex) {
|
||||
thrown = true;
|
||||
} finally {
|
||||
assertThat(thrown).isFalse();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -152,7 +143,7 @@ public class InteractionJankMonitorTest {
|
||||
new ViewRootWrapper(mView.getViewRootImpl()), new SurfaceControlWrapper(),
|
||||
mock(FrameTracker.ChoreographerWrapper.class),
|
||||
new FrameMetricsWrapper(), /*traceThresholdMissedFrames=*/ 1,
|
||||
/*traceThresholdFrameTimeMillis=*/ -1));
|
||||
/*traceThresholdFrameTimeMillis=*/ -1, null));
|
||||
doReturn(tracker).when(monitor).createFrameTracker(any(), any());
|
||||
|
||||
assertThat(monitor.begin(mView, session.getCuj())).isTrue();
|
||||
|
||||
Reference in New Issue
Block a user