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

Commit b4a9e9c8 authored by Julia Reynolds's avatar Julia Reynolds
Browse files

Allow delegates to read target app notification channels

Test: cts, atest
Fixes: 128852206
Change-Id: I12ddfbdf6f520d29a8ea5fe8e0581bc425c1638b
parent e9e18868
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -90,10 +90,10 @@ interface INotificationManager
    NotificationChannelGroup getPopulatedNotificationChannelGroupForPackage(String pkg, int uid, String groupId, boolean includeDeleted);
    void updateNotificationChannelGroupForPackage(String pkg, int uid, in NotificationChannelGroup group);
    void updateNotificationChannelForPackage(String pkg, int uid, in NotificationChannel channel);
    NotificationChannel getNotificationChannel(String pkg, String channelId);
    NotificationChannel getNotificationChannel(String callingPkg, int userId, String pkg, String channelId);
    NotificationChannel getNotificationChannelForPackage(String pkg, int uid, String channelId, boolean includeDeleted);
    void deleteNotificationChannel(String pkg, String channelId);
    ParceledListSlice getNotificationChannels(String pkg);
    ParceledListSlice getNotificationChannels(String callingPkg, String targetPkg, int userId);
    ParceledListSlice getNotificationChannelsForPackage(String pkg, int uid, boolean includeDeleted);
    int getNumNotificationChannelsForPackage(String pkg, int uid, boolean includeDeleted);
    int getDeletedChannelCount(String pkg, int uid);
+13 −3
Original line number Diff line number Diff line
@@ -716,12 +716,16 @@ public class NotificationManager {
    /**
     * Returns the notification channel settings for a given channel id.
     *
     * The channel must belong to your package, or it will not be returned.
     * <p>The channel must belong to your package, or to a package you are an approved notification
     * delegate for (see {@link #canNotifyAsPackage(String)}), or it will not be returned. To query
     * a channel as a notification delegate, call this method from a context created for that
     * package (see {@link Context#createPackageContext(String, int)}).</p>
     */
    public NotificationChannel getNotificationChannel(String channelId) {
        INotificationManager service = getService();
        try {
            return service.getNotificationChannel(mContext.getPackageName(), channelId);
            return service.getNotificationChannel(mContext.getOpPackageName(),
                    mContext.getUserId(), mContext.getPackageName(), channelId);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
@@ -729,11 +733,17 @@ public class NotificationManager {

    /**
     * Returns all notification channels belonging to the calling package.
     *
     * <p>Approved notification delegates (see {@link #canNotifyAsPackage(String)}) can query
     * notification channels belonging to packages they are the delegate for. To do so, call this
     * method from a context created for that package (see
     * {@link Context#createPackageContext(String, int)}).</p>
     */
    public List<NotificationChannel> getNotificationChannels() {
        INotificationManager service = getService();
        try {
            return service.getNotificationChannels(mContext.getPackageName()).getList();
            return service.getNotificationChannels(mContext.getOpPackageName(),
                    mContext.getPackageName(), mContext.getUserId()).getList();
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
+33 −8
Original line number Diff line number Diff line
@@ -2519,6 +2519,9 @@ public class NotificationManagerService extends SystemService {
                        android.Manifest.permission.INTERACT_ACROSS_USERS,
                        "canNotifyAsPackage for user " + userId);
            }
            if (callingPkg.equals(targetPkg)) {
                return true;
            }
            try {
                ApplicationInfo info =
                        mPackageManager.getApplicationInfo(targetPkg,
@@ -2588,10 +2591,21 @@ public class NotificationManagerService extends SystemService {
        }

        @Override
        public NotificationChannel getNotificationChannel(String pkg, String channelId) {
            checkCallerIsSystemOrSameApp(pkg);
        public NotificationChannel getNotificationChannel(String callingPkg, int userId,
                String targetPkg, String channelId) {
            if (canNotifyAsPackage(callingPkg, targetPkg, userId)
                    || isCallingUidSystem()) {
                int targetUid = -1;
                try {
                    targetUid = mPackageManagerClient.getPackageUidAsUser(targetPkg, userId);
                } catch (NameNotFoundException e) {
                    /* ignore */
                }
                return mPreferencesHelper.getNotificationChannel(
                    pkg, Binder.getCallingUid(), channelId, false /* includeDeleted */);
                        targetPkg, targetUid, channelId, false /* includeDeleted */);
            }
            throw new SecurityException("Pkg " + callingPkg
                    + " cannot read channels for " + targetPkg + " in " + userId);
        }

        @Override
@@ -2726,10 +2740,21 @@ public class NotificationManagerService extends SystemService {
        }

        @Override
        public ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg) {
            checkCallerIsSystemOrSameApp(pkg);
        public ParceledListSlice<NotificationChannel> getNotificationChannels(
                String callingPkg, String targetPkg, int userId) {
            if (canNotifyAsPackage(callingPkg, targetPkg, userId)
                || isCallingUidSystem()) {
                int targetUid = -1;
                try {
                    targetUid = mPackageManagerClient.getPackageUidAsUser(targetPkg, userId);
                } catch (NameNotFoundException e) {
                    /* ignore */
                }
                return mPreferencesHelper.getNotificationChannels(
                    pkg, Binder.getCallingUid(), false /* includeDeleted */);
                        targetPkg, targetUid, false /* includeDeleted */);
            }
            throw new SecurityException("Pkg " + callingPkg
                    + " cannot read channels for " + targetPkg + " in " + userId);
        }

        @Override
+41 −19
Original line number Diff line number Diff line
@@ -391,7 +391,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {

        mBinderService.createNotificationChannels(
                PKG, new ParceledListSlice(Arrays.asList(mTestNotificationChannel)));
        assertNotNull(mBinderService.getNotificationChannel(PKG, TEST_CHANNEL_ID));
        assertNotNull(mBinderService.getNotificationChannel(
                PKG, mContext.getUserId(), PKG, TEST_CHANNEL_ID));
    }

    @After
@@ -497,7 +498,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        mBinderService.createNotificationChannels(PKG,
                new ParceledListSlice(Arrays.asList(channel)));
        final NotificationChannel createdChannel =
                mBinderService.getNotificationChannel(PKG, "id");
                mBinderService.getNotificationChannel(PKG, mContext.getUserId(), PKG, "id");
        assertTrue(createdChannel != null);
    }

@@ -520,8 +521,10 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
                new NotificationChannel("id2", "name", IMPORTANCE_DEFAULT);
        mBinderService.createNotificationChannels(PKG,
                new ParceledListSlice(Arrays.asList(channel1, channel2)));
        assertTrue(mBinderService.getNotificationChannel(PKG, "id1") != null);
        assertTrue(mBinderService.getNotificationChannel(PKG, "id2") != null);
        assertTrue(mBinderService.getNotificationChannel(
                PKG, mContext.getUserId(), PKG, "id1") != null);
        assertTrue(mBinderService.getNotificationChannel(
                PKG, mContext.getUserId(), PKG, "id2") != null);
    }

    @Test
@@ -538,7 +541,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        mBinderService.createNotificationChannels(PKG,
                new ParceledListSlice(Arrays.asList(dupeChannel)));
        final NotificationChannel createdChannel =
                mBinderService.getNotificationChannel(PKG, "id");
                mBinderService.getNotificationChannel(PKG, mContext.getUserId(), PKG, "id");
        assertEquals(IMPORTANCE_DEFAULT, createdChannel.getImportance());
    }

@@ -556,7 +559,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        mBinderService.createNotificationChannels(PKG,
                new ParceledListSlice(Arrays.asList(dupeChannel)));
        final NotificationChannel createdChannel =
                mBinderService.getNotificationChannel(PKG, "id");
                mBinderService.getNotificationChannel(PKG, mContext.getUserId(), PKG, "id");
        assertEquals(NotificationManager.IMPORTANCE_LOW, createdChannel.getImportance());
    }

@@ -579,7 +582,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        mBinderService.createNotificationChannels(PKG,
                new ParceledListSlice(Arrays.asList(dupeChannel)));
        final NotificationChannel createdChannel =
                mBinderService.getNotificationChannel(PKG, "id");
                mBinderService.getNotificationChannel(PKG, mContext.getUserId(), PKG, "id");
        assertEquals(IMPORTANCE_HIGH, createdChannel.getImportance());
    }

@@ -593,7 +596,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        mBinderService.createNotificationChannels(PKG,
                new ParceledListSlice(Arrays.asList(channel1, channel2)));
        final NotificationChannel createdChannel =
                mBinderService.getNotificationChannel(PKG, "id");
                mBinderService.getNotificationChannel(PKG, mContext.getUserId(), PKG, "id");
        assertEquals(IMPORTANCE_DEFAULT, createdChannel.getImportance());
    }

@@ -646,8 +649,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        assertEquals(1, mBinderService.getActiveNotifications(sbn.getPackageName()).length);
        assertEquals(IMPORTANCE_LOW,
                mService.getNotificationRecord(sbn.getKey()).getImportance());
        assertEquals(IMPORTANCE_LOW,
                mBinderService.getNotificationChannel(PKG, channel.getId()).getImportance());
        assertEquals(IMPORTANCE_LOW, mBinderService.getNotificationChannel(
                PKG, mContext.getUserId(), PKG, channel.getId()).getImportance());
    }

    @Test
@@ -664,8 +667,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
                new NotificationChannel("blockedbyuser", "name", IMPORTANCE_NONE);
        mBinderService.updateNotificationChannelForPackage(PKG, mUid, update);
        waitForIdle();
        assertEquals(IMPORTANCE_NONE,
                mBinderService.getNotificationChannel(PKG, channel.getId()).getImportance());
        assertEquals(IMPORTANCE_NONE, mBinderService.getNotificationChannel(
                PKG, mContext.getUserId(), PKG, channel.getId()).getImportance());

        StatusBarNotification sbn = generateNotificationRecord(channel).sbn;
        sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
@@ -677,8 +680,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        assertEquals(1, mBinderService.getActiveNotifications(sbn.getPackageName()).length);
        assertEquals(IMPORTANCE_LOW,
                mService.getNotificationRecord(sbn.getKey()).getImportance());
        assertEquals(IMPORTANCE_LOW,
                mBinderService.getNotificationChannel(PKG, channel.getId()).getImportance());
        assertEquals(IMPORTANCE_LOW, mBinderService.getNotificationChannel(
                PKG, mContext.getUserId(), PKG, channel.getId()).getImportance());
        mBinderService.cancelNotificationWithTag(PKG, "tag", sbn.getId(), sbn.getUserId());
        waitForIdle();

@@ -686,8 +689,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        update.setFgServiceShown(true);
        mBinderService.updateNotificationChannelForPackage(PKG, mUid, update);
        waitForIdle();
        assertEquals(IMPORTANCE_NONE,
                mBinderService.getNotificationChannel(PKG, channel.getId()).getImportance());
        assertEquals(IMPORTANCE_NONE, mBinderService.getNotificationChannel(
                PKG, mContext.getUserId(), PKG, channel.getId()).getImportance());

        sbn = generateNotificationRecord(channel).sbn;
        sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
@@ -697,8 +700,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        // The second time it is shown, we keep the user's preference.
        assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length);
        assertNull(mService.getNotificationRecord(sbn.getKey()));
        assertEquals(IMPORTANCE_NONE,
                mBinderService.getNotificationChannel(PKG, channel.getId()).getImportance());
        assertEquals(IMPORTANCE_NONE, mBinderService.getNotificationChannel(
                PKG, mContext.getUserId(), PKG, channel.getId()).getImportance());
    }

    @Test
@@ -2692,7 +2695,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
                mService.getNotificationRecord(sbn.getKey()).getImportance());

        NotificationChannel defaultChannel = mBinderService.getNotificationChannel(
                preOPkg, NotificationChannel.DEFAULT_CHANNEL_ID);
                preOPkg, mContext.getUserId(), preOPkg, NotificationChannel.DEFAULT_CHANNEL_ID);
        assertEquals(IMPORTANCE_UNSPECIFIED, defaultChannel.getImportance());
    }

@@ -4191,6 +4194,25 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        mBinderService.canNotifyAsPackage("src", "target", mContext.getUserId() + 1);
    }

    @Test
    public void testgetNotificationChannels_crossUser() throws Exception {
        // same user no problem
        mBinderService.getNotificationChannels("src", "target", mContext.getUserId());

        // cross user, no permission, problem
        try {
            mBinderService.getNotificationChannels("src", "target", mContext.getUserId() + 1);
            fail("Should not be callable cross user without cross user permission");
        } catch (SecurityException e) {
            // good
        }

        // cross user, with permission, no problem
        TestablePermissions perms = mContext.getTestablePermissions();
        perms.setPermission(android.Manifest.permission.INTERACT_ACROSS_USERS, PERMISSION_GRANTED);
        mBinderService.getNotificationChannels("src", "target", mContext.getUserId() + 1);
    }

    @Test
    public void setDefaultAssistantForUser_fromConfigXml() {
        clearDeviceConfig();