diff options
2 files changed, 74 insertions, 61 deletions
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 2f4cbd558fb9..e7db3f09578e 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -378,8 +378,6 @@ public class NotificationManagerService extends SystemService { static final int INVALID_UID = -1; static final String ROOT_PKG = "root"; - static final boolean ENABLE_BLOCKED_TOASTS = true; - static final String[] DEFAULT_ALLOWED_ADJUSTMENTS = new String[] { Adjustment.KEY_CONTEXTUAL_ACTIONS, Adjustment.KEY_TEXT_REPLIES, @@ -3035,34 +3033,11 @@ public class NotificationManagerService extends SystemService { } final int callingUid = Binder.getCallingUid(); - final UserHandle callingUser = Binder.getCallingUserHandle(); + checkCallerIsSameApp(pkg); final boolean isSystemToast = isCallerSystemOrPhone() || PackageManagerService.PLATFORM_PACKAGE_NAME.equals(pkg); - final boolean isPackageSuspended = isPackagePaused(pkg); - final boolean notificationsDisabledForPackage = !areNotificationsEnabledForPackage(pkg, - callingUid); - - final boolean appIsForeground; - final long callingIdentity = Binder.clearCallingIdentity(); - try { - appIsForeground = mActivityManager.getUidImportance(callingUid) - == IMPORTANCE_FOREGROUND; - } finally { - Binder.restoreCallingIdentity(callingIdentity); - } - - if (ENABLE_BLOCKED_TOASTS && !isSystemToast && ((notificationsDisabledForPackage - && !appIsForeground) || isPackageSuspended)) { - Slog.e(TAG, "Suppressing toast from package " + pkg - + (isPackageSuspended ? " due to package suspended." - : " by user request.")); - return; - } - boolean isAppRenderedToast = (callback != null); - if (blockToast(callingUid, isSystemToast, isAppRenderedToast)) { - Slog.w(TAG, "Blocking custom toast from package " + pkg - + " due to package not in the foreground at time the toast was posted"); + if (!checkCanEnqueueToast(pkg, callingUid, isAppRenderedToast, isSystemToast)) { return; } @@ -3116,6 +3091,39 @@ public class NotificationManagerService extends SystemService { } } + private boolean checkCanEnqueueToast(String pkg, int callingUid, + boolean isAppRenderedToast, boolean isSystemToast) { + final boolean isPackageSuspended = isPackagePaused(pkg); + final boolean notificationsDisabledForPackage = !areNotificationsEnabledForPackage(pkg, + callingUid); + + final boolean appIsForeground; + final long callingIdentity = Binder.clearCallingIdentity(); + try { + appIsForeground = mActivityManager.getUidImportance(callingUid) + == IMPORTANCE_FOREGROUND; + } finally { + Binder.restoreCallingIdentity(callingIdentity); + } + + if (!isSystemToast && ((notificationsDisabledForPackage && !appIsForeground) + || isPackageSuspended)) { + Slog.e(TAG, "Suppressing toast from package " + pkg + + (isPackageSuspended ? " due to package suspended." + : " by user request.")); + return false; + } + + if (blockToast(callingUid, isSystemToast, isAppRenderedToast, + isPackageInForegroundForToast(callingUid))) { + Slog.w(TAG, "Blocking custom toast from package " + pkg + + " due to package not in the foreground at time the toast was posted"); + return false; + } + + return true; + } + @Override public void cancelToast(String pkg, IBinder token) { Slog.i(TAG, "cancelToast pkg=" + pkg + " token=" + token); @@ -7540,12 +7548,13 @@ public class NotificationManagerService extends SystemService { boolean isWithinQuota = mToastRateLimiter.isWithinQuota(userId, record.pkg, TOAST_QUOTA_TAG) || isExemptFromRateLimiting(record.pkg, userId); + boolean isPackageInForeground = isPackageInForegroundForToast(record.uid); if (tryShowToast( - record, rateLimitingEnabled, isWithinQuota)) { + record, rateLimitingEnabled, isWithinQuota, isPackageInForeground)) { scheduleDurationReachedLocked(record, lastToastWasTextRecord); mIsCurrentToastShown = true; - if (rateLimitingEnabled) { + if (rateLimitingEnabled && !isPackageInForeground) { mToastRateLimiter.noteEvent(userId, record.pkg, TOAST_QUOTA_TAG); } return; @@ -7561,14 +7570,15 @@ public class NotificationManagerService extends SystemService { /** Returns true if it successfully showed the toast. */ private boolean tryShowToast(ToastRecord record, boolean rateLimitingEnabled, - boolean isWithinQuota) { - if (rateLimitingEnabled && !isWithinQuota) { + boolean isWithinQuota, boolean isPackageInForeground) { + if (rateLimitingEnabled && !isWithinQuota && !isPackageInForeground) { reportCompatRateLimitingToastsChange(record.uid); Slog.w(TAG, "Package " + record.pkg + " is above allowed toast quota, the " + "following toast was blocked and discarded: " + record); return false; } - if (blockToast(record.uid, record.isSystemToast, record.isAppRendered())) { + if (blockToast(record.uid, record.isSystemToast, record.isAppRendered(), + isPackageInForeground)) { Slog.w(TAG, "Blocking custom toast from package " + record.pkg + " due to package not in the foreground at the time of showing the toast"); return false; @@ -7759,10 +7769,11 @@ public class NotificationManagerService extends SystemService { * with targetSdk < R. For apps with targetSdk R+, text toasts are not app-rendered, so * isAppRenderedToast == true means it's a custom toast. */ - private boolean blockToast(int uid, boolean isSystemToast, boolean isAppRenderedToast) { + private boolean blockToast(int uid, boolean isSystemToast, boolean isAppRenderedToast, + boolean isPackageInForeground) { return isAppRenderedToast && !isSystemToast - && !isPackageInForegroundForToast(uid) + && !isPackageInForeground && CompatChanges.isChangeEnabled(CHANGE_BACKGROUND_CUSTOM_TOAST_BLOCK, uid); } 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 8be19f002fa5..91d7430a7077 100755 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -58,7 +58,6 @@ import static android.service.notification.Adjustment.KEY_USER_SENTIMENT; import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ALERTING; import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_CONVERSATIONS; import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ONGOING; -import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_SILENT; import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE; import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL; @@ -5037,7 +5036,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } @Test - public void testToastRateLimiterCanPreventShowCallForCustomToast() throws Exception { + public void testToastRateLimiterWontPreventShowCallForCustomToastWhenInForeground() + throws Exception { final String testPackage = "testPackageName"; assertEquals(0, mService.mToastQueue.size()); mService.isSystemUid = false; @@ -5055,30 +5055,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { INotificationManager nmService = (INotificationManager) mService.mService; nmService.enqueueToast(testPackage, token, callback, 2000, 0); - verify(callback, times(0)).show(any()); - } - - @Test - public void testCustomToastRateLimiterAllowsLimitAvoidanceWithPermission() throws Exception { - final String testPackage = "testPackageName"; - assertEquals(0, mService.mToastQueue.size()); - mService.isSystemUid = false; - setToastRateIsWithinQuota(false); // rate limit reached - // Avoids rate limiting. - setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, true); - - // package is not suspended - when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid))) - .thenReturn(false); - - setAppInForegroundForToasts(mUid, true); - - Binder token = new Binder(); - ITransientNotification callback = mock(ITransientNotification.class); - INotificationManager nmService = (INotificationManager) mService.mService; - - nmService.enqueueToast(testPackage, token, callback, 2000, 0); - verify(callback).show(any()); + verify(callback, times(1)).show(any()); } @Test @@ -5186,12 +5163,14 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } @Test - public void testToastRateLimiterCanPreventShowCallForTextToast() throws Exception { + public void testToastRateLimiterCanPreventShowCallForTextToast_whenInBackground() + throws Exception { final String testPackage = "testPackageName"; assertEquals(0, mService.mToastQueue.size()); mService.isSystemUid = false; setToastRateIsWithinQuota(false); // rate limit reached setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); + setAppInForegroundForToasts(mUid, false); // package is not suspended when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid))) @@ -5206,12 +5185,35 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } @Test + public void testToastRateLimiterWontPreventShowCallForTextToast_whenInForeground() + throws Exception { + final String testPackage = "testPackageName"; + assertEquals(0, mService.mToastQueue.size()); + mService.isSystemUid = false; + setToastRateIsWithinQuota(false); // rate limit reached + setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); + setAppInForegroundForToasts(mUid, true); + + // package is not suspended + when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid))) + .thenReturn(false); + + Binder token = new Binder(); + INotificationManager nmService = (INotificationManager) mService.mService; + + nmService.enqueueTextToast(testPackage, token, "Text", 2000, 0, null); + verify(mStatusBar, times(1)) + .showToast(anyInt(), any(), any(), any(), any(), anyInt(), any()); + } + + @Test public void testTextToastRateLimiterAllowsLimitAvoidanceWithPermission() throws Exception { final String testPackage = "testPackageName"; assertEquals(0, mService.mToastQueue.size()); mService.isSystemUid = false; setToastRateIsWithinQuota(false); // rate limit reached setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, true); + setAppInForegroundForToasts(mUid, false); // package is not suspended when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid))) |