diff --git a/core/java/com/android/internal/util/DumpUtils.java b/core/java/com/android/internal/util/DumpUtils.java index f6d80a572c75b..8fe2b9cdf1e55 100644 --- a/core/java/com/android/internal/util/DumpUtils.java +++ b/core/java/com/android/internal/util/DumpUtils.java @@ -25,6 +25,7 @@ import android.os.Binder; import android.os.Handler; import android.text.TextUtils; import android.util.Slog; +import android.util.SparseArray; import java.io.PrintWriter; import java.io.StringWriter; @@ -312,5 +313,85 @@ public final class DumpUtils { || cn.flattenToString().toLowerCase().contains(filterString.toLowerCase()); }; } -} + /** + * Lambda used to dump a key (and its index) while iterating though a collection. + */ + public interface KeyDumper { + + /** Dumps the index and key.*/ + void dump(int index, int key); + } + + /** + * Lambda used to dump a value while iterating though a collection. + * + * @param type of the value. + */ + public interface ValueDumper { + + /** Dumps the value.*/ + void dump(T value); + } + + /** + * Dumps a sparse array. + */ + public static void dumpSparseArray(PrintWriter pw, String prefix, SparseArray array, + String name) { + dumpSparseArray(pw, prefix, array, name, /* keyDumper= */ null, /* valueDumper= */ null); + } + + /** + * Dumps the values of a sparse array. + */ + public static void dumpSparseArrayValues(PrintWriter pw, String prefix, + SparseArray array, String name) { + dumpSparseArray(pw, prefix, array, name, (i, k) -> { + pw.printf("%s%s", prefix, prefix); + }, /* valueDumper= */ null); + } + + /** + * Dumps a sparse array, customizing each line. + */ + public static void dumpSparseArray(PrintWriter pw, String prefix, SparseArray array, + String name, @Nullable KeyDumper keyDumper, @Nullable ValueDumper valueDumper) { + int size = array.size(); + if (size == 0) { + pw.print(prefix); + pw.print("No "); + pw.print(name); + pw.println("s"); + return; + } + pw.print(prefix); + pw.print(size); + pw.print(' '); + pw.print(name); + pw.println("(s):"); + + String prefix2 = prefix + prefix; + for (int i = 0; i < size; i++) { + int key = array.keyAt(i); + T value = array.valueAt(i); + if (keyDumper != null) { + keyDumper.dump(i, key); + } else { + pw.print(prefix2); + pw.print(i); + pw.print(": "); + pw.print(key); + pw.print("->"); + } + if (value == null) { + pw.print("(null)"); + } else if (valueDumper != null) { + valueDumper.dump(value); + } else { + pw.print(value); + } + pw.println(); + } + } +} diff --git a/core/tests/coretests/src/com/android/internal/util/DumpUtilsTest.java b/core/tests/coretests/src/com/android/internal/util/DumpUtilsTest.java index 4716312c59a8f..36c2a62ae6ed5 100644 --- a/core/tests/coretests/src/com/android/internal/util/DumpUtilsTest.java +++ b/core/tests/coretests/src/com/android/internal/util/DumpUtilsTest.java @@ -23,16 +23,25 @@ import static com.android.internal.util.DumpUtils.isPlatformCriticalPackage; import static com.android.internal.util.DumpUtils.isPlatformNonCriticalPackage; import static com.android.internal.util.DumpUtils.isPlatformPackage; +import static com.google.common.truth.Truth.assertWithMessage; + import android.content.ComponentName; +import android.util.SparseArray; import junit.framework.TestCase; +import java.io.PrintWriter; +import java.io.StringWriter; + /** * Run with: atest FrameworksCoreTests:DumpUtilsTest */ public class DumpUtilsTest extends TestCase { + private final StringWriter mStringWriter = new StringWriter(); + private final PrintWriter mPrintWriter = new PrintWriter(mStringWriter); + private static ComponentName cn(String componentName) { if (componentName == null) { return null; @@ -168,4 +177,144 @@ public class DumpUtilsTest extends TestCase { Integer.toHexString(System.identityHashCode(component))).test( wcn("com.google/.abc"))); } + + public void testDumpSparseArray_empty() { + SparseArray array = new SparseArray<>(); + + DumpUtils.dumpSparseArray(mPrintWriter, /* prefix= */ "...", array, "whatever"); + + String output = flushPrintWriter(); + + assertWithMessage("empty array dump").that(output).isEqualTo("...No whatevers\n"); + } + + public void testDumpSparseArray_oneElement() { + SparseArray array = new SparseArray<>(); + array.put(1, "uno"); + + DumpUtils.dumpSparseArray(mPrintWriter, /* prefix= */ ".", array, "number"); + + String output = flushPrintWriter(); + + assertWithMessage("dump of %s", array).that(output).isEqualTo("" + + ".1 number(s):\n" + + "..0: 1->uno\n"); + } + + public void testDumpSparseArray_oneNullElement() { + SparseArray array = new SparseArray<>(); + array.put(1, null); + + DumpUtils.dumpSparseArray(mPrintWriter, /* prefix= */ ".", array, "NULL"); + + String output = flushPrintWriter(); + + assertWithMessage("dump of %s", array).that(output).isEqualTo("" + + ".1 NULL(s):\n" + + "..0: 1->(null)\n"); + } + + public void testDumpSparseArray_multipleElements() { + SparseArray array = new SparseArray<>(); + array.put(1, "uno"); + array.put(2, "duo"); + array.put(42, null); + + DumpUtils.dumpSparseArray(mPrintWriter, /* prefix= */ ".", array, "number"); + + String output = flushPrintWriter(); + + assertWithMessage("dump of %s", array).that(output).isEqualTo("" + + ".3 number(s):\n" + + "..0: 1->uno\n" + + "..1: 2->duo\n" + + "..2: 42->(null)\n"); + } + + public void testDumpSparseArray_keyDumperOnly() { + SparseArray array = new SparseArray<>(); + array.put(1, "uno"); + array.put(2, "duo"); + array.put(42, null); + + DumpUtils.dumpSparseArray(mPrintWriter, /* prefix= */ ".", array, "number", + (i, k) -> { + mPrintWriter.printf("_%d=%d_", i, k); + }, /* valueDumper= */ null); + + String output = flushPrintWriter(); + + assertWithMessage("dump of %s", array).that(output).isEqualTo("" + + ".3 number(s):\n" + + "_0=1_uno\n" + + "_1=2_duo\n" + + "_2=42_(null)\n"); + } + + public void testDumpSparseArray_valueDumperOnly() { + SparseArray array = new SparseArray<>(); + array.put(1, "uno"); + array.put(2, "duo"); + array.put(42, null); + + DumpUtils.dumpSparseArray(mPrintWriter, /* prefix= */ ".", array, "number", + /* keyDumper= */ null, + s -> { + mPrintWriter.print(s.toUpperCase()); + }); + + String output = flushPrintWriter(); + + assertWithMessage("dump of %s", array).that(output).isEqualTo("" + + ".3 number(s):\n" + + "..0: 1->UNO\n" + + "..1: 2->DUO\n" + + "..2: 42->(null)\n"); + } + + public void testDumpSparseArray_keyAndValueDumpers() { + SparseArray array = new SparseArray<>(); + array.put(1, "uno"); + array.put(2, "duo"); + array.put(42, null); + + DumpUtils.dumpSparseArray(mPrintWriter, /* prefix= */ ".", array, "number", + (i, k) -> { + mPrintWriter.printf("_%d=%d_", i, k); + }, + s -> { + mPrintWriter.print(s.toUpperCase()); + }); + + String output = flushPrintWriter(); + + assertWithMessage("dump of %s", array).that(output).isEqualTo("" + + ".3 number(s):\n" + + "_0=1_UNO\n" + + "_1=2_DUO\n" + + "_2=42_(null)\n"); + } + + public void testDumpSparseArrayValues() { + SparseArray array = new SparseArray<>(); + array.put(1, "uno"); + array.put(2, "duo"); + array.put(42, null); + + DumpUtils.dumpSparseArrayValues(mPrintWriter, /* prefix= */ ".", array, "number"); + + String output = flushPrintWriter(); + + assertWithMessage("dump of %s", array).that(output).isEqualTo("" + + ".3 numbers:\n" + + "..uno\n" + + "..duo\n" + + "..(null)\n"); + } + + private String flushPrintWriter() { + mPrintWriter.flush(); + + return mStringWriter.toString(); + } } diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java index df360b86fdf8c..f3001133338a2 100644 --- a/services/core/java/com/android/server/wm/AccessibilityController.java +++ b/services/core/java/com/android/server/wm/AccessibilityController.java @@ -25,6 +25,8 @@ import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_MAGNIFI import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; import static android.view.WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY; +import static com.android.internal.util.DumpUtils.dumpSparseArray; +import static com.android.internal.util.DumpUtils.dumpSparseArrayValues; import static com.android.server.accessibility.AccessibilityTraceFileProto.ENTRY; import static com.android.server.accessibility.AccessibilityTraceFileProto.MAGIC_NUMBER; import static com.android.server.accessibility.AccessibilityTraceFileProto.MAGIC_NUMBER_H; @@ -44,8 +46,6 @@ import static com.android.server.accessibility.AccessibilityTraceProto.WHERE; import static com.android.server.accessibility.AccessibilityTraceProto.WINDOW_MANAGER_SERVICE; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; -import static com.android.server.wm.WindowManagerService.dumpSparseArray; -import static com.android.server.wm.WindowManagerService.dumpSparseArrayValues; import static com.android.server.wm.WindowTracing.WINSCOPE_EXT; import android.accessibilityservice.AccessibilityTrace; diff --git a/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java b/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java index afe164056ff44..70f20075b48c3 100644 --- a/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java +++ b/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java @@ -16,8 +16,9 @@ package com.android.server.wm; -import static com.android.server.wm.WindowManagerService.ValueDumper; -import static com.android.server.wm.WindowManagerService.dumpSparseArray; +import static com.android.internal.util.DumpUtils.KeyDumper; +import static com.android.internal.util.DumpUtils.ValueDumper; +import static com.android.internal.util.DumpUtils.dumpSparseArray; import static com.android.server.wm.utils.RegionUtils.forEachRect; import android.annotation.NonNull; @@ -41,7 +42,6 @@ import android.view.WindowManager; import android.window.WindowInfosListener; import com.android.internal.annotations.GuardedBy; -import com.android.server.wm.WindowManagerService.KeyDumper; import java.io.PrintWriter; import java.util.ArrayList; diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 82c057b99c10e..8fecf111d98cb 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -235,7 +235,6 @@ import android.util.EventLog; import android.util.MergedConfiguration; import android.util.Pair; import android.util.Slog; -import android.util.SparseArray; import android.util.SparseBooleanArray; import android.util.SparseIntArray; import android.util.TimeUtils; @@ -9460,53 +9459,4 @@ public class WindowManagerService extends IWindowManager.Stub return List.copyOf(notifiedApps); } } - - // TODO(b/271188189): move dump stuff below to common code / add unit tests - - interface ValueDumper { - void dump(T value); - } - - interface KeyDumper{ - void dump(int index, int key); - } - - static void dumpSparseArray(PrintWriter pw, String prefix, SparseArray array, String name) { - dumpSparseArray(pw, prefix, array, name, /* keyDumper= */ null, /* valuedumper= */ null); - } - - static void dumpSparseArrayValues(PrintWriter pw, String prefix, SparseArray array, - String name) { - dumpSparseArray(pw, prefix, array, name, (i, k) -> {}, /* valueDumper= */ null); - } - - static void dumpSparseArray(PrintWriter pw, String prefix, SparseArray array, - String name, @Nullable KeyDumper keyDumper, @Nullable ValueDumper valueDumper) { - int size = array.size(); - if (size == 0) { - pw.print(prefix); pw.print("No "); pw.print(name); pw.println("s"); - return; - } - pw.print(prefix); pw.print(size); pw.print(' '); - pw.print(name); pw.print(size > 1 ? "s" : ""); pw.println(':'); - - String prefix2 = prefix + " "; - for (int i = 0; i < size; i++) { - int key = array.keyAt(i); - T value = array.valueAt(i); - if (keyDumper != null) { - keyDumper.dump(i, key); - } else { - pw.print(prefix2); pw.print(i); pw.print(": "); pw.print(key); pw.print("->"); - } - if (value == null) { - pw.print("(null)"); - } else if (valueDumper != null) { - valueDumper.dump(value); - } else { - pw.print(value); - } - pw.println(); - } - } }