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

Commit bf37f650 authored by WoongKi Min's avatar WoongKi Min
Browse files

Prevent FGS notification from exceeding allowed

As only the FGS flag is removed by removeForegroundServiceFlagFromNotification,
it exceeds the package limit(MAX_PACKAGE_NOTIFICATIONS).
And eventually OutOfMemory occurs and the device is reset.
When the flag is removed, check in the same way the normal notification to prevent problems.

Test: Searching for images in the Chrome browser
Test: Download more than 50 images
Test: Check NotificationRecord count in Notification dump
Change-Id: Iacbc3a3e545f62d15bae5245ebcf6ed47f5c83a8
parent 3ea732de
Loading
Loading
Loading
Loading
+56 −14
Original line number Original line Diff line number Diff line
@@ -6275,6 +6275,24 @@ public class NotificationManagerService extends SystemService {
            checkCallerIsSystem();
            checkCallerIsSystem();
            mHandler.post(() -> {
            mHandler.post(() -> {
                synchronized (mNotificationLock) {
                synchronized (mNotificationLock) {
                    int count = getNotificationCount(pkg, userId);
                    boolean removeFgsNotification = false;
                    if (count > MAX_PACKAGE_NOTIFICATIONS) {
                        mUsageStats.registerOverCountQuota(pkg);
                        removeFgsNotification = true;
                    }
                    if (removeFgsNotification) {
                        NotificationRecord r = findNotificationLocked(pkg, null, notificationId,
                                userId);
                        if (r != null) {
                            if (DBG) {
                                Slog.d(TAG, "Remove FGS flag not allow. Cancel FGS notification");
                            }
                            removeFromNotificationListsLocked(r);
                            cancelNotificationLocked(r, false, REASON_APP_CANCEL, true,
                                    null, SystemClock.elapsedRealtime());
                        }
                    } else {
                        // strip flag from all enqueued notifications. listeners will be informed
                        // strip flag from all enqueued notifications. listeners will be informed
                        // in post runnable.
                        // in post runnable.
                        List<NotificationRecord> enqueued = findNotificationsByListLocked(
                        List<NotificationRecord> enqueued = findNotificationsByListLocked(
@@ -6292,6 +6310,7 @@ public class NotificationManagerService extends SystemService {
                            mListeners.notifyPostedLocked(r, r);
                            mListeners.notifyPostedLocked(r, r);
                        }
                        }
                    }
                    }
                }
            });
            });
        }
        }
@@ -6967,6 +6986,29 @@ public class NotificationManagerService extends SystemService {
        return mPermissionHelper.hasPermission(uid);
        return mPermissionHelper.hasPermission(uid);
    }
    }
    private int getNotificationCount(String pkg, int userId) {
        int count = 0;
        synchronized (mNotificationLock) {
            final int numListSize = mNotificationList.size();
            for (int i = 0; i < numListSize; i++) {
                final NotificationRecord existing = mNotificationList.get(i);
                if (existing.getSbn().getPackageName().equals(pkg)
                        && existing.getSbn().getUserId() == userId) {
                    count++;
                }
            }
            final int numEnqSize = mEnqueuedNotifications.size();
            for (int i = 0; i < numEnqSize; i++) {
                final NotificationRecord existing = mEnqueuedNotifications.get(i);
                if (existing.getSbn().getPackageName().equals(pkg)
                        && existing.getSbn().getUserId() == userId) {
                    count++;
                }
            }
        }
        return count;
    }
    protected int getNotificationCount(String pkg, int userId, int excludedId,
    protected int getNotificationCount(String pkg, int userId, int excludedId,
            String excludedTag) {
            String excludedTag) {
        int count = 0;
        int count = 0;
+56 −0
Original line number Original line Diff line number Diff line
@@ -6038,6 +6038,62 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        assertEquals(0, captor.getValue().getNotification().flags);
        assertEquals(0, captor.getValue().getNotification().flags);
    }
    }


    @Test
    public void testCannotRemoveForegroundFlagWhenOverLimit_enqueued() {
        for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) {
            Notification n = new Notification.Builder(mContext, "").build();
            StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, i, null, mUid, 0,
                    n, UserHandle.getUserHandleForUid(mUid), null, 0);
            NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
            mService.addEnqueuedNotification(r);
        }
        Notification n = new Notification.Builder(mContext, "").build();
        n.flags |= FLAG_FOREGROUND_SERVICE;

        StatusBarNotification sbn = new StatusBarNotification(PKG, PKG,
                NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS, null, mUid, 0,
                n, UserHandle.getUserHandleForUid(mUid), null, 0);
        NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);

        mService.addEnqueuedNotification(r);

        mInternalService.removeForegroundServiceFlagFromNotification(
                PKG, r.getSbn().getId(), r.getSbn().getUserId());

        waitForIdle();

        assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS,
                mService.getNotificationRecordCount());
    }

    @Test
    public void testCannotRemoveForegroundFlagWhenOverLimit_posted() {
        for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) {
            Notification n = new Notification.Builder(mContext, "").build();
            StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, i, null, mUid, 0,
                    n, UserHandle.getUserHandleForUid(mUid), null, 0);
            NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
            mService.addNotification(r);
        }
        Notification n = new Notification.Builder(mContext, "").build();
        n.flags |= FLAG_FOREGROUND_SERVICE;

        StatusBarNotification sbn = new StatusBarNotification(PKG, PKG,
                NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS, null, mUid, 0,
                n, UserHandle.getUserHandleForUid(mUid), null, 0);
        NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);

        mService.addNotification(r);

        mInternalService.removeForegroundServiceFlagFromNotification(
                PKG, r.getSbn().getId(), r.getSbn().getUserId());

        waitForIdle();

        assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS,
                mService.getNotificationRecordCount());
    }

    @Test
    @Test
    public void testAllowForegroundCustomToasts() throws Exception {
    public void testAllowForegroundCustomToasts() throws Exception {
        final String testPackage = "testPackageName";
        final String testPackage = "testPackageName";