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

Commit 2eb7e4f9 authored by Jan Tomljanovic's avatar Jan Tomljanovic Committed by Android (Google) Code Review
Browse files

Merge "Add permission for avoiding toast rate limiting." into sc-dev

parents c24be7e6 b7ac0ad3
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -3443,6 +3443,14 @@
    <permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW"
        android:protectionLevel="signature" />

    <!-- Allows an application to avoid all toast rate limiting restrictions.
         <p>Not for use by third-party applications.
         @hide
    -->
    <permission android:name="android.permission.UNLIMITED_TOASTS"
                android:protectionLevel="signature" />
    <uses-permission android:name="android.permission.UNLIMITED_TOASTS" />

    <!-- @SystemApi Allows an application to use
         {@link android.view.WindowManager.LayoutsParams#SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS}
         to hide non-system-overlay windows.
+3 −0
Original line number Diff line number Diff line
@@ -437,6 +437,9 @@
    <!-- Permission required for CTS test - ResourceObserverNativeTest -->
    <uses-permission android:name="android.permission.REGISTER_MEDIA_RESOURCE_OBSERVER" />

    <!-- Permission required for CTS test - android.widget.cts.ToastTest -->
    <uses-permission android:name="android.permission.UNLIMITED_TOASTS" />

    <application android:label="@string/app_label"
                android:theme="@android:style/Theme.DeviceDefault.DayNight"
                android:defaultToDeviceProtectedStorage="true"
+16 −2
Original line number Diff line number Diff line
@@ -7490,9 +7490,11 @@ public class NotificationManagerService extends SystemService {
            boolean rateLimitingEnabled =
                    !mToastRateLimitingDisabledUids.contains(record.uid);
            boolean isWithinQuota =
                    mToastRateLimiter.isWithinQuota(userId, record.pkg, TOAST_QUOTA_TAG);
                    mToastRateLimiter.isWithinQuota(userId, record.pkg, TOAST_QUOTA_TAG)
                            || isExemptFromRateLimiting(record.pkg, userId);

            if (tryShowToast(record, rateLimitingEnabled, isWithinQuota)) {
            if (tryShowToast(
                    record, rateLimitingEnabled, isWithinQuota)) {
                scheduleDurationReachedLocked(record, lastToastWasTextRecord);
                mIsCurrentToastShown = true;
                if (rateLimitingEnabled) {
@@ -7526,6 +7528,18 @@ public class NotificationManagerService extends SystemService {
        return record.show();
    }

    private boolean isExemptFromRateLimiting(String pkg, int userId) {
        boolean isExemptFromRateLimiting = false;
        try {
            isExemptFromRateLimiting = mPackageManager.checkPermission(
                    android.Manifest.permission.UNLIMITED_TOASTS, pkg, userId)
                    == PackageManager.PERMISSION_GRANTED;
        } catch (RemoteException e) {
            Slog.e(TAG, "Failed to connect with package manager");
        }
        return isExemptFromRateLimiting;
    }

    /** Reports rate limiting toasts compat change (used when the toast was blocked). */
    private void reportCompatRateLimitingToastsChange(int uid) {
        final long id = Binder.clearCallingIdentity();
+68 −2
Original line number Diff line number Diff line
@@ -4910,6 +4910,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        assertEquals(0, mService.mToastQueue.size());
        mService.isSystemUid = false;
        setToastRateIsWithinQuota(true);
        setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);

        // package is not suspended
        when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
@@ -4933,6 +4934,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        assertEquals(0, mService.mToastQueue.size());
        mService.isSystemUid = false;
        setToastRateIsWithinQuota(true);
        setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);

        // package is not suspended
        when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
@@ -4952,6 +4954,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        assertEquals(0, mService.mToastQueue.size());
        mService.isSystemUid = false;
        setToastRateIsWithinQuota(true);
        setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);

        // package is not suspended
        when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
@@ -4974,11 +4977,12 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
    }

    @Test
    public void testToastRateLimiterCanPreventsShowCallForCustomToast() throws Exception {
    public void testToastRateLimiterCanPreventShowCallForCustomToast() throws Exception {
        final String testPackage = "testPackageName";
        assertEquals(0, mService.mToastQueue.size());
        mService.isSystemUid = false;
        setToastRateIsWithinQuota(false); // rate limit reached
        setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);

        // package is not suspended
        when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
@@ -4994,6 +4998,29 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        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());
    }

    @Test
    public void testCustomToastPostedWhileInForeground_blockedIfAppGoesToBackground()
            throws Exception {
@@ -5001,6 +5028,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        assertEquals(0, mService.mToastQueue.size());
        mService.isSystemUid = false;
        setToastRateIsWithinQuota(true);
        setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);

        // package is not suspended
        when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
@@ -5034,6 +5062,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        assertEquals(0, mService.mToastQueue.size());
        mService.isSystemUid = false;
        setToastRateIsWithinQuota(true);
        setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);

        // package is not suspended
        when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
@@ -5053,6 +5082,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        assertEquals(0, mService.mToastQueue.size());
        mService.isSystemUid = false;
        setToastRateIsWithinQuota(true);
        setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);

        // package is not suspended
        when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
@@ -5072,6 +5102,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        assertEquals(0, mService.mToastQueue.size());
        mService.isSystemUid = false;
        setToastRateIsWithinQuota(true);
        setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);

        // package is not suspended
        when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
@@ -5095,11 +5126,12 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
    }

    @Test
    public void testToastRateLimiterCanPreventsShowCallForTextToast() throws Exception {
    public void testToastRateLimiterCanPreventShowCallForTextToast() throws Exception {
        final String testPackage = "testPackageName";
        assertEquals(0, mService.mToastQueue.size());
        mService.isSystemUid = false;
        setToastRateIsWithinQuota(false); // rate limit reached
        setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);

        // package is not suspended
        when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
@@ -5113,6 +5145,25 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
                .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);

        // 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).showToast(anyInt(), any(), any(), any(), any(), anyInt(), any());
    }

    @Test
    public void backgroundSystemCustomToast_callsSetProcessImportantAsForegroundForToast() throws
            Exception {
@@ -5120,6 +5171,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        assertEquals(0, mService.mToastQueue.size());
        mService.isSystemUid = true;
        setToastRateIsWithinQuota(true);
        setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);

        // package is not suspended
        when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
@@ -5145,6 +5197,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        assertEquals(0, mService.mToastQueue.size());
        mService.isSystemUid = false;
        setToastRateIsWithinQuota(true);
        setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);

        // package is not suspended
        when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
@@ -5166,6 +5219,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        assertEquals(0, mService.mToastQueue.size());
        mService.isSystemUid = false;
        setToastRateIsWithinQuota(true);
        setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);

        // package is not suspended
        when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
@@ -5186,6 +5240,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        assertEquals(0, mService.mToastQueue.size());
        mService.isSystemUid = false;
        setToastRateIsWithinQuota(true);
        setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);

        // package is not suspended
        when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
@@ -5203,6 +5258,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        assertEquals(0, mService.mToastQueue.size());
        mService.isSystemUid = false;
        setToastRateIsWithinQuota(true);
        setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);

        // package is suspended
        when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
@@ -5224,6 +5280,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        assertEquals(0, mService.mToastQueue.size());
        mService.isSystemUid = false;
        setToastRateIsWithinQuota(true);
        setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);

        // package is not suspended
        when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
@@ -5247,6 +5304,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        assertEquals(0, mService.mToastQueue.size());
        mService.isSystemUid = true;
        setToastRateIsWithinQuota(true);
        setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);

        // package is suspended
        when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
@@ -5270,6 +5328,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        assertEquals(0, mService.mToastQueue.size());
        mService.isSystemUid = false;
        setToastRateIsWithinQuota(true);
        setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);

        // package is not suspended
        when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
@@ -5305,6 +5364,13 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
                .thenReturn(isWithinQuota);
    }

    private void setIfPackageHasPermissionToAvoidToastRateLimiting(
            String pkg, boolean hasPermission) throws Exception {
        when(mPackageManager.checkPermission(android.Manifest.permission.UNLIMITED_TOASTS,
                pkg, UserHandle.getUserId(mUid)))
                .thenReturn(hasPermission ? PERMISSION_GRANTED : PERMISSION_DENIED);
    }

    @Test
    public void testOnPanelRevealedAndHidden() {
        int items = 5;