diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 6c3177fe253ad..fb7169b0134f6 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -512,7 +512,7 @@ public class NotificationManagerService extends SystemService { private float mMaxPackageEnqueueRate = DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE; private NotificationHistoryManager mHistoryManager; - private SnoozeHelper mSnoozeHelper; + protected SnoozeHelper mSnoozeHelper; private GroupHelper mGroupHelper; private int mAutoGroupAtCount; private boolean mIsTelevision; @@ -7913,7 +7913,7 @@ public class NotificationManagerService extends SystemService { void snoozeNotificationInt(String key, long duration, String snoozeCriterionId, ManagedServiceInfo listener) { String listenerName = listener == null ? null : listener.component.toShortString(); - if (duration <= 0 && snoozeCriterionId == null || key == null) { + if ((duration <= 0 && snoozeCriterionId == null) || key == null) { return; } diff --git a/services/core/java/com/android/server/notification/NotificationShellCmd.java b/services/core/java/com/android/server/notification/NotificationShellCmd.java index e4a17740b0b7c..da7864ba32c47 100644 --- a/services/core/java/com/android/server/notification/NotificationShellCmd.java +++ b/services/core/java/com/android/server/notification/NotificationShellCmd.java @@ -50,6 +50,7 @@ import android.util.Slog; import java.io.PrintWriter; import java.net.URISyntaxException; import java.util.Collections; +import java.util.Date; /** * Implementation of `cmd notification` in NotificationManagerService. @@ -73,7 +74,12 @@ public class NotificationShellCmd extends ShellCommand { + " set_bubbles PACKAGE PREFERENCE (0=none 1=all 2=selected) " + "[user_id (current user if not specified)]\n" + " set_bubbles_channel PACKAGE CHANNEL_ID ALLOW " - + "[user_id (current user if not specified)]\n"; + + "[user_id (current user if not specified)]\n" + + " list\n" + + " get \n" + + " snooze --for \n" + + " unsnooze \n" + ; private static final String NOTIFY_USAGE = "usage: cmd notification post [flags] \n\n" @@ -118,6 +124,10 @@ public class NotificationShellCmd extends ShellCommand { mPm = mDirectService.getContext().getPackageManager(); } + protected boolean checkShellCommandPermission(int callingUid) { + return (callingUid == Process.ROOT_UID || callingUid == Process.SHELL_UID); + } + @Override public int onCommand(String cmd) { if (cmd == null) { @@ -140,7 +150,17 @@ public class NotificationShellCmd extends ShellCommand { } finally { Binder.restoreCallingIdentity(identity); } + final PrintWriter pw = getOutPrintWriter(); + + if (!checkShellCommandPermission(callingUid)) { + Slog.e(TAG, "error: permission denied: callingUid=" + + callingUid + " callingPackage=" + callingPackage); + pw.println("error: permission denied: callingUid=" + + callingUid + " callingPackage=" + callingPackage); + return 255; + } + try { switch (cmd.replace('-', '_')) { case "set_dnd": { @@ -316,6 +336,100 @@ public class NotificationShellCmd extends ShellCommand { case "notify": doNotify(pw, callingPackage, callingUid); break; + case "list": + for (String key : mDirectService.mNotificationsByKey.keySet()) { + pw.println(key); + } + break; + case "get": { + final String key = getNextArgRequired(); + final NotificationRecord nr = mDirectService.getNotificationRecord(key); + if (nr != null) { + nr.dump(pw, "", mDirectService.getContext(), false); + } else { + pw.println("error: no active notification matching key: " + key); + return 1; + } + break; + } + case "snoozed": { + final StringBuilder sb = new StringBuilder(); + final SnoozeHelper sh = mDirectService.mSnoozeHelper; + for (NotificationRecord nr : sh.getSnoozed()) { + final String pkg = nr.getSbn().getPackageName(); + final String key = nr.getKey(); + pw.println(key + " snoozed, time=" + + sh.getSnoozeTimeForUnpostedNotification( + nr.getUserId(), pkg, key) + + " context=" + + sh.getSnoozeContextForUnpostedNotification( + nr.getUserId(), pkg, key)); + } + break; + } + case "unsnooze": { + boolean mute = false; + String key = getNextArgRequired(); + if ("--mute".equals(key)) { + mute = true; + key = getNextArgRequired(); + } + if (null != mDirectService.mSnoozeHelper.getNotification(key)) { + pw.println("unsnoozing: " + key); + mDirectService.unsnoozeNotificationInt(key, null, mute); + } else { + pw.println("error: no snoozed otification matching key: " + key); + return 1; + } + break; + } + case "snooze": { + String subflag = getNextArg(); + if (subflag == null) { + subflag = "help"; + } else if (subflag.startsWith("--")) { + subflag = subflag.substring(2); + } + String flagarg = getNextArg(); + String key = getNextArg(); + if (key == null) subflag = "help"; + String criterion = null; + long duration = 0; + switch (subflag) { + case "context": + case "condition": + case "criterion": + criterion = flagarg; + break; + case "until": + case "for": + case "duration": + duration = Long.parseLong(flagarg); + break; + default: + pw.println("usage: cmd notification snooze (--for | " + + "--context ) "); + return 1; + } + if (null == mDirectService.getNotificationRecord(key)) { + pw.println("error: no notification matching key: " + key); + return 1; + } + if (duration > 0 || criterion != null) { + if (duration > 0) { + pw.println(String.format("snoozing <%s> until time: %s", key, + new Date(System.currentTimeMillis() + duration))); + } else { + pw.println(String.format("snoozing <%s> until criterion: %s", key, + criterion)); + } + mDirectService.snoozeNotificationInt(key, duration, criterion, null); + } else { + pw.println("error: invalid value for --" + subflag + ": " + flagarg); + return 1; + } + break; + } default: return handleDefaultCommands(cmd); } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationShellCmdTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationShellCmdTest.java index 0d44318e4aaad..00061931b18d2 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationShellCmdTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationShellCmdTest.java @@ -98,7 +98,8 @@ public class NotificationShellCmdTest extends UiServiceTestCase { } private void doCmd(String... args) { - new NotificationShellCmd(mMockService) + System.out.println("Running command: " + String.join(" ", args)); + new TestNotificationShellCmd(mMockService) .exec(mBinder, in, out, err, args, mCallback, mResultReceiver); } @@ -267,4 +268,19 @@ public class NotificationShellCmdTest extends UiServiceTestCase { } } + + /** + * Version of NotificationShellCmd that allows this atest to work properly despite coming in + * from the wrong uid. + */ + private final class TestNotificationShellCmd extends NotificationShellCmd { + TestNotificationShellCmd(NotificationManagerService service) { + super(service); + } + + @Override + protected boolean checkShellCommandPermission(int callingUid) { + return true; + } + } }