Merge "Introduce a way to debug relayouts and slow measures/layout" into tm-qpr-dev

This commit is contained in:
Nicolò Mazzucato
2023-02-01 07:08:55 +00:00
committed by Android (Google) Code Review
4 changed files with 219 additions and 6 deletions

View File

@@ -109,7 +109,8 @@ public final class Trace {
public static final long TRACE_TAG_THERMAL = 1L << 27; public static final long TRACE_TAG_THERMAL = 1L << 27;
private static final long TRACE_TAG_NOT_READY = 1L << 63; private static final long TRACE_TAG_NOT_READY = 1L << 63;
private static final int MAX_SECTION_NAME_LEN = 127; /** @hide **/
public static final int MAX_SECTION_NAME_LEN = 127;
// Must be volatile to avoid word tearing. // Must be volatile to avoid word tearing.
// This is only kept in case any apps get this by reflection but do not // This is only kept in case any apps get this by reflection but do not

View File

@@ -17,6 +17,7 @@
package android.view; package android.view;
import static android.content.res.Resources.ID_NULL; import static android.content.res.Resources.ID_NULL;
import static android.os.Trace.TRACE_TAG_APP;
import static android.view.ContentInfo.SOURCE_DRAG_AND_DROP; import static android.view.ContentInfo.SOURCE_DRAG_AND_DROP;
import static android.view.accessibility.AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED; import static android.view.accessibility.AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED;
import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_INVALID_BOUNDS; import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_INVALID_BOUNDS;
@@ -984,6 +985,22 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/ */
private static boolean sAcceptZeroSizeDragShadow; private static boolean sAcceptZeroSizeDragShadow;
/**
* When true, measure and layout passes of all the newly attached views will be logged with
* {@link Trace}, so we can better debug jank due to complex view hierarchies.
*/
private static boolean sTraceLayoutSteps;
/**
* When not null, emits a {@link Trace} instant event and the stacktrace every time a relayout
* of a class having this name happens.
*/
private static String sTraceRequestLayoutClass;
/** Used to avoid computing the full strings each time when layout tracing is enabled. */
@Nullable
private ViewTraversalTracingStrings mTracingStrings;
/** /**
* Prior to R, {@link #dispatchApplyWindowInsets} had an issue: * Prior to R, {@link #dispatchApplyWindowInsets} had an issue:
* <p>The modified insets changed by {@link #onApplyWindowInsets} were passed to the * <p>The modified insets changed by {@link #onApplyWindowInsets} were passed to the
@@ -3532,6 +3549,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* 1 PFLAG4_HAS_TRANSLATION_TRANSIENT_STATE * 1 PFLAG4_HAS_TRANSLATION_TRANSIENT_STATE
* 1 PFLAG4_DRAG_A11Y_STARTED * 1 PFLAG4_DRAG_A11Y_STARTED
* 1 PFLAG4_AUTO_HANDWRITING_INITIATION_ENABLED * 1 PFLAG4_AUTO_HANDWRITING_INITIATION_ENABLED
* 1 PFLAG4_TRAVERSAL_TRACING_ENABLED
* 1 PFLAG4_RELAYOUT_TRACING_ENABLED
* |-------|-------|-------|-------| * |-------|-------|-------|-------|
*/ */
@@ -3612,6 +3631,19 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* Indicates that the view enables auto handwriting initiation. * Indicates that the view enables auto handwriting initiation.
*/ */
private static final int PFLAG4_AUTO_HANDWRITING_ENABLED = 0x000010000; private static final int PFLAG4_AUTO_HANDWRITING_ENABLED = 0x000010000;
/**
* When set, measure and layout passes of this view will be logged with {@link Trace}, so we
* can better debug jank due to complex view hierarchies.
*/
private static final int PFLAG4_TRAVERSAL_TRACING_ENABLED = 0x000040000;
/**
* When set, emits a {@link Trace} instant event and stacktrace every time a requestLayout of
* this class happens.
*/
private static final int PFLAG4_RELAYOUT_TRACING_ENABLED = 0x000080000;
/* End of masks for mPrivateFlags4 */ /* End of masks for mPrivateFlags4 */
/** @hide */ /** @hide */
@@ -6537,6 +6569,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
out.append(mRight); out.append(mRight);
out.append(','); out.append(',');
out.append(mBottom); out.append(mBottom);
appendId(out);
if (mAutofillId != null) {
out.append(" aid="); out.append(mAutofillId);
}
out.append("}");
return out.toString();
}
void appendId(StringBuilder out) {
final int id = getId(); final int id = getId();
if (id != NO_ID) { if (id != NO_ID) {
out.append(" #"); out.append(" #");
@@ -6568,11 +6609,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
} }
} }
} }
if (mAutofillId != null) {
out.append(" aid="); out.append(mAutofillId);
}
out.append("}");
return out.toString();
} }
/** /**
@@ -20767,6 +20803,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
if (isFocused()) { if (isFocused()) {
notifyFocusChangeToImeFocusController(true /* hasFocus */); notifyFocusChangeToImeFocusController(true /* hasFocus */);
} }
if (sTraceLayoutSteps) {
setTraversalTracingEnabled(true);
}
if (sTraceRequestLayoutClass != null
&& sTraceRequestLayoutClass.equals(getClass().getSimpleName())) {
setRelayoutTracingEnabled(true);
}
} }
/** /**
@@ -23666,6 +23710,30 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
return o instanceof ViewGroup && ((ViewGroup) o).isLayoutModeOptical(); return o instanceof ViewGroup && ((ViewGroup) o).isLayoutModeOptical();
} }
/**
* Enable measure/layout debugging on traces.
*
* @see Trace
* @hide
*/
public static void setTraceLayoutSteps(boolean traceLayoutSteps) {
sTraceLayoutSteps = traceLayoutSteps;
}
/**
* Enable request layout tracing classes with {@code s} simple name.
* <p>
* When set, a {@link Trace} instant event and a log with the stacktrace is emitted every
* time a requestLayout of a class matching {@code s} name happens.
* This applies only to views attached from this point onwards.
*
* @see Trace#instant(long, String)
* @hide
*/
public static void setTracedRequestLayoutClassClass(String s) {
sTraceRequestLayoutClass = s;
}
private boolean setOpticalFrame(int left, int top, int right, int bottom) { private boolean setOpticalFrame(int left, int top, int right, int bottom) {
Insets parentInsets = mParent instanceof View ? Insets parentInsets = mParent instanceof View ?
((View) mParent).getOpticalInsets() : Insets.NONE; ((View) mParent).getOpticalInsets() : Insets.NONE;
@@ -23700,7 +23768,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
@SuppressWarnings({"unchecked"}) @SuppressWarnings({"unchecked"})
public void layout(int l, int t, int r, int b) { public void layout(int l, int t, int r, int b) {
if ((mPrivateFlags3 & PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT) != 0) { if ((mPrivateFlags3 & PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT) != 0) {
if (isTraversalTracingEnabled()) {
Trace.beginSection(mTracingStrings.onMeasureBeforeLayout);
}
onMeasure(mOldWidthMeasureSpec, mOldHeightMeasureSpec); onMeasure(mOldWidthMeasureSpec, mOldHeightMeasureSpec);
if (isTraversalTracingEnabled()) {
Trace.endSection();
}
mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
} }
@@ -23713,7 +23787,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b); setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b);
if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) { if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) {
if (isTraversalTracingEnabled()) {
Trace.beginSection(mTracingStrings.onLayout);
}
onLayout(changed, l, t, r, b); onLayout(changed, l, t, r, b);
if (isTraversalTracingEnabled()) {
Trace.endSection();
}
if (shouldDrawRoundScrollbar()) { if (shouldDrawRoundScrollbar()) {
if(mRoundScrollbarRenderer == null) { if(mRoundScrollbarRenderer == null) {
@@ -26270,6 +26350,25 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
return (viewRoot != null && viewRoot.isInLayout()); return (viewRoot != null && viewRoot.isInLayout());
} }
/** To be used only for debugging purposes. */
private void printStackStrace(String name) {
Log.d(VIEW_LOG_TAG, "---- ST:" + name);
StringBuilder sb = new StringBuilder();
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
int startIndex = 1;
int endIndex = Math.min(stackTraceElements.length, startIndex + 20); // max 20 entries.
for (int i = startIndex; i < endIndex; i++) {
StackTraceElement s = stackTraceElements[i];
sb.append(s.getMethodName())
.append("(")
.append(s.getFileName())
.append(":")
.append(s.getLineNumber())
.append(") <- ");
}
Log.d(VIEW_LOG_TAG, name + ": " + sb);
}
/** /**
* Call this when something has changed which has invalidated the * Call this when something has changed which has invalidated the
* layout of this view. This will schedule a layout pass of the view * layout of this view. This will schedule a layout pass of the view
@@ -26283,6 +26382,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/ */
@CallSuper @CallSuper
public void requestLayout() { public void requestLayout() {
if (isRelayoutTracingEnabled()) {
Trace.instantForTrack(TRACE_TAG_APP, "requestLayoutTracing",
mTracingStrings.classSimpleName);
printStackStrace(mTracingStrings.requestLayoutStacktracePrefix);
}
if (mMeasureCache != null) mMeasureCache.clear(); if (mMeasureCache != null) mMeasureCache.clear();
if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == null) { if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == null) {
@@ -26376,8 +26481,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
int cacheIndex = forceLayout ? -1 : mMeasureCache.indexOfKey(key); int cacheIndex = forceLayout ? -1 : mMeasureCache.indexOfKey(key);
if (cacheIndex < 0 || sIgnoreMeasureCache) { if (cacheIndex < 0 || sIgnoreMeasureCache) {
if (isTraversalTracingEnabled()) {
Trace.beginSection(mTracingStrings.onMeasure);
}
// measure ourselves, this should set the measured dimension flag back // measure ourselves, this should set the measured dimension flag back
onMeasure(widthMeasureSpec, heightMeasureSpec); onMeasure(widthMeasureSpec, heightMeasureSpec);
if (isTraversalTracingEnabled()) {
Trace.endSection();
}
mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
} else { } else {
long value = mMeasureCache.valueAt(cacheIndex); long value = mMeasureCache.valueAt(cacheIndex);
@@ -31547,6 +31658,38 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
== PFLAG4_AUTO_HANDWRITING_ENABLED; == PFLAG4_AUTO_HANDWRITING_ENABLED;
} }
private void setTraversalTracingEnabled(boolean enabled) {
if (enabled) {
if (mTracingStrings == null) {
mTracingStrings = new ViewTraversalTracingStrings(this);
}
mPrivateFlags4 |= PFLAG4_TRAVERSAL_TRACING_ENABLED;
} else {
mPrivateFlags4 &= ~PFLAG4_TRAVERSAL_TRACING_ENABLED;
}
}
private boolean isTraversalTracingEnabled() {
return (mPrivateFlags4 & PFLAG4_TRAVERSAL_TRACING_ENABLED)
== PFLAG4_TRAVERSAL_TRACING_ENABLED;
}
private void setRelayoutTracingEnabled(boolean enabled) {
if (enabled) {
if (mTracingStrings == null) {
mTracingStrings = new ViewTraversalTracingStrings(this);
}
mPrivateFlags4 |= PFLAG4_RELAYOUT_TRACING_ENABLED;
} else {
mPrivateFlags4 &= ~PFLAG4_RELAYOUT_TRACING_ENABLED;
}
}
private boolean isRelayoutTracingEnabled() {
return (mPrivateFlags4 & PFLAG4_RELAYOUT_TRACING_ENABLED)
== PFLAG4_RELAYOUT_TRACING_ENABLED;
}
/** /**
* Collects a {@link ViewTranslationRequest} which represents the content to be translated in * Collects a {@link ViewTranslationRequest} which represents the content to be translated in
* the view. * the view.

View File

@@ -0,0 +1,63 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.view;
import android.os.Trace;
/**
* Keeps and caches strings used to trace {@link View} traversals.
* <p>
* This is done to avoid expensive computations of them every time, which can improve performance.
*/
class ViewTraversalTracingStrings {
/** {@link Trace} tag used to mark {@link View#onMeasure(int, int)}. */
public final String onMeasure;
/** {@link Trace} tag used to mark {@link View#onLayout(boolean, int, int, int, int)}. */
public final String onLayout;
/** Caches the view simple name to avoid re-computations. */
public final String classSimpleName;
/** Prefix for request layout stacktraces output in logs. */
public final String requestLayoutStacktracePrefix;
/** {@link Trace} tag used to mark {@link View#onMeasure(int, int)} happening before layout. */
public final String onMeasureBeforeLayout;
/**
* @param v {@link View} from where to get the class name.
*/
ViewTraversalTracingStrings(View v) {
String className = v.getClass().getSimpleName();
classSimpleName = className;
onMeasureBeforeLayout = getTraceName("onMeasureBeforeLayout", className, v);
onMeasure = getTraceName("onMeasure", className, v);
onLayout = getTraceName("onLayout", className, v);
requestLayoutStacktracePrefix = "requestLayout " + className;
}
private String getTraceName(String sectionName, String className, View v) {
StringBuilder out = new StringBuilder();
out.append(sectionName);
out.append(" ");
out.append(className);
v.appendId(out);
return out.substring(0, Math.min(out.length() - 1, Trace.MAX_SECTION_NAME_LEN - 1));
}
}

View File

@@ -40,6 +40,7 @@ import android.util.Log;
import android.util.TimingsTraceLog; import android.util.TimingsTraceLog;
import android.view.SurfaceControl; import android.view.SurfaceControl;
import android.view.ThreadedRenderer; import android.view.ThreadedRenderer;
import android.view.View;
import com.android.internal.protolog.common.ProtoLog; import com.android.internal.protolog.common.ProtoLog;
import com.android.systemui.dagger.GlobalRootComponent; import com.android.systemui.dagger.GlobalRootComponent;
@@ -114,6 +115,11 @@ public class SystemUIApplication extends Application implements
// the theme set there. // the theme set there.
setTheme(R.style.Theme_SystemUI); setTheme(R.style.Theme_SystemUI);
View.setTraceLayoutSteps(
SystemProperties.getBoolean("persist.debug.trace_layouts", false));
View.setTracedRequestLayoutClassClass(
SystemProperties.get("persist.debug.trace_request_layout_class", null));
if (Process.myUserHandle().equals(UserHandle.SYSTEM)) { if (Process.myUserHandle().equals(UserHandle.SYSTEM)) {
IntentFilter bootCompletedFilter = new IntentFilter bootCompletedFilter = new
IntentFilter(Intent.ACTION_LOCKED_BOOT_COMPLETED); IntentFilter(Intent.ACTION_LOCKED_BOOT_COMPLETED);