Merge "Fix crash in jank monitor debug overlay" into udc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
4da9107a3a
@@ -275,7 +275,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
|
||||||
public Handler getHandler() {
|
public Handler getHandler() {
|
||||||
return mHandler;
|
return mHandler;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -772,11 +772,12 @@ public class InteractionJankMonitor {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@UiThread
|
||||||
private void putTracker(@CujType int cuj, @NonNull FrameTracker tracker) {
|
private void putTracker(@CujType int cuj, @NonNull FrameTracker tracker) {
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
mRunningTrackers.put(cuj, tracker);
|
mRunningTrackers.put(cuj, tracker);
|
||||||
if (mDebugOverlay != null) {
|
if (mDebugOverlay != null) {
|
||||||
mDebugOverlay.onTrackerAdded(cuj, tracker.getViewRoot());
|
mDebugOverlay.onTrackerAdded(cuj, tracker);
|
||||||
}
|
}
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.d(TAG, "Added tracker for " + getNameOfCuj(cuj)
|
Log.d(TAG, "Added tracker for " + getNameOfCuj(cuj)
|
||||||
@@ -791,6 +792,7 @@ public class InteractionJankMonitor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@UiThread
|
||||||
private void removeTracker(@CujType int cuj, int reason) {
|
private void removeTracker(@CujType int cuj, int reason) {
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
mRunningTrackers.remove(cuj);
|
mRunningTrackers.remove(cuj);
|
||||||
@@ -818,7 +820,7 @@ public class InteractionJankMonitor {
|
|||||||
SETTINGS_DEBUG_OVERLAY_ENABLED_KEY,
|
SETTINGS_DEBUG_OVERLAY_ENABLED_KEY,
|
||||||
DEFAULT_DEBUG_OVERLAY_ENABLED);
|
DEFAULT_DEBUG_OVERLAY_ENABLED);
|
||||||
if (debugOverlayEnabled && mDebugOverlay == null) {
|
if (debugOverlayEnabled && mDebugOverlay == null) {
|
||||||
mDebugOverlay = new InteractionMonitorDebugOverlay(mDebugBgColor, mDebugYOffset);
|
mDebugOverlay = new InteractionMonitorDebugOverlay(mLock, mDebugBgColor, mDebugYOffset);
|
||||||
} else if (!debugOverlayEnabled && mDebugOverlay != null) {
|
} else if (!debugOverlayEnabled && mDebugOverlay != null) {
|
||||||
mDebugOverlay.dispose();
|
mDebugOverlay.dispose();
|
||||||
mDebugOverlay = null;
|
mDebugOverlay = null;
|
||||||
|
|||||||
@@ -19,25 +19,30 @@ package com.android.internal.jank;
|
|||||||
import static com.android.internal.jank.FrameTracker.REASON_END_NORMAL;
|
import static com.android.internal.jank.FrameTracker.REASON_END_NORMAL;
|
||||||
|
|
||||||
import android.annotation.ColorInt;
|
import android.annotation.ColorInt;
|
||||||
|
import android.annotation.UiThread;
|
||||||
import android.app.ActivityThread;
|
import android.app.ActivityThread;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
import android.graphics.RecordingCanvas;
|
import android.graphics.RecordingCanvas;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
|
import android.os.Handler;
|
||||||
import android.os.Trace;
|
import android.os.Trace;
|
||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
import android.util.SparseIntArray;
|
import android.util.SparseIntArray;
|
||||||
import android.view.WindowCallbacks;
|
import android.view.WindowCallbacks;
|
||||||
|
|
||||||
|
import com.android.internal.annotations.GuardedBy;
|
||||||
import com.android.internal.jank.FrameTracker.Reasons;
|
import com.android.internal.jank.FrameTracker.Reasons;
|
||||||
import com.android.internal.jank.InteractionJankMonitor.CujType;
|
import com.android.internal.jank.InteractionJankMonitor.CujType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An overlay that uses WindowCallbacks to draw the names of all running CUJs to the window
|
* An overlay that uses WindowCallbacks to draw the names of all running CUJs to the window
|
||||||
* associated with one of the CUJs being tracked. There's no guarantee which window it will
|
* associated with one of the CUJs being tracked. There's no guarantee which window it will
|
||||||
* draw to. NOTE: sometimes the CUJ names will remain displayed on the screen longer than they
|
* draw to. Traces that use the debug overlay should not be used for performance analysis.
|
||||||
* are actually running.
|
* <p>
|
||||||
|
* To enable the overlay, run the following: <code>adb shell device_config put
|
||||||
|
* interaction_jank_monitor debug_overlay_enabled true</code>
|
||||||
* <p>
|
* <p>
|
||||||
* CUJ names will be drawn as follows:
|
* CUJ names will be drawn as follows:
|
||||||
* <ul>
|
* <ul>
|
||||||
@@ -45,12 +50,16 @@ import com.android.internal.jank.InteractionJankMonitor.CujType;
|
|||||||
* <li> Grey text indicates the CUJ ended normally and is no longer running
|
* <li> Grey text indicates the CUJ ended normally and is no longer running
|
||||||
* <li> Red text with a strikethrough indicates the CUJ was canceled or ended abnormally
|
* <li> Red text with a strikethrough indicates the CUJ was canceled or ended abnormally
|
||||||
* </ul>
|
* </ul>
|
||||||
|
* @hide
|
||||||
*/
|
*/
|
||||||
class InteractionMonitorDebugOverlay implements WindowCallbacks {
|
class InteractionMonitorDebugOverlay implements WindowCallbacks {
|
||||||
private static final int REASON_STILL_RUNNING = -1000;
|
private static final int REASON_STILL_RUNNING = -1000;
|
||||||
|
private final Object mLock;
|
||||||
// Sparse array where the key in the CUJ and the value is the session status, or null if
|
// Sparse array where the key in the CUJ and the value is the session status, or null if
|
||||||
// it's currently running
|
// it's currently running
|
||||||
|
@GuardedBy("mLock")
|
||||||
private final SparseIntArray mRunningCujs = new SparseIntArray();
|
private final SparseIntArray mRunningCujs = new SparseIntArray();
|
||||||
|
private Handler mHandler = null;
|
||||||
private FrameTracker.ViewRootWrapper mViewRoot = null;
|
private FrameTracker.ViewRootWrapper mViewRoot = null;
|
||||||
private final Paint mDebugPaint;
|
private final Paint mDebugPaint;
|
||||||
private final Paint.FontMetrics mDebugFontMetrics;
|
private final Paint.FontMetrics mDebugFontMetrics;
|
||||||
@@ -59,8 +68,10 @@ class InteractionMonitorDebugOverlay implements WindowCallbacks {
|
|||||||
private final int mBgColor;
|
private final int mBgColor;
|
||||||
private final double mYOffset;
|
private final double mYOffset;
|
||||||
private final String mPackageName;
|
private final String mPackageName;
|
||||||
|
private static final String TRACK_NAME = "InteractionJankMonitor";
|
||||||
|
|
||||||
InteractionMonitorDebugOverlay(@ColorInt int bgColor, double yOffset) {
|
InteractionMonitorDebugOverlay(Object lock, @ColorInt int bgColor, double yOffset) {
|
||||||
|
mLock = lock;
|
||||||
mBgColor = bgColor;
|
mBgColor = bgColor;
|
||||||
mYOffset = yOffset;
|
mYOffset = yOffset;
|
||||||
mDebugPaint = new Paint();
|
mDebugPaint = new Paint();
|
||||||
@@ -70,18 +81,30 @@ class InteractionMonitorDebugOverlay implements WindowCallbacks {
|
|||||||
mPackageName = context.getPackageName();
|
mPackageName = context.getPackageName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@UiThread
|
||||||
void dispose() {
|
void dispose() {
|
||||||
if (mViewRoot != null) {
|
if (mViewRoot != null && mHandler != null) {
|
||||||
mViewRoot.removeWindowCallbacks(this);
|
mHandler.runWithScissors(() -> mViewRoot.removeWindowCallbacks(this),
|
||||||
|
InteractionJankMonitor.EXECUTOR_TASK_TIMEOUT);
|
||||||
forceRedraw();
|
forceRedraw();
|
||||||
}
|
}
|
||||||
|
mHandler = null;
|
||||||
mViewRoot = null;
|
mViewRoot = null;
|
||||||
|
Trace.asyncTraceForTrackEnd(Trace.TRACE_TAG_APP, TRACK_NAME, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean attachViewRootIfNeeded(FrameTracker.ViewRootWrapper viewRoot) {
|
@UiThread
|
||||||
|
private boolean attachViewRootIfNeeded(FrameTracker tracker) {
|
||||||
|
FrameTracker.ViewRootWrapper viewRoot = tracker.getViewRoot();
|
||||||
if (mViewRoot == null && viewRoot != null) {
|
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();
|
||||||
mViewRoot = viewRoot;
|
mViewRoot = viewRoot;
|
||||||
viewRoot.addWindowCallbacks(this);
|
mHandler.runWithScissors(() -> viewRoot.addWindowCallbacks(this),
|
||||||
|
InteractionJankMonitor.EXECUTOR_TASK_TIMEOUT);
|
||||||
forceRedraw();
|
forceRedraw();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -115,52 +138,61 @@ class InteractionMonitorDebugOverlay implements WindowCallbacks {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@UiThread
|
||||||
private void forceRedraw() {
|
private void forceRedraw() {
|
||||||
if (mViewRoot != null) {
|
if (mViewRoot != null && mHandler != null) {
|
||||||
mViewRoot.requestInvalidateRootRenderNode();
|
mHandler.runWithScissors(() -> {
|
||||||
mViewRoot.getView().invalidate();
|
mViewRoot.requestInvalidateRootRenderNode();
|
||||||
|
mViewRoot.getView().invalidate();
|
||||||
|
}, InteractionJankMonitor.EXECUTOR_TASK_TIMEOUT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@UiThread
|
||||||
void onTrackerRemoved(@CujType int removedCuj, @Reasons int reason,
|
void onTrackerRemoved(@CujType int removedCuj, @Reasons int reason,
|
||||||
SparseArray<FrameTracker> runningTrackers) {
|
SparseArray<FrameTracker> runningTrackers) {
|
||||||
mRunningCujs.put(removedCuj, reason);
|
synchronized (mLock) {
|
||||||
// If REASON_STILL_RUNNING is not in mRunningCujs, then all CUJs have ended
|
mRunningCujs.put(removedCuj, reason);
|
||||||
if (mRunningCujs.indexOfValue(REASON_STILL_RUNNING) < 0) {
|
// If REASON_STILL_RUNNING is not in mRunningCujs, then all CUJs have ended
|
||||||
mRunningCujs.clear();
|
if (mRunningCujs.indexOfValue(REASON_STILL_RUNNING) < 0) {
|
||||||
dispose();
|
mRunningCujs.clear();
|
||||||
} else {
|
|
||||||
boolean needsNewViewRoot = true;
|
|
||||||
if (mViewRoot != null) {
|
|
||||||
// Check to see if this viewroot is still associated with one of the running
|
|
||||||
// trackers
|
|
||||||
for (int i = 0; i < runningTrackers.size(); i++) {
|
|
||||||
if (mViewRoot.equals(
|
|
||||||
runningTrackers.valueAt(i).getViewRoot())) {
|
|
||||||
needsNewViewRoot = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (needsNewViewRoot) {
|
|
||||||
dispose();
|
dispose();
|
||||||
for (int i = 0; i < runningTrackers.size(); i++) {
|
} else {
|
||||||
if (attachViewRootIfNeeded(runningTrackers.valueAt(i).getViewRoot())) {
|
boolean needsNewViewRoot = true;
|
||||||
break;
|
if (mViewRoot != null) {
|
||||||
|
// Check to see if this viewroot is still associated with one of the running
|
||||||
|
// trackers
|
||||||
|
for (int i = 0; i < runningTrackers.size(); i++) {
|
||||||
|
if (mViewRoot.equals(
|
||||||
|
runningTrackers.valueAt(i).getViewRoot())) {
|
||||||
|
needsNewViewRoot = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
if (needsNewViewRoot) {
|
||||||
forceRedraw();
|
dispose();
|
||||||
|
for (int i = 0; i < runningTrackers.size(); i++) {
|
||||||
|
if (attachViewRootIfNeeded(runningTrackers.valueAt(i))) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
forceRedraw();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void onTrackerAdded(@CujType int addedCuj, FrameTracker.ViewRootWrapper viewRoot) {
|
@UiThread
|
||||||
// Use REASON_STILL_RUNNING (not technically one of the '@Reasons') to indicate the CUJ
|
void onTrackerAdded(@CujType int addedCuj, FrameTracker tracker) {
|
||||||
// is still running
|
synchronized (mLock) {
|
||||||
mRunningCujs.put(addedCuj, REASON_STILL_RUNNING);
|
// Use REASON_STILL_RUNNING (not technically one of the '@Reasons') to indicate the CUJ
|
||||||
attachViewRootIfNeeded(viewRoot);
|
// is still running
|
||||||
forceRedraw();
|
mRunningCujs.put(addedCuj, REASON_STILL_RUNNING);
|
||||||
|
attachViewRootIfNeeded(tracker);
|
||||||
|
forceRedraw();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -188,7 +220,6 @@ class InteractionMonitorDebugOverlay implements WindowCallbacks {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPostDraw(RecordingCanvas canvas) {
|
public void onPostDraw(RecordingCanvas canvas) {
|
||||||
Trace.beginSection("InteractionJankMonitor#drawDebug");
|
|
||||||
final int padding = dipToPx(5);
|
final int padding = dipToPx(5);
|
||||||
final int h = canvas.getHeight();
|
final int h = canvas.getHeight();
|
||||||
final int w = canvas.getWidth();
|
final int w = canvas.getWidth();
|
||||||
@@ -235,6 +266,5 @@ class InteractionMonitorDebugOverlay implements WindowCallbacks {
|
|||||||
canvas.translate(0, cujNameTextHeight);
|
canvas.translate(0, cujNameTextHeight);
|
||||||
canvas.drawText(cujName, 0, 0, mDebugPaint);
|
canvas.drawText(cujName, 0, 0, mDebugPaint);
|
||||||
}
|
}
|
||||||
Trace.endSection();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user