Loading services/core/java/com/android/server/notification/NotificationManagerService.java +28 −9 Original line number Diff line number Diff line Loading @@ -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(); Loading @@ -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()]); } } Loading Loading @@ -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()]); } /** Loading Loading @@ -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; Loading services/tests/uiservicestests/src/com/android/server/notification/ArchiveTest.java +35 −7 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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() { Loading @@ -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) { Loading @@ -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<>(); Loading @@ -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<>(); Loading @@ -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()); Loading @@ -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()); Loading @@ -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()); Loading @@ -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()); Loading Loading @@ -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()); Loading services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +33 −2 Original line number Diff line number Diff line Loading @@ -476,6 +476,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"); Loading Loading @@ -7004,8 +7005,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); Loading Loading @@ -8323,4 +8325,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"); } } } } Loading
services/core/java/com/android/server/notification/NotificationManagerService.java +28 −9 Original line number Diff line number Diff line Loading @@ -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(); Loading @@ -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()]); } } Loading Loading @@ -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()]); } /** Loading Loading @@ -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; Loading
services/tests/uiservicestests/src/com/android/server/notification/ArchiveTest.java +35 −7 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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() { Loading @@ -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) { Loading @@ -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<>(); Loading @@ -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<>(); Loading @@ -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()); Loading @@ -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()); Loading @@ -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()); Loading @@ -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()); Loading Loading @@ -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()); Loading
services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +33 −2 Original line number Diff line number Diff line Loading @@ -476,6 +476,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"); Loading Loading @@ -7004,8 +7005,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); Loading Loading @@ -8323,4 +8325,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"); } } } }