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

Commit f315ba91 authored by Julia Reynolds's avatar Julia Reynolds Committed by Android Build Coastguard Worker
Browse files

Filter notification APIs by user

Specifically getActiveNotifications and
getHistoricalNotifications

Test: atest NotificationManagerServiceTest
Bug: 214999128
Change-Id: I2eba0a592fa33ed25e1ac3919f1b2631e5db4258
Merged-In: I2eba0a592fa33ed25e1ac3919f1b2631e5db4258
(cherry picked from commit 73745b16)
Merged-In: I2eba0a592fa33ed25e1ac3919f1b2631e5db4258
parent 58700935
Loading
Loading
Loading
Loading
+28 −9
Original line number Diff line number Diff line
@@ -658,7 +658,14 @@ public class NotificationManagerService extends SystemService {
            return mBuffer.descendingIterator();
        }

        public StatusBarNotification[] getArray(int count, boolean includeSnoozed) {
        public StatusBarNotification[] getArray(UserManager um, int count, boolean includeSnoozed) {
            ArrayList<Integer> currentUsers = new ArrayList<>();
            currentUsers.add(UserHandle.USER_ALL);
            Binder.withCleanCallingIdentity(() -> {
                for (int user : um.getProfileIds(ActivityManager.getCurrentUser(), false)) {
                    currentUsers.add(user);
                }
            });
            synchronized (mBufferLock) {
                if (count == 0) count = mBufferSize;
                List<StatusBarNotification> a = new ArrayList();
@@ -667,10 +674,12 @@ public class NotificationManagerService extends SystemService {
                while (iter.hasNext() && i < count) {
                    Pair<StatusBarNotification, Integer> pair = iter.next();
                    if (pair.second != REASON_SNOOZED || includeSnoozed) {
                        if (currentUsers.contains(pair.first.getUserId())) {
                            i++;
                            a.add(pair.first);
                        }
                    }
                }
                return a.toArray(new StatusBarNotification[a.size()]);
            }
        }
@@ -4042,22 +4051,32 @@ public class NotificationManagerService extends SystemService {
                    android.Manifest.permission.ACCESS_NOTIFICATIONS,
                    "NotificationManagerService.getActiveNotifications");

            StatusBarNotification[] tmp = null;
            ArrayList<StatusBarNotification> tmp = new ArrayList<>();
            int uid = Binder.getCallingUid();

            ArrayList<Integer> currentUsers = new ArrayList<>();
            currentUsers.add(UserHandle.USER_ALL);
            Binder.withCleanCallingIdentity(() -> {
                for (int user : mUm.getProfileIds(ActivityManager.getCurrentUser(), false)) {
                    currentUsers.add(user);
                }
            });

            // noteOp will check to make sure the callingPkg matches the uid
            if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg,
                    callingAttributionTag, null)
                    == AppOpsManager.MODE_ALLOWED) {
                synchronized (mNotificationLock) {
                    tmp = new StatusBarNotification[mNotificationList.size()];
                    final int N = mNotificationList.size();
                    for (int i = 0; i < N; i++) {
                        tmp[i] = mNotificationList.get(i).getSbn();
                        final StatusBarNotification sbn = mNotificationList.get(i).getSbn();
                        if (currentUsers.contains(sbn.getUserId())) {
                            tmp.add(sbn);
                        }
                    }
                }
            return tmp;
            }
            return tmp.toArray(new StatusBarNotification[tmp.size()]);
        }

        /**
@@ -4166,7 +4185,7 @@ public class NotificationManagerService extends SystemService {
                    callingAttributionTag, null)
                    == AppOpsManager.MODE_ALLOWED) {
                synchronized (mArchive) {
                    tmp = mArchive.getArray(count, includeSnoozed);
                    tmp = mArchive.getArray(mUm, count, includeSnoozed);
                }
            }
            return tmp;
+35 −7
Original line number Diff line number Diff line
@@ -15,16 +15,22 @@
 */
package com.android.server.notification;

import static android.os.UserHandle.USER_ALL;
import static android.os.UserHandle.USER_CURRENT;
import static android.os.UserHandle.USER_NULL;
import static android.os.UserHandle.USER_SYSTEM;
import static android.service.notification.NotificationListenerService.REASON_CANCEL;

import static com.google.common.truth.Truth.assertThat;

import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.when;

import android.app.Notification;
import android.os.UserHandle;
import android.os.UserManager;
import android.service.notification.StatusBarNotification;
import android.test.suitebuilder.annotation.SmallTest;

@@ -35,6 +41,7 @@ import com.android.server.UiServiceTestCase;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import java.util.ArrayList;
@@ -51,6 +58,8 @@ public class ArchiveTest extends UiServiceTestCase {
    private static final int SIZE = 5;

    private NotificationManagerService.Archive mArchive;
    @Mock
    private UserManager mUm;

    @Before
    public void setUp() {
@@ -59,6 +68,9 @@ public class ArchiveTest extends UiServiceTestCase {
        mArchive = new NotificationManagerService.Archive(SIZE);
        mArchive.updateHistoryEnabled(USER_SYSTEM, true);
        mArchive.updateHistoryEnabled(USER_CURRENT, true);

        when(mUm.getProfileIds(anyInt(), anyBoolean())).thenReturn(
                new int[] {USER_CURRENT, USER_SYSTEM});
    }

    private StatusBarNotification getNotification(String pkg, int id, UserHandle user) {
@@ -70,7 +82,6 @@ public class ArchiveTest extends UiServiceTestCase {
                pkg, pkg, id, null, 0, 0, n, user, null, System.currentTimeMillis());
    }


    @Test
    public void testRecordAndRead() {
        List<String> expected = new ArrayList<>();
@@ -81,13 +92,29 @@ public class ArchiveTest extends UiServiceTestCase {
            mArchive.record(sbn, REASON_CANCEL);
        }

        List<StatusBarNotification> actual = Arrays.asList(mArchive.getArray(SIZE, true));
        List<StatusBarNotification> actual = Arrays.asList(mArchive.getArray(mUm, SIZE, true));
        assertThat(actual).hasSize(expected.size());
        for (StatusBarNotification sbn : actual) {
            assertThat(expected).contains(sbn.getKey());
        }
    }

    @Test
    public void testCrossUser() {
        mArchive.record(getNotification("pkg", 1, UserHandle.of(USER_SYSTEM)), REASON_CANCEL);
        mArchive.record(getNotification("pkg", 2, UserHandle.of(USER_CURRENT)), REASON_CANCEL);
        mArchive.record(getNotification("pkg", 3, UserHandle.of(USER_ALL)), REASON_CANCEL);
        mArchive.record(getNotification("pkg", 4, UserHandle.of(USER_NULL)), REASON_CANCEL);

        List<StatusBarNotification> actual = Arrays.asList(mArchive.getArray(mUm, SIZE, true));
        assertThat(actual).hasSize(3);
        for (StatusBarNotification sbn : actual) {
            if (sbn.getUserId() == USER_NULL) {
                fail("leaked notification from wrong user");
            }
        }
    }

    @Test
    public void testRecordAndRead_overLimit() {
        List<String> expected = new ArrayList<>();
@@ -99,7 +126,8 @@ public class ArchiveTest extends UiServiceTestCase {
            }
        }

        List<StatusBarNotification> actual = Arrays.asList(mArchive.getArray((SIZE * 2), true));
        List<StatusBarNotification> actual = Arrays.asList(
                mArchive.getArray(mUm, (SIZE * 2), true));
        assertThat(actual).hasSize(expected.size());
        for (StatusBarNotification sbn : actual) {
            assertThat(expected).contains(sbn.getKey());
@@ -119,7 +147,7 @@ public class ArchiveTest extends UiServiceTestCase {
            }
        }

        List<StatusBarNotification> actual = Arrays.asList(mArchive.getArray(SIZE, true));
        List<StatusBarNotification> actual = Arrays.asList(mArchive.getArray(mUm, SIZE, true));
        assertThat(actual).hasSize(expected.size());
        for (StatusBarNotification sbn : actual) {
            assertThat(expected).contains(sbn.getKey());
@@ -140,7 +168,7 @@ public class ArchiveTest extends UiServiceTestCase {
        }
        mArchive.updateHistoryEnabled(USER_CURRENT, false);

        List<StatusBarNotification> actual = Arrays.asList(mArchive.getArray(SIZE, true));
        List<StatusBarNotification> actual = Arrays.asList(mArchive.getArray(mUm, SIZE, true));
        assertThat(actual).hasSize(expected.size());
        for (StatusBarNotification sbn : actual) {
            assertThat(expected).contains(sbn.getKey());
@@ -165,7 +193,7 @@ public class ArchiveTest extends UiServiceTestCase {
        }
        mArchive.removeChannelNotifications("pkg", USER_CURRENT, "test0");
        mArchive.removeChannelNotifications("pkg", USER_CURRENT, "test" + (SIZE - 2));
        List<StatusBarNotification> actual = Arrays.asList(mArchive.getArray(SIZE, true));
        List<StatusBarNotification> actual = Arrays.asList(mArchive.getArray(mUm, SIZE, true));
        assertThat(actual).hasSize(expected.size());
        for (StatusBarNotification sbn : actual) {
            assertThat(expected).contains(sbn.getKey());
@@ -215,7 +243,7 @@ public class ArchiveTest extends UiServiceTestCase {
            fail("Concurrent modification exception");
        }

        List<StatusBarNotification> actual = Arrays.asList(mArchive.getArray(SIZE, true));
        List<StatusBarNotification> actual = Arrays.asList(mArchive.getArray(mUm, SIZE, true));
        assertThat(actual).hasSize(expected.size());
        for (StatusBarNotification sbn : actual) {
            assertThat(expected).contains(sbn.getKey());
+33 −2
Original line number Diff line number Diff line
@@ -475,6 +475,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        when(mPackageManager.getPackagesForUid(mUid)).thenReturn(new String[]{PKG});
        when(mPackageManagerClient.getPackagesForUid(anyInt())).thenReturn(new String[]{PKG});
        mContext.addMockSystemService(AppOpsManager.class, mock(AppOpsManager.class));
        when(mUm.getProfileIds(0, false)).thenReturn(new int[]{0});

        // write to a test file; the system file isn't readable from tests
        mFile = new File(mContext.getCacheDir(), "test.xml");
@@ -6970,8 +6971,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        waitForIdle();

        // A notification exists for the given record
        StatusBarNotification[] notifsBefore = mBinderService.getActiveNotifications(PKG);
        assertEquals(1, notifsBefore.length);
        List<StatusBarNotification> notifsBefore =
                mBinderService.getAppActiveNotifications(PKG, nr.getSbn().getUserId()).getList();
        assertEquals(1, notifsBefore.size());

        reset(mPackageManager);

@@ -8289,4 +8291,33 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        assertTrue(captor.getValue().isPackageAllowed(new VersionedPackage("apples", 1001)));
        assertFalse(captor.getValue().isPackageAllowed(new VersionedPackage("test", 1002)));
    }

    @Test
    public void testGetActiveNotification_filtersUsers() throws Exception {
        when(mUm.getProfileIds(0, false)).thenReturn(new int[]{0, 10});

        NotificationRecord nr0 =
                generateNotificationRecord(mTestNotificationChannel, 0);
        mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag0",
                nr0.getSbn().getId(), nr0.getSbn().getNotification(), nr0.getSbn().getUserId());

        NotificationRecord nr10 =
                generateNotificationRecord(mTestNotificationChannel, 10);
        mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag10",
                nr10.getSbn().getId(), nr10.getSbn().getNotification(), nr10.getSbn().getUserId());

        NotificationRecord nr11 =
                generateNotificationRecord(mTestNotificationChannel, 11);
        mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag11",
                nr11.getSbn().getId(), nr11.getSbn().getNotification(), nr11.getSbn().getUserId());
        waitForIdle();

        StatusBarNotification[] notifs = mBinderService.getActiveNotifications(PKG);
        assertEquals(2, notifs.length);
        for (StatusBarNotification sbn : notifs) {
            if (sbn.getUserId() == 11) {
                fail("leaked data across users");
            }
        }
    }
}