summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java73
-rwxr-xr-xservices/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java110
2 files changed, 149 insertions, 34 deletions
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 308d441fb871..5d699b557aa4 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -4877,14 +4877,14 @@ public class NotificationManagerService extends SystemService {
continue;
}
notificationsRapidlyCleared = notificationsRapidlyCleared
- || isNotificationRecent(r);
+ || isNotificationRecent(r.getUpdateTimeMs());
cancelNotificationFromListenerLocked(info, callingUid, callingPid,
r.getSbn().getPackageName(), r.getSbn().getTag(),
r.getSbn().getId(), userId, reason);
}
} else {
for (NotificationRecord notificationRecord : mNotificationList) {
- if (isNotificationRecent(notificationRecord)) {
+ if (isNotificationRecent(notificationRecord.getUpdateTimeMs())) {
notificationsRapidlyCleared = true;
break;
}
@@ -4910,14 +4910,6 @@ public class NotificationManagerService extends SystemService {
}
}
- private boolean isNotificationRecent(@NonNull NotificationRecord notificationRecord) {
- if (!rapidClearNotificationsByListenerAppOpEnabled()) {
- return false;
- }
- return notificationRecord.getFreshnessMs(System.currentTimeMillis())
- < NOTIFICATION_RAPID_CLEAR_THRESHOLD_MS;
- }
-
/**
* Handle request from an approved listener to re-enable itself.
*
@@ -5041,12 +5033,11 @@ public class NotificationManagerService extends SystemService {
@Override
public void snoozeNotificationUntilContextFromListener(INotificationListener token,
String key, String snoozeCriterionId) {
+ final int callingUid = Binder.getCallingUid();
final long identity = Binder.clearCallingIdentity();
try {
- synchronized (mNotificationLock) {
- final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
- snoozeNotificationInt(key, SNOOZE_UNTIL_UNSPECIFIED, snoozeCriterionId, info);
- }
+ snoozeNotificationInt(callingUid, token, key, SNOOZE_UNTIL_UNSPECIFIED,
+ snoozeCriterionId);
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -5060,12 +5051,10 @@ public class NotificationManagerService extends SystemService {
@Override
public void snoozeNotificationUntilFromListener(INotificationListener token, String key,
long duration) {
+ final int callingUid = Binder.getCallingUid();
final long identity = Binder.clearCallingIdentity();
try {
- synchronized (mNotificationLock) {
- final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
- snoozeNotificationInt(key, duration, null, info);
- }
+ snoozeNotificationInt(callingUid, token, key, duration, null);
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -10306,16 +10295,22 @@ public class NotificationManagerService extends SystemService {
}
}
- void snoozeNotificationInt(String key, long duration, String snoozeCriterionId,
- ManagedServiceInfo listener) {
- if (listener == null) {
- return;
- }
- String listenerName = listener.component.toShortString();
- if ((duration <= 0 && snoozeCriterionId == null) || key == null) {
- return;
- }
+ void snoozeNotificationInt(int callingUid, INotificationListener token, String key,
+ long duration, String snoozeCriterionId) {
+ final String packageName;
+ final long notificationUpdateTimeMs;
+
synchronized (mNotificationLock) {
+ final ManagedServiceInfo listener = mListeners.checkServiceTokenLocked(token);
+ if (listener == null) {
+ return;
+ }
+ packageName = listener.component.getPackageName();
+ String listenerName = listener.component.toShortString();
+ if ((duration <= 0 && snoozeCriterionId == null) || key == null) {
+ return;
+ }
+
final NotificationRecord r = findInCurrentAndSnoozedNotificationByKeyLocked(key);
if (r == null) {
return;
@@ -10323,14 +10318,20 @@ public class NotificationManagerService extends SystemService {
if (!listener.enabledAndUserMatches(r.getSbn().getNormalizedUserId())){
return;
}
+ notificationUpdateTimeMs = r.getUpdateTimeMs();
+
+ if (DBG) {
+ Slog.d(TAG, String.format("snooze event(%s, %d, %s, %s)", key, duration,
+ snoozeCriterionId, listenerName));
+ }
+ // Needs to post so that it can cancel notifications not yet enqueued.
+ mHandler.post(new SnoozeNotificationRunnable(key, duration, snoozeCriterionId));
}
- if (DBG) {
- Slog.d(TAG, String.format("snooze event(%s, %d, %s, %s)", key, duration,
- snoozeCriterionId, listenerName));
+ if (isNotificationRecent(notificationUpdateTimeMs)) {
+ mAppOps.noteOpNoThrow(AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER,
+ callingUid, packageName, /* attributionTag= */ null, /* message= */ null);
}
- // Needs to post so that it can cancel notifications not yet enqueued.
- mHandler.post(new SnoozeNotificationRunnable(key, duration, snoozeCriterionId));
}
void unsnoozeNotificationInt(String key, ManagedServiceInfo listener, boolean muteOnReturn) {
@@ -10342,6 +10343,14 @@ public class NotificationManagerService extends SystemService {
handleSavePolicyFile();
}
+ private boolean isNotificationRecent(long notificationUpdateTimeMs) {
+ if (!rapidClearNotificationsByListenerAppOpEnabled()) {
+ return false;
+ }
+ return System.currentTimeMillis() - notificationUpdateTimeMs
+ < NOTIFICATION_RAPID_CLEAR_THRESHOLD_MS;
+ }
+
@GuardedBy("mNotificationLock")
void cancelAllLocked(int callingUid, int callingPid, int userId, int reason,
ManagedServiceInfo listener, boolean includeCurrentProfiles, int mustNotHaveFlags) {
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 9c2cba8ecf96..f82b6a41f35d 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -4116,7 +4116,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
when(mListener.enabledAndUserMatches(anyInt())).thenReturn(false);
when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
- mService.snoozeNotificationInt(r.getKey(), 1000, null, mListener);
+ mService.snoozeNotificationInt(Binder.getCallingUid(), mock(INotificationListener.class),
+ r.getKey(), 1000, null);
verify(mWorkerHandler, never()).post(
any(NotificationManagerService.SnoozeNotificationRunnable.class));
@@ -4134,13 +4135,118 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
when(mListener.enabledAndUserMatches(anyInt())).thenReturn(true);
when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
- mService.snoozeNotificationInt(r2.getKey(), 1000, null, mListener);
+ mService.snoozeNotificationInt(Binder.getCallingUid(), mock(INotificationListener.class),
+ r2.getKey(), 1000, null);
verify(mWorkerHandler).post(
any(NotificationManagerService.SnoozeNotificationRunnable.class));
}
@Test
+ public void snoozeNotificationInt_rapidSnooze_new() {
+ mSetFlagsRule.enableFlags(android.view.contentprotection.flags.Flags
+ .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED);
+
+ // Create recent notification.
+ final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel,
+ System.currentTimeMillis());
+ mService.addNotification(nr1);
+
+ mListener = mock(ManagedServices.ManagedServiceInfo.class);
+ mListener.component = new ComponentName(PKG, PKG);
+ when(mListener.enabledAndUserMatches(anyInt())).thenReturn(true);
+ when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
+
+ mService.snoozeNotificationInt(Binder.getCallingUid(), mock(INotificationListener.class),
+ nr1.getKey(), 1000, null);
+
+ verify(mWorkerHandler).post(
+ any(NotificationManagerService.SnoozeNotificationRunnable.class));
+ // Ensure cancel event is logged.
+ verify(mAppOpsManager).noteOpNoThrow(
+ AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER, mUid, PKG, null,
+ null);
+ }
+
+ @Test
+ public void snoozeNotificationInt_rapidSnooze_old() {
+ mSetFlagsRule.enableFlags(android.view.contentprotection.flags.Flags
+ .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED);
+
+ // Create old notification.
+ final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel,
+ System.currentTimeMillis() - 60000);
+ mService.addNotification(nr1);
+
+ mListener = mock(ManagedServices.ManagedServiceInfo.class);
+ mListener.component = new ComponentName(PKG, PKG);
+ when(mListener.enabledAndUserMatches(anyInt())).thenReturn(true);
+ when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
+
+ mService.snoozeNotificationInt(Binder.getCallingUid(), mock(INotificationListener.class),
+ nr1.getKey(), 1000, null);
+
+ verify(mWorkerHandler).post(
+ any(NotificationManagerService.SnoozeNotificationRunnable.class));
+ // Ensure cancel event is not logged.
+ verify(mAppOpsManager, never()).noteOpNoThrow(
+ eq(AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER), anyInt(), anyString(),
+ any(), any());
+ }
+
+ @Test
+ public void snoozeNotificationInt_rapidSnooze_new_flagDisabled() {
+ mSetFlagsRule.disableFlags(android.view.contentprotection.flags.Flags
+ .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED);
+
+ // Create recent notification.
+ final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel,
+ System.currentTimeMillis());
+ mService.addNotification(nr1);
+
+ mListener = mock(ManagedServices.ManagedServiceInfo.class);
+ mListener.component = new ComponentName(PKG, PKG);
+ when(mListener.enabledAndUserMatches(anyInt())).thenReturn(true);
+ when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
+
+ mService.snoozeNotificationInt(Binder.getCallingUid(), mock(INotificationListener.class),
+ nr1.getKey(), 1000, null);
+
+ verify(mWorkerHandler).post(
+ any(NotificationManagerService.SnoozeNotificationRunnable.class));
+ // Ensure cancel event is not logged.
+ verify(mAppOpsManager, never()).noteOpNoThrow(
+ eq(AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER), anyInt(), anyString(),
+ any(), any());
+ }
+
+ @Test
+ public void snoozeNotificationInt_rapidSnooze_old_flagDisabled() {
+ mSetFlagsRule.disableFlags(android.view.contentprotection.flags.Flags
+ .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED);
+
+ // Create old notification.
+ final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel,
+ System.currentTimeMillis() - 60000);
+ mService.addNotification(nr1);
+
+ mListener = mock(ManagedServices.ManagedServiceInfo.class);
+ mListener.component = new ComponentName(PKG, PKG);
+ when(mListener.enabledAndUserMatches(anyInt())).thenReturn(true);
+ when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
+
+ mService.snoozeNotificationInt(Binder.getCallingUid(), mock(INotificationListener.class),
+ nr1.getKey(), 1000, null);
+
+ verify(mWorkerHandler).post(
+ any(NotificationManagerService.SnoozeNotificationRunnable.class));
+ // Ensure cancel event is not logged.
+ verify(mAppOpsManager, never()).noteOpNoThrow(
+ eq(AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER), anyInt(), anyString(),
+ any(), any());
+ }
+
+ @Test
public void testSnoozeRunnable_tooManySnoozed_singleNotification() {
final NotificationRecord notification = generateNotificationRecord(
mTestNotificationChannel, 1, null, true);