From a17703138b0c51226c0e73dd8d34ea037d260aeb Mon Sep 17 00:00:00 2001 From: Dan Sandler Date: Fri, 10 Jul 2015 13:59:29 -0400 Subject: Allow notification strings to be unredacted in dump output. This won't happen automatically and unredacted strings will still not appear in bugreports, but if you are attached via adb you can now do `dumpsys notification --unredact` to get the contents of String/CharSequence fields and extras emitted along with the rest of the dump. The arg handling is also improved so that multiple filters can be specified at once, e.g. --package (was "p") to restrict to a single package, and --stats to get JSON output. Bug: 20451514 Change-Id: I37fc5ce86c7e28e8f8286917f6764d64bc081108 --- .../notification/NotificationManagerService.java | 65 +++++++++++++--------- .../server/notification/NotificationRecord.java | 13 ++++- 2 files changed, 49 insertions(+), 29 deletions(-) (limited to 'services/core/java') diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index b23b856..7a6895f 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -1837,7 +1837,7 @@ public class NotificationManagerService extends SystemService { void dumpImpl(PrintWriter pw, DumpFilter filter) { pw.print("Current Notification Manager state"); - if (filter != null) { + if (filter.filtered) { pw.print(" (filtered to "); pw.print(filter); pw.print(")"); } pw.println(':'); @@ -1865,7 +1865,7 @@ public class NotificationManagerService extends SystemService { for (int i=0; i " + r.getKey()); if (mNotificationsByKey.get(r.getKey()) != r) { pw.println("!!!!!!LEAK: Record not found in mNotificationsByKey."); - r.dump(pw, " ", getContext()); + r.dump(pw, " ", getContext(), filter.redact); } } @@ -3499,46 +3499,59 @@ public class NotificationManagerService extends SystemService { } public static final class DumpFilter { + public boolean filtered = false; public String pkgFilter; public boolean zen; public long since; public boolean stats; - private boolean all; + public boolean redact = true; public static DumpFilter parseFromArguments(String[] args) { - if (args != null && args.length == 2 && "p".equals(args[0]) - && args[1] != null && !args[1].trim().isEmpty()) { - final DumpFilter filter = new DumpFilter(); - filter.pkgFilter = args[1].trim().toLowerCase(); - return filter; - } - if (args != null && args.length == 1 && "zen".equals(args[0])) { - final DumpFilter filter = new DumpFilter(); - filter.zen = true; - filter.all = true; - return filter; - } - if (args != null && args.length >= 1 && "--stats".equals(args[0])) { - final DumpFilter filter = new DumpFilter(); - filter.stats = true; - filter.since = args.length == 2 ? Long.valueOf(args[1]) : 0; - filter.all = true; - return filter; + final DumpFilter filter = new DumpFilter(); + for (int ai = 0; ai < args.length; ai++) { + final String a = args[ai]; + if ("--noredact".equals(a) || "--reveal".equals(a)) { + filter.redact = false; + } else if ("p".equals(a) || "pkg".equals(a) || "--package".equals(a)) { + if (ai < args.length-1) { + ai++; + filter.pkgFilter = args[ai].trim().toLowerCase(); + if (filter.pkgFilter.isEmpty()) { + filter.pkgFilter = null; + } else { + filter.filtered = true; + } + } + } else if ("--zen".equals(a) || "zen".equals(a)) { + filter.filtered = true; + filter.zen = true; + } else if ("--stats".equals(a)) { + filter.stats = true; + if (ai < args.length-1) { + ai++; + filter.since = Long.valueOf(args[ai]); + } else { + filter.since = 0; + } + } } - return null; + return filter; } public boolean matches(StatusBarNotification sbn) { - return all ? true : sbn != null + if (!filtered) return true; + return zen ? true : sbn != null && (matches(sbn.getPackageName()) || matches(sbn.getOpPkg())); } public boolean matches(ComponentName component) { - return all ? true : component != null && matches(component.getPackageName()); + if (!filtered) return true; + return zen ? true : component != null && matches(component.getPackageName()); } public boolean matches(String pkg) { - return all ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter); + if (!filtered) return true; + return zen ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter); } @Override diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java index b7aea9d..f37702c 100644 --- a/services/core/java/com/android/server/notification/NotificationRecord.java +++ b/services/core/java/com/android/server/notification/NotificationRecord.java @@ -114,7 +114,7 @@ public final class NotificationRecord { /** @deprecated Use {@link #getUser()} instead. */ public int getUserId() { return sbn.getUserId(); } - void dump(PrintWriter pw, String prefix, Context baseContext) { + void dump(PrintWriter pw, String prefix, Context baseContext, boolean redact) { final Notification notification = sbn.getNotification(); final Icon icon = notification.getSmallIcon(); String iconStr = String.valueOf(icon); @@ -164,7 +164,7 @@ public final class NotificationRecord { pw.println("null"); } else { pw.print(val.getClass().getSimpleName()); - if (val instanceof CharSequence || val instanceof String) { + if (redact && (val instanceof CharSequence || val instanceof String)) { // redact contents from bugreports } else if (val instanceof Bitmap) { pw.print(String.format(" (%dx%d)", @@ -172,7 +172,14 @@ public final class NotificationRecord { ((Bitmap) val).getHeight())); } else if (val.getClass().isArray()) { final int N = Array.getLength(val); - pw.println(" (" + N + ")"); + pw.print(" (" + N + ")"); + if (!redact) { + for (int j=0; j