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

Commit 52cfba0d authored by Winson Chung's avatar Winson Chung
Browse files

Add mechanism to trace specific sf tx changes without rebuilding fw



- It's often that we see something affecting a surface, but there's
  no way to know who/what code is updating the surface without adding
  logging to SurfaceControl.Transaction to dump the trace and
  rebuilding with the logs in place.  This cl uses two sysprops
  to define a call/surface name filter to dynamically dump call
  stacks for specific updates in all processes.  This only applies
  to eng/userdebug builds.

  ie.
  // set
  adb shell setprop persist.wm.debug.sc.tx.log_match_call setAlpha
  adb shell setprop persist.wm.debug.sc.tx.log_match_name com.android.systemui
  adb reboot
  adb logcat -s "SurfaceControlRegistry"

  // unset
  adb shell setprop persist.wm.debug.sc.tx.log_match_call \"\"
  adb shell setprop persist.wm.debug.sc.tx.log_match_name \"\"
  adb reboot
  adb logcat -s "SurfaceControlRegistry"
- Also simplify checks in SC by always having a no-op implementation

Bug: 266978825
Test: adb shell setprop persist.wm.debug.sc.tx.log_match_call <call>
      adb shell setprop persist.wm.debug.sc.tx.log_match_name <name>
      adb reboot
      adb logcat
Test: atest FrameworksCoreTests:android.view.SurfaceControlRegistryTests
Change-Id: I2a2ef5e8bfae1a748df1a32ce7969de4ee8d9645
Signed-off-by: default avatarWinson Chung <winsonc@google.com>
parent 52d4cfa2
Loading
Loading
Loading
Loading
+111 −25
Original line number Diff line number Diff line
@@ -70,6 +70,7 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemProperties;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Slog;
@@ -796,7 +797,7 @@ public final class SurfaceControl implements Parcelable {
        if (nativeObject != 0) {
            // Only add valid surface controls to the registry. This is called at the end of this
            // method since its information is dumped if the process threshold is reached.
            addToRegistry();
            SurfaceControlRegistry.getProcessInstance().add(this);
        }
    }

@@ -1501,7 +1502,7 @@ public final class SurfaceControl implements Parcelable {
            if (mCloseGuard != null) {
                mCloseGuard.warnIfOpen();
            }
            removeFromRegistry();
            SurfaceControlRegistry.getProcessInstance().remove(this);
        } finally {
            super.finalize();
        }
@@ -1519,6 +1520,10 @@ public final class SurfaceControl implements Parcelable {
     */
    public void release() {
        if (mNativeObject != 0) {
            if (SurfaceControlRegistry.sCallStackDebuggingEnabled) {
                SurfaceControlRegistry.getProcessInstance().checkCallStackDebugging(
                        "release", null, this, null);
            }
            mFreeNativeResources.run();
            mNativeObject = 0;
            mNativeHandle = 0;
@@ -1532,7 +1537,7 @@ public final class SurfaceControl implements Parcelable {
                    mChoreographer = null;
                }
            }
            removeFromRegistry();
            SurfaceControlRegistry.getProcessInstance().remove(this);
        }
    }

@@ -2765,8 +2770,10 @@ public final class SurfaceControl implements Parcelable {

        private Transaction(long nativeObject) {
            mNativeObject = nativeObject;
            mFreeNativeResources =
                    sRegistry.registerNativeAllocation(this, mNativeObject);
            mFreeNativeResources = sRegistry.registerNativeAllocation(this, mNativeObject);
            if (!SurfaceControlRegistry.sCallStackDebuggingInitialized) {
                SurfaceControlRegistry.initializeCallStackDebugging();
            }
        }

        private Transaction(Parcel in) {
@@ -2845,6 +2852,11 @@ public final class SurfaceControl implements Parcelable {
            applyResizedSurfaces();
            notifyReparentedSurfaces();
            nativeApplyTransaction(mNativeObject, sync, oneWay);

            if (SurfaceControlRegistry.sCallStackDebuggingEnabled) {
                SurfaceControlRegistry.getProcessInstance().checkCallStackDebugging(
                        "apply", this, null, null);
            }
        }

        /**
@@ -2920,6 +2932,10 @@ public final class SurfaceControl implements Parcelable {
        @UnsupportedAppUsage
        public Transaction show(SurfaceControl sc) {
            checkPreconditions(sc);
            if (SurfaceControlRegistry.sCallStackDebuggingEnabled) {
                SurfaceControlRegistry.getProcessInstance().checkCallStackDebugging(
                        "show", this, sc, null);
            }
            nativeSetFlags(mNativeObject, sc.mNativeObject, 0, SURFACE_HIDDEN);
            return this;
        }
@@ -2934,6 +2950,10 @@ public final class SurfaceControl implements Parcelable {
        @UnsupportedAppUsage
        public Transaction hide(SurfaceControl sc) {
            checkPreconditions(sc);
            if (SurfaceControlRegistry.sCallStackDebuggingEnabled) {
                SurfaceControlRegistry.getProcessInstance().checkCallStackDebugging(
                        "hide", this, sc, null);
            }
            nativeSetFlags(mNativeObject, sc.mNativeObject, SURFACE_HIDDEN, SURFACE_HIDDEN);
            return this;
        }
@@ -2950,6 +2970,10 @@ public final class SurfaceControl implements Parcelable {
        @NonNull
        public Transaction setPosition(@NonNull SurfaceControl sc, float x, float y) {
            checkPreconditions(sc);
            if (SurfaceControlRegistry.sCallStackDebuggingEnabled) {
                SurfaceControlRegistry.getProcessInstance().checkCallStackDebugging(
                        "setPosition", this, sc, "x=" + x + " y=" + y);
            }
            nativeSetPosition(mNativeObject, sc.mNativeObject, x, y);
            return this;
        }
@@ -2968,6 +2992,10 @@ public final class SurfaceControl implements Parcelable {
            checkPreconditions(sc);
            Preconditions.checkArgument(scaleX >= 0, "Negative value passed in for scaleX");
            Preconditions.checkArgument(scaleY >= 0, "Negative value passed in for scaleY");
            if (SurfaceControlRegistry.sCallStackDebuggingEnabled) {
                SurfaceControlRegistry.getProcessInstance().checkCallStackDebugging(
                        "setScale", this, sc, "sx=" + scaleX + " sy=" + scaleY);
            }
            nativeSetScale(mNativeObject, sc.mNativeObject, scaleX, scaleY);
            return this;
        }
@@ -2985,6 +3013,10 @@ public final class SurfaceControl implements Parcelable {
        public Transaction setBufferSize(@NonNull SurfaceControl sc,
                @IntRange(from = 0) int w, @IntRange(from = 0) int h) {
            checkPreconditions(sc);
            if (SurfaceControlRegistry.sCallStackDebuggingEnabled) {
                SurfaceControlRegistry.getProcessInstance().checkCallStackDebugging(
                        "setBufferSize", this, sc, "w=" + w + " h=" + h);
            }
            mResizedSurfaces.put(sc, new Point(w, h));
            return this;
        }
@@ -3005,6 +3037,10 @@ public final class SurfaceControl implements Parcelable {
        public Transaction setFixedTransformHint(@NonNull SurfaceControl sc,
                       @Surface.Rotation int transformHint) {
            checkPreconditions(sc);
            if (SurfaceControlRegistry.sCallStackDebuggingEnabled) {
                SurfaceControlRegistry.getProcessInstance().checkCallStackDebugging(
                        "setFixedTransformHint", this, sc, "hint=" + transformHint);
            }
            nativeSetFixedTransformHint(mNativeObject, sc.mNativeObject, transformHint);
            return this;
        }
@@ -3018,6 +3054,10 @@ public final class SurfaceControl implements Parcelable {
        @NonNull
        public Transaction unsetFixedTransformHint(@NonNull SurfaceControl sc) {
            checkPreconditions(sc);
            if (SurfaceControlRegistry.sCallStackDebuggingEnabled) {
                SurfaceControlRegistry.getProcessInstance().checkCallStackDebugging(
                        "unsetFixedTransformHint", this, sc, null);
            }
            nativeSetFixedTransformHint(mNativeObject, sc.mNativeObject, -1/* INVALID_ROTATION */);
            return this;
        }
@@ -3035,6 +3075,10 @@ public final class SurfaceControl implements Parcelable {
        public Transaction setLayer(@NonNull SurfaceControl sc,
                @IntRange(from = Integer.MIN_VALUE, to = Integer.MAX_VALUE) int z) {
            checkPreconditions(sc);
            if (SurfaceControlRegistry.sCallStackDebuggingEnabled) {
                SurfaceControlRegistry.getProcessInstance().checkCallStackDebugging(
                        "setLayer", this, sc, "z=" + z);
            }
            nativeSetLayer(mNativeObject, sc.mNativeObject, z);
            return this;
        }
@@ -3044,6 +3088,10 @@ public final class SurfaceControl implements Parcelable {
         */
        public Transaction setRelativeLayer(SurfaceControl sc, SurfaceControl relativeTo, int z) {
            checkPreconditions(sc);
            if (SurfaceControlRegistry.sCallStackDebuggingEnabled) {
                SurfaceControlRegistry.getProcessInstance().checkCallStackDebugging(
                        "setRelativeLayer", this, sc, "relTo=" + relativeTo + " z=" + z);
            }
            nativeSetRelativeLayer(mNativeObject, sc.mNativeObject, relativeTo.mNativeObject, z);
            return this;
        }
@@ -3053,6 +3101,10 @@ public final class SurfaceControl implements Parcelable {
         */
        public Transaction setTransparentRegionHint(SurfaceControl sc, Region transparentRegion) {
            checkPreconditions(sc);
            if (SurfaceControlRegistry.sCallStackDebuggingEnabled) {
                SurfaceControlRegistry.getProcessInstance().checkCallStackDebugging(
                        "unsetFixedTransformHint", this, sc, "region=" + transparentRegion);
            }
            nativeSetTransparentRegionHint(mNativeObject,
                    sc.mNativeObject, transparentRegion);
            return this;
@@ -3069,6 +3121,10 @@ public final class SurfaceControl implements Parcelable {
        public Transaction setAlpha(@NonNull SurfaceControl sc,
                @FloatRange(from = 0.0, to = 1.0) float alpha) {
            checkPreconditions(sc);
            if (SurfaceControlRegistry.sCallStackDebuggingEnabled) {
                SurfaceControlRegistry.getProcessInstance().checkCallStackDebugging(
                        "setAlpha", this, sc, "alpha=" + alpha);
            }
            nativeSetAlpha(mNativeObject, sc.mNativeObject, alpha);
            return this;
        }
@@ -3124,6 +3180,11 @@ public final class SurfaceControl implements Parcelable {
        public Transaction setMatrix(SurfaceControl sc,
                float dsdx, float dtdx, float dtdy, float dsdy) {
            checkPreconditions(sc);
            if (SurfaceControlRegistry.sCallStackDebuggingEnabled) {
                SurfaceControlRegistry.getProcessInstance().checkCallStackDebugging(
                        "setMatrix", this, sc,
                        "dsdx=" + dsdx + " dtdx=" + dtdx + " dtdy=" + dtdy + " dsdy=" + dsdy);
            }
            nativeSetMatrix(mNativeObject, sc.mNativeObject,
                    dsdx, dtdx, dtdy, dsdy);
            return this;
@@ -3189,6 +3250,10 @@ public final class SurfaceControl implements Parcelable {
        @UnsupportedAppUsage
        public Transaction setWindowCrop(SurfaceControl sc, Rect crop) {
            checkPreconditions(sc);
            if (SurfaceControlRegistry.sCallStackDebuggingEnabled) {
                SurfaceControlRegistry.getProcessInstance().checkCallStackDebugging(
                        "setWindowCrop", this, sc, "crop=" + crop);
            }
            if (crop != null) {
                nativeSetWindowCrop(mNativeObject, sc.mNativeObject,
                        crop.left, crop.top, crop.right, crop.bottom);
@@ -3211,6 +3276,10 @@ public final class SurfaceControl implements Parcelable {
         */
        public @NonNull Transaction setCrop(@NonNull SurfaceControl sc, @Nullable Rect crop) {
            checkPreconditions(sc);
            if (SurfaceControlRegistry.sCallStackDebuggingEnabled) {
                SurfaceControlRegistry.getProcessInstance().checkCallStackDebugging(
                        "setCrop", this, sc, "crop=" + crop);
            }
            if (crop != null) {
                Preconditions.checkArgument(crop.isValid(), "Crop isn't valid.");
                nativeSetWindowCrop(mNativeObject, sc.mNativeObject,
@@ -3233,6 +3302,10 @@ public final class SurfaceControl implements Parcelable {
         */
        public Transaction setWindowCrop(SurfaceControl sc, int width, int height) {
            checkPreconditions(sc);
            if (SurfaceControlRegistry.sCallStackDebuggingEnabled) {
                SurfaceControlRegistry.getProcessInstance().checkCallStackDebugging(
                        "setCornerRadius", this, sc, "w=" + width + " h=" + height);
            }
            nativeSetWindowCrop(mNativeObject, sc.mNativeObject, 0, 0, width, height);
            return this;
        }
@@ -3247,6 +3320,10 @@ public final class SurfaceControl implements Parcelable {
        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
        public Transaction setCornerRadius(SurfaceControl sc, float cornerRadius) {
            checkPreconditions(sc);
            if (SurfaceControlRegistry.sCallStackDebuggingEnabled) {
                SurfaceControlRegistry.getProcessInstance().checkCallStackDebugging(
                        "setCornerRadius", this, sc, "cornerRadius=" + cornerRadius);
            }
            nativeSetCornerRadius(mNativeObject, sc.mNativeObject, cornerRadius);

            return this;
@@ -3262,6 +3339,10 @@ public final class SurfaceControl implements Parcelable {
         */
        public Transaction setBackgroundBlurRadius(SurfaceControl sc, int radius) {
            checkPreconditions(sc);
            if (SurfaceControlRegistry.sCallStackDebuggingEnabled) {
                SurfaceControlRegistry.getProcessInstance().checkCallStackDebugging(
                        "setBackgroundBlurRadius", this, sc, "radius=" + radius);
            }
            nativeSetBackgroundBlurRadius(mNativeObject, sc.mNativeObject, radius);
            return this;
        }
@@ -3318,6 +3399,10 @@ public final class SurfaceControl implements Parcelable {
        public Transaction reparent(@NonNull SurfaceControl sc,
                @Nullable SurfaceControl newParent) {
            checkPreconditions(sc);
            if (SurfaceControlRegistry.sCallStackDebuggingEnabled) {
                SurfaceControlRegistry.getProcessInstance().checkCallStackDebugging(
                        "reparent", this, sc, "newParent=" + newParent);
            }
            long otherObject = 0;
            if (newParent != null) {
                newParent.checkNotReleased();
@@ -3337,6 +3422,11 @@ public final class SurfaceControl implements Parcelable {
        @UnsupportedAppUsage
        public Transaction setColor(SurfaceControl sc, @Size(3) float[] color) {
            checkPreconditions(sc);
            if (SurfaceControlRegistry.sCallStackDebuggingEnabled) {
                SurfaceControlRegistry.getProcessInstance().checkCallStackDebugging(
                        "reparent", this, sc,
                        "r=" + color[0] + " g=" + color[1] + " b=" + color[2]);
            }
            nativeSetColor(mNativeObject, sc.mNativeObject, color);
            return this;
        }
@@ -3347,6 +3437,10 @@ public final class SurfaceControl implements Parcelable {
        */
        public Transaction unsetColor(SurfaceControl sc) {
            checkPreconditions(sc);
            if (SurfaceControlRegistry.sCallStackDebuggingEnabled) {
                SurfaceControlRegistry.getProcessInstance().checkCallStackDebugging(
                        "unsetColor", this, sc, null);
            }
            nativeSetColor(mNativeObject, sc.mNativeObject, INVALID_COLOR);
            return this;
        }
@@ -3358,6 +3452,10 @@ public final class SurfaceControl implements Parcelable {
         */
        public Transaction setSecure(SurfaceControl sc, boolean isSecure) {
            checkPreconditions(sc);
            if (SurfaceControlRegistry.sCallStackDebuggingEnabled) {
                SurfaceControlRegistry.getProcessInstance().checkCallStackDebugging(
                        "setSecure", this, sc, "secure=" + isSecure);
            }
            if (isSecure) {
                nativeSetFlags(mNativeObject, sc.mNativeObject, SECURE, SECURE);
            } else {
@@ -3411,6 +3509,10 @@ public final class SurfaceControl implements Parcelable {
        @NonNull
        public Transaction setOpaque(@NonNull SurfaceControl sc, boolean isOpaque) {
            checkPreconditions(sc);
            if (SurfaceControlRegistry.sCallStackDebuggingEnabled) {
                SurfaceControlRegistry.getProcessInstance().checkCallStackDebugging(
                        "setOpaque", this, sc, "opaque=" + isOpaque);
            }
            if (isOpaque) {
                nativeSetFlags(mNativeObject, sc.mNativeObject, SURFACE_OPAQUE, SURFACE_OPAQUE);
            } else {
@@ -3580,6 +3682,10 @@ public final class SurfaceControl implements Parcelable {
          */
        public Transaction setShadowRadius(SurfaceControl sc, float shadowRadius) {
            checkPreconditions(sc);
            if (SurfaceControlRegistry.sCallStackDebuggingEnabled) {
                SurfaceControlRegistry.getProcessInstance().checkCallStackDebugging(
                        "setShadowRadius", this, sc, "radius=" + shadowRadius);
            }
            nativeSetShadowRadius(mNativeObject, sc.mNativeObject, shadowRadius);
            return this;
        }
@@ -4463,26 +4569,6 @@ public final class SurfaceControl implements Parcelable {
        return -1;
    }

    /**
     * Adds this surface control to the registry for this process if it is created.
     */
    private void addToRegistry() {
        final SurfaceControlRegistry registry = SurfaceControlRegistry.getProcessInstance();
        if (registry != null) {
            registry.add(this);
        }
    }

    /**
     * Removes this surface control from the registry for this process.
     */
    private void removeFromRegistry() {
        final SurfaceControlRegistry registry = SurfaceControlRegistry.getProcessInstance();
        if (registry != null) {
            registry.remove(this);
        }
    }

    // Called by native
    private static void invokeReleaseCallback(Consumer<SyncFence> callback, long nativeFencePtr) {
        SyncFence fence = new SyncFence(nativeFencePtr);
+133 −3
Original line number Diff line number Diff line
@@ -23,7 +23,9 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.content.Context;
import android.os.Build;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.util.Log;

import com.android.internal.annotations.GuardedBy;
@@ -99,6 +101,9 @@ public class SurfaceControlRegistry {
    // Number of surface controls to dump when the max threshold is exceeded
    private static final int DUMP_LIMIT = 256;

    // An instance of a registry that is a no-op
    private static final SurfaceControlRegistry NO_OP_REGISTRY = new NoOpRegistry();

    // Static lock, must be held for all registry operations
    private static final Object sLock = new Object();

@@ -108,6 +113,22 @@ public class SurfaceControlRegistry {
    // The registry for a given process
    private static volatile SurfaceControlRegistry sProcessRegistry;

    // Whether call stack debugging has been initialized. This is evaluated only once per process
    // instance when the first SurfaceControl.Transaction object is created
    static boolean sCallStackDebuggingInitialized;

    // Whether call stack debugging is currently enabled, ie. whether there is a valid match string
    // for either a specific surface control name or surface control transaction method
    static boolean sCallStackDebuggingEnabled;

    // The name of the surface control to log stack traces for.  Always non-null if
    // sCallStackDebuggingEnabled is true.  Can be combined with the match call.
    private static String sCallStackDebuggingMatchName;

    // The surface control transaction method name to log stack traces for.  Always non-null if
    // sCallStackDebuggingEnabled is true.  Can be combined with the match name.
    private static String sCallStackDebuggingMatchCall;

    // Mapping of the active SurfaceControls to the elapsed time when they were registered
    @GuardedBy("sLock")
    private final WeakHashMap<SurfaceControl, Long> mSurfaceControls;
@@ -155,6 +176,12 @@ public class SurfaceControlRegistry {
        }
    }

    @VisibleForTesting
    public void setCallStackDebuggingParams(String matchName, String matchCall) {
        sCallStackDebuggingMatchName = matchName.toLowerCase();
        sCallStackDebuggingMatchCall = matchCall.toLowerCase();
    }

    /**
     * Creates and initializes the registry for all SurfaceControls in this process. The caller must
     * hold the READ_FRAME_BUFFER permission.
@@ -191,11 +218,9 @@ public class SurfaceControlRegistry {
     * createProcessInstance(Context) was previously called from a valid caller.
     * @hide
     */
    @Nullable
    @VisibleForTesting
    public static SurfaceControlRegistry getProcessInstance() {
        synchronized (sLock) {
            return sProcessRegistry;
            return sProcessRegistry != null ? sProcessRegistry : NO_OP_REGISTRY;
        }
    }

@@ -242,6 +267,91 @@ public class SurfaceControlRegistry {
        }
    }

    /**
     * Initializes global call stack debugging if this is a debug build and a filter is specified.
     * This is a no-op if
     *
     * Usage:
     *   adb shell setprop persist.wm.debug.sc.tx.log_match_call <call or \"\" to unset>
     *   adb shell setprop persist.wm.debug.sc.tx.log_match_name <name or \"\" to unset>
     *   adb reboot
     */
    final static void initializeCallStackDebugging() {
        if (sCallStackDebuggingInitialized || !Build.IS_DEBUGGABLE) {
            // Return early if already initialized or this is not a debug build
            return;
        }

        sCallStackDebuggingInitialized = true;
        sCallStackDebuggingMatchCall =
                SystemProperties.get("persist.wm.debug.sc.tx.log_match_call", null)
                        .toLowerCase();
        sCallStackDebuggingMatchName =
                SystemProperties.get("persist.wm.debug.sc.tx.log_match_name", null)
                        .toLowerCase();
        // Only enable stack debugging if any of the match filters are set
        sCallStackDebuggingEnabled = (!sCallStackDebuggingMatchCall.isEmpty()
                || !sCallStackDebuggingMatchName.isEmpty());
        if (sCallStackDebuggingEnabled) {
            Log.d(TAG, "Enabling transaction call stack debugging:"
                    + " matchCall=" + sCallStackDebuggingMatchCall
                    + " matchName=" + sCallStackDebuggingMatchName);
        }
    }

    /**
     * Dumps the callstack if it matches the global debug properties. Caller should first verify
     * {@link #sCallStackDebuggingEnabled} is true.
     *
     * @param call the name of the call
     * @param tx (optional) the transaction associated with this call
     * @param sc the affected surface
     * @param details additional details to print with the stack track
     */
    final void checkCallStackDebugging(@NonNull String call,
            @Nullable SurfaceControl.Transaction tx, @Nullable SurfaceControl sc,
            @Nullable String details) {
        if (!sCallStackDebuggingEnabled) {
            return;
        }
        if (!matchesForCallStackDebugging(sc != null ? sc.getName() : null, call)) {
            return;
        }
        final String txMsg = tx != null ? "tx=" + tx.getId() + " ": "";
        final String scMsg = sc != null ? " sc=" + sc.getName() + "": "";
        final String msg = details != null
                ? call + " (" + txMsg + scMsg + ") " + details
                : call + " (" + txMsg + scMsg + ")";
        Log.e(TAG, msg, new Throwable());
    }

    /**
     * Tests whether the given surface control name/method call matches the filters set for the
     * call stack debugging.
     */
    @VisibleForTesting
    public final boolean matchesForCallStackDebugging(@Nullable String name, @NonNull String call) {
        final boolean matchCall = !sCallStackDebuggingMatchCall.isEmpty();
        if (matchCall && !call.toLowerCase().contains(sCallStackDebuggingMatchCall)) {
            // Skip if target call doesn't match requested caller
            return false;
        }
        final boolean matchName = !sCallStackDebuggingMatchName.isEmpty();
        if (matchName && (name == null
                || !name.toLowerCase().contains(sCallStackDebuggingMatchName))) {
            // Skip if target surface doesn't match requested surface
            return false;
        }
        return true;
    }

    /**
     * Returns whether call stack debugging is enabled for this process.
     */
    final static boolean isCallStackDebuggingEnabled() {
        return sCallStackDebuggingEnabled;
    }

    /**
     * Forces the gc and finalizers to run, used prior to dumping to ensure we only dump strongly
     * referenced surface controls.
@@ -267,7 +377,27 @@ public class SurfaceControlRegistry {
        synchronized (sLock) {
            if (sProcessRegistry != null) {
                sDefaultReporter.onMaxLayersExceeded(sProcessRegistry.mSurfaceControls, limit, pw);
                pw.println("sCallStackDebuggingInitialized=" + sCallStackDebuggingInitialized);
                pw.println("sCallStackDebuggingEnabled=" + sCallStackDebuggingEnabled);
                pw.println("sCallStackDebuggingMatchName=" + sCallStackDebuggingMatchName);
                pw.println("sCallStackDebuggingMatchCall=" + sCallStackDebuggingMatchCall);
            }
        }
    }

    /**
     * A no-op implementation of the registry.
     */
    private static class NoOpRegistry extends SurfaceControlRegistry {

        @Override
        public void setReportingThresholds(int maxLayersReportingThreshold,
                int resetReportingThreshold, Reporter reporter) {}

        @Override
        void add(SurfaceControl sc) {}

        @Override
        void remove(SurfaceControl sc) {}
    }
}
+23 −0
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentat

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.eq;
@@ -148,6 +149,28 @@ public class SurfaceControlRegistryTests {
        reporter.assertLastReportedSetEquals(sc5, sc6, sc7, sc8);
    }

    @Test
    public void testCallStackDebugging_matchesFilters() {
        SurfaceControlRegistry registry = SurfaceControlRegistry.getProcessInstance();

        // Specific name, any call
        registry.setCallStackDebuggingParams("com.android.app1", "");
        assertFalse(registry.matchesForCallStackDebugging("com.android.noMatchApp", "setAlpha"));
        assertTrue(registry.matchesForCallStackDebugging("com.android.app1", "setAlpha"));

        // Any name, specific call
        registry.setCallStackDebuggingParams("", "setAlpha");
        assertFalse(registry.matchesForCallStackDebugging("com.android.app1", "setLayer"));
        assertTrue(registry.matchesForCallStackDebugging("com.android.app1", "setAlpha"));
        assertTrue(registry.matchesForCallStackDebugging("com.android.app2", "setAlpha"));

        // Specific name, specific call
        registry.setCallStackDebuggingParams("com.android.app1", "setAlpha");
        assertFalse(registry.matchesForCallStackDebugging("com.android.app1", "setLayer"));
        assertFalse(registry.matchesForCallStackDebugging("com.android.app2", "setAlpha"));
        assertTrue(registry.matchesForCallStackDebugging("com.android.app1", "setAlpha"));
    }

    private SurfaceControl buildTestSurface() {
        return new SurfaceControl.Builder()
                .setContainerLayer()