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

Commit 73f1c18a authored by Gaurav Gupta's avatar Gaurav Gupta Committed by Android (Google) Code Review
Browse files

Merge "Extend rapid cancelling notification AppOp to include snoozed...

Merge "Extend rapid cancelling notification AppOp to include snoozed notifications and rework time arithmetic to prevent overflow" into main
parents 1e775c89 ccb699c0
Loading
Loading
Loading
Loading
+41 −32
Original line number Diff line number Diff line
@@ -4895,14 +4895,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;
                            }
@@ -4928,14 +4928,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.
         *
@@ -5059,12 +5051,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);
            }
@@ -5078,12 +5069,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);
            }
@@ -10342,16 +10331,22 @@ public class NotificationManagerService extends SystemService {
        }
    }
    void snoozeNotificationInt(String key, long duration, String snoozeCriterionId,
            ManagedServiceInfo listener) {
    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;
            }
        synchronized (mNotificationLock) {
            final NotificationRecord r = findInCurrentAndSnoozedNotificationByKeyLocked(key);
            if (r == null) {
                return;
@@ -10359,7 +10354,7 @@ 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,
@@ -10369,6 +10364,12 @@ public class NotificationManagerService extends SystemService {
            mHandler.post(new SnoozeNotificationRunnable(key, duration, snoozeCriterionId));
        }
        if (isNotificationRecent(notificationUpdateTimeMs)) {
            mAppOps.noteOpNoThrow(AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER,
                    callingUid, packageName, /* attributionTag= */ null, /* message= */ null);
        }
    }
    void unsnoozeNotificationInt(String key, ManagedServiceInfo listener, boolean muteOnReturn) {
        String listenerName = listener == null ? null : listener.component.toShortString();
        if (DBG) {
@@ -10378,6 +10379,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) {
+108 −2
Original line number Diff line number Diff line
@@ -4121,7 +4121,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));
@@ -4139,12 +4140,117 @@ 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(