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

Commit 33342e21 authored by Julia Reynolds's avatar Julia Reynolds
Browse files

Make bundle channel even more system reserved

- Apps cannot post to these channels (no bypassing the notif
permission, no diluting the content)
- Don't show the notification runtime permission prompt if
the only channels that exist are bundle channels (not a strong
enough signal that the app intends to send notifications)

Test: NotificationManagerServiceTest
Test: PreferencesHelperTest
Test: NotificationPermissionTest
Test: NotificationManagerTest
Fixes: 373476732
Flag: android.service.notification.notification_classification
Change-Id: I4bdf475e83dfd174482f9ed239276a4e0cdee5fd
parent 8ec3af27
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -44,7 +44,7 @@ public interface NotificationManagerInternal {

    void onConversationRemoved(String pkg, int uid, Set<String> shortcuts);

    /** Get the number of notification channels for a given package */
    /** Get the number of app created notification channels for a given package */
    int getNumNotificationChannelsForPackage(String pkg, int uid, boolean includeDeleted);

    /** Does the specified package/uid have permission to post notifications? */
+26 −14
Original line number Diff line number Diff line
@@ -4392,8 +4392,9 @@ public class NotificationManagerService extends SystemService {
            List<NotificationChannel> channels = channelsList.getList();
            final int channelsSize = channels.size();
            ParceledListSlice<NotificationChannel> oldChannels =
                    mPreferencesHelper.getNotificationChannels(pkg, uid, true);
            final boolean hadChannel = oldChannels != null && !oldChannels.getList().isEmpty();
                    mPreferencesHelper.getNotificationChannels(pkg, uid, true, false);
            final boolean hadNonBundleChannel =
                    oldChannels != null && !oldChannels.getList().isEmpty();
            boolean needsPolicyFileChange = false;
            boolean hasRequestedNotificationPermission = false;
            for (int i = 0; i < channelsSize; i++) {
@@ -4410,13 +4411,18 @@ public class NotificationManagerService extends SystemService {
                            mPreferencesHelper.getNotificationChannel(pkg, uid, channel.getId(),
                                    false),
                            NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
                    boolean hasChannel = hadChannel || hasRequestedNotificationPermission;
                    if (!hasChannel) {
                    boolean hasNonBundleChannel =
                            hadNonBundleChannel || hasRequestedNotificationPermission;
                    if (!hasNonBundleChannel) {
                        ParceledListSlice<NotificationChannel> currChannels =
                                mPreferencesHelper.getNotificationChannels(pkg, uid, true);
                        hasChannel = currChannels != null && !currChannels.getList().isEmpty();
                    }
                    if (!hadChannel && hasChannel && !hasRequestedNotificationPermission
                                mPreferencesHelper.getNotificationChannels(pkg, uid, true, false);
                        hasNonBundleChannel =
                                currChannels != null && !currChannels.getList().isEmpty();
                    }
                    // show perm prompt if new non-bundle channel added and the user has not
                    // seen the prompt
                    if (!hadNonBundleChannel && hasNonBundleChannel
                            && !hasRequestedNotificationPermission
                            && startingTaskId != ActivityTaskManager.INVALID_TASK_ID) {
                        hasRequestedNotificationPermission = true;
                        if (mPermissionPolicyInternal == null) {
@@ -4651,7 +4657,7 @@ public class NotificationManagerService extends SystemService {
        public ParceledListSlice<NotificationChannel> getNotificationChannelsForPackage(String pkg,
                int uid, boolean includeDeleted) {
            enforceSystemOrSystemUI("getNotificationChannelsForPackage");
            return mPreferencesHelper.getNotificationChannels(pkg, uid, includeDeleted);
            return mPreferencesHelper.getNotificationChannels(pkg, uid, includeDeleted, true);
        }
        @Override
@@ -4783,7 +4789,7 @@ public class NotificationManagerService extends SystemService {
                    /* ignore */
                }
                return mPreferencesHelper.getNotificationChannels(
                        targetPkg, targetUid, false /* includeDeleted */);
                        targetPkg, targetUid, false /* includeDeleted */, true);
            }
            throw new SecurityException("Pkg " + callingPkg
                    + " cannot read channels for " + targetPkg + " in " + userId);
@@ -6652,7 +6658,7 @@ public class NotificationManagerService extends SystemService {
            verifyPrivilegedListener(token, user, true);
            return mPreferencesHelper.getNotificationChannels(pkg,
                    getUidForPackageAndUser(pkg, user), false /* includeDeleted */);
                    getUidForPackageAndUser(pkg, user), false /* includeDeleted */, true);
        }
        @Override
@@ -7693,8 +7699,9 @@ public class NotificationManagerService extends SystemService {
    }
    int getNumNotificationChannelsForPackage(String pkg, int uid, boolean includeDeleted) {
        return mPreferencesHelper.getNotificationChannels(pkg, uid, includeDeleted).getList()
                .size();
        // don't show perm prompt if the only channels are bundle channels
        return mPreferencesHelper.getNotificationChannels(
                pkg, uid, includeDeleted, false).getList().size();
    }
    void cancelNotificationInternal(String pkg, String opPkg, int callingUid, int callingPid,
@@ -8005,11 +8012,16 @@ public class NotificationManagerService extends SystemService {
    }
    /**
     * Returns a channel, if exists, and restores deleted conversation channels.
     * Returns a channel, if exists and is not a bundle channel, and restores deleted
     * conversation channels.
     */
    @Nullable
    private NotificationChannel getNotificationChannelRestoreDeleted(String pkg,
            int callingUid, int notificationUid, String channelId, String conversationId) {
        if (SYSTEM_RESERVED_IDS.contains(channelId)) {
            // apps cannot post to these channels directly, in case they post incorrect content
            return null;
        }
        // Restore a deleted conversation channel, if exists. Otherwise use the parent channel.
        NotificationChannel channel = mPreferencesHelper.getConversationNotificationChannel(
                pkg, notificationUid, channelId, conversationId,
+4 −2
Original line number Diff line number Diff line
@@ -1870,7 +1870,7 @@ public class PreferencesHelper implements RankingConfig {

    @Override
    public ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg, int uid,
            boolean includeDeleted) {
            boolean includeDeleted, boolean includeBundles) {
        Objects.requireNonNull(pkg);
        List<NotificationChannel> channels = new ArrayList<>();
        synchronized (mLock) {
@@ -1882,9 +1882,11 @@ public class PreferencesHelper implements RankingConfig {
            for (int i = 0; i < N; i++) {
                final NotificationChannel nc = r.channels.valueAt(i);
                if (includeDeleted || !nc.isDeleted()) {
                    if (includeBundles || !SYSTEM_RESERVED_IDS.contains(nc.getId())) {
                        channels.add(nc);
                    }
                }
            }
            return new ParceledListSlice<>(channels);
        }
    }
+1 −1
Original line number Diff line number Diff line
@@ -55,5 +55,5 @@ public interface RankingConfig {
    void permanentlyDeleteNotificationChannel(String pkg, int uid, String channelId);
    void permanentlyDeleteNotificationChannels(String pkg, int uid);
    ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg, int uid,
            boolean includeDeleted);
            boolean includeDeleted, boolean includeBundles);
}
+21 −5
Original line number Diff line number Diff line
@@ -4838,7 +4838,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
                null, mPkg, Process.myUserHandle());
        verify(mPreferencesHelper, times(1)).getNotificationChannels(
                anyString(), anyInt(), anyBoolean());
                anyString(), anyInt(), anyBoolean(), anyBoolean());
    }
    @Test
@@ -4856,7 +4856,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        }
        verify(mPreferencesHelper, never()).getNotificationChannels(
                anyString(), anyInt(), anyBoolean());
                anyString(), anyInt(), anyBoolean(), anyBoolean());
    }
    @Test
@@ -4871,7 +4871,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
                null, mPkg, Process.myUserHandle());
        verify(mPreferencesHelper, times(1)).getNotificationChannels(
                anyString(), anyInt(), anyBoolean());
                anyString(), anyInt(), anyBoolean(), anyBoolean());
    }
    @Test
@@ -4891,7 +4891,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        }
        verify(mPreferencesHelper, never()).getNotificationChannels(
                anyString(), anyInt(), anyBoolean());
                anyString(), anyInt(), anyBoolean(), anyBoolean());
    }
    @Test
@@ -4913,7 +4913,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        }
        verify(mPreferencesHelper, never()).getNotificationChannels(
                anyString(), anyInt(), anyBoolean());
                anyString(), anyInt(), anyBoolean(), anyBoolean());
    }
    @Test
@@ -17062,4 +17062,20 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        assertThat(mService.hasFlag(captor.getValue().getNotification().flags,
                FLAG_PROMOTED_ONGOING)).isFalse();
    }
    @Test
    @EnableFlags(FLAG_NOTIFICATION_CLASSIFICATION)
    public void testAppCannotUseReservedBundleChannels() throws Exception {
        mBinderService.getBubblePreferenceForPackage(mPkg, mUid);
        NotificationChannel news = mBinderService.getNotificationChannel(
                mPkg, mContext.getUserId(), mPkg, NEWS_ID);
        assertThat(news).isNotNull();
        NotificationRecord nr = generateNotificationRecord(news);
        mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
                nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
        waitForIdle();
        assertThat(mService.mNotificationList).isEmpty();
    }
}
Loading