Loading core/java/android/app/INotificationManager.aidl +1 −0 Original line number Diff line number Diff line Loading @@ -114,6 +114,7 @@ interface INotificationManager NotificationChannel getNotificationChannelForPackage(String pkg, int uid, String channelId, String conversationId, boolean includeDeleted); void deleteNotificationChannel(String pkg, String channelId); ParceledListSlice getNotificationChannels(String callingPkg, String targetPkg, int userId); ParceledListSlice getOrCreateNotificationChannels(String callingPkg, String targetPkg, int userId, boolean createPrefsIfNeeded); ParceledListSlice getNotificationChannelsForPackage(String pkg, int uid, boolean includeDeleted); int getNumNotificationChannelsForPackage(String pkg, int uid, boolean includeDeleted); int getDeletedChannelCount(String pkg, int uid); Loading core/java/android/app/NotificationManager.java +12 −8 Original line number Diff line number Diff line Loading @@ -1211,7 +1211,8 @@ public class NotificationManager { mNotificationChannelListCache.query(new NotificationChannelQuery( mContext.getOpPackageName(), mContext.getPackageName(), mContext.getUserId()))); mContext.getUserId(), true))); // create (default channel) if needed } else { INotificationManager service = service(); try { Loading Loading @@ -1239,7 +1240,8 @@ public class NotificationManager { mNotificationChannelListCache.query(new NotificationChannelQuery( mContext.getOpPackageName(), mContext.getPackageName(), mContext.getUserId()))); mContext.getUserId(), true))); // create (default channel) if needed } else { INotificationManager service = service(); try { Loading @@ -1265,7 +1267,8 @@ public class NotificationManager { return mNotificationChannelListCache.query(new NotificationChannelQuery( mContext.getOpPackageName(), mContext.getPackageName(), mContext.getUserId())); mContext.getUserId(), false)); } else { INotificationManager service = service(); try { Loading Loading @@ -1405,8 +1408,8 @@ public class NotificationManager { public List<NotificationChannel> apply(NotificationChannelQuery query) { INotificationManager service = service(); try { return service.getNotificationChannels(query.callingPkg, query.targetPkg, query.userId).getList(); return service.getOrCreateNotificationChannels(query.callingPkg, query.targetPkg, query.userId, query.createIfNeeded).getList(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } Loading Loading @@ -1434,7 +1437,8 @@ public class NotificationManager { private record NotificationChannelQuery( String callingPkg, String targetPkg, int userId) {} int userId, boolean createIfNeeded) {} /** * @hide Loading core/tests/coretests/src/android/app/NotificationManagerTest.java +24 −20 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package android.app; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.atLeast; Loading Loading @@ -269,8 +270,9 @@ public class NotificationManagerTest { // It doesn't matter what the returned contents are, as long as we return a channel. // This setup must set up getNotificationChannels(), as that's the method called. when(mNotificationManager.mBackendService.getNotificationChannels(any(), any(), anyInt())).thenReturn(new ParceledListSlice<>(List.of(exampleChannel()))); when(mNotificationManager.mBackendService.getOrCreateNotificationChannels(any(), any(), anyInt(), anyBoolean())).thenReturn( new ParceledListSlice<>(List.of(exampleChannel()))); // ask for the same channel 100 times without invalidating the cache for (int i = 0; i < 100; i++) { Loading @@ -282,7 +284,7 @@ public class NotificationManagerTest { NotificationChannel unused = mNotificationManager.getNotificationChannel("id"); verify(mNotificationManager.mBackendService, times(2)) .getNotificationChannels(any(), any(), anyInt()); .getOrCreateNotificationChannels(any(), any(), anyInt(), anyBoolean()); } @Test Loading @@ -295,23 +297,24 @@ public class NotificationManagerTest { NotificationChannel c2 = new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_NONE); when(mNotificationManager.mBackendService.getNotificationChannels(any(), any(), anyInt())).thenReturn(new ParceledListSlice<>(List.of(c1, c2))); when(mNotificationManager.mBackendService.getOrCreateNotificationChannels(any(), any(), anyInt(), anyBoolean())).thenReturn(new ParceledListSlice<>(List.of(c1, c2))); assertThat(mNotificationManager.getNotificationChannel("id1")).isEqualTo(c1); assertThat(mNotificationManager.getNotificationChannel("id2")).isEqualTo(c2); assertThat(mNotificationManager.getNotificationChannel("id3")).isNull(); verify(mNotificationManager.mBackendService, times(1)) .getNotificationChannels(any(), any(), anyInt()); .getOrCreateNotificationChannels(any(), any(), anyInt(), anyBoolean()); } @Test @EnableFlags(Flags.FLAG_NM_BINDER_PERF_CACHE_CHANNELS) public void getNotificationChannels_cachedUntilInvalidated() throws Exception { NotificationManager.invalidateNotificationChannelCache(); when(mNotificationManager.mBackendService.getNotificationChannels(any(), any(), anyInt())).thenReturn(new ParceledListSlice<>(List.of(exampleChannel()))); when(mNotificationManager.mBackendService.getOrCreateNotificationChannels(any(), any(), anyInt(), anyBoolean())).thenReturn( new ParceledListSlice<>(List.of(exampleChannel()))); // ask for channels 100 times without invalidating the cache for (int i = 0; i < 100; i++) { Loading @@ -323,7 +326,7 @@ public class NotificationManagerTest { List<NotificationChannel> res = mNotificationManager.getNotificationChannels(); verify(mNotificationManager.mBackendService, times(2)) .getNotificationChannels(any(), any(), anyInt()); .getOrCreateNotificationChannels(any(), any(), anyInt(), anyBoolean()); assertThat(res).containsExactlyElementsIn(List.of(exampleChannel())); } Loading @@ -341,8 +344,9 @@ public class NotificationManagerTest { NotificationChannel c2 = new NotificationChannel("other", "name2", NotificationManager.IMPORTANCE_DEFAULT); when(mNotificationManager.mBackendService.getNotificationChannels(any(), any(), anyInt())) .thenReturn(new ParceledListSlice<>(List.of(c1, conv1, c2))); when(mNotificationManager.mBackendService.getOrCreateNotificationChannels(any(), any(), anyInt(), anyBoolean())).thenReturn( new ParceledListSlice<>(List.of(c1, conv1, c2))); // Lookup for channel c1 and c2: returned as expected assertThat(mNotificationManager.getNotificationChannel("id")).isEqualTo(c1); Loading @@ -359,9 +363,9 @@ public class NotificationManagerTest { // Lookup of a nonexistent channel is null assertThat(mNotificationManager.getNotificationChannel("id3")).isNull(); // All of that should have been one call to getNotificationChannels() // All of that should have been one call to getOrCreateNotificationChannels() verify(mNotificationManager.mBackendService, times(1)) .getNotificationChannels(any(), any(), anyInt()); .getOrCreateNotificationChannels(any(), any(), anyInt(), anyBoolean()); } @Test Loading @@ -381,12 +385,12 @@ public class NotificationManagerTest { NotificationChannel channel3 = channel1.copy(); channel3.setName("name3"); when(mNotificationManager.mBackendService.getNotificationChannels(any(), eq(pkg1), eq(userId))).thenReturn(new ParceledListSlice<>(List.of(channel1))); when(mNotificationManager.mBackendService.getNotificationChannels(any(), eq(pkg2), eq(userId))).thenReturn(new ParceledListSlice<>(List.of(channel2))); when(mNotificationManager.mBackendService.getNotificationChannels(any(), eq(pkg1), eq(userId1))).thenReturn(new ParceledListSlice<>(List.of(channel3))); when(mNotificationManager.mBackendService.getOrCreateNotificationChannels(any(), eq(pkg1), eq(userId), anyBoolean())).thenReturn(new ParceledListSlice<>(List.of(channel1))); when(mNotificationManager.mBackendService.getOrCreateNotificationChannels(any(), eq(pkg2), eq(userId), anyBoolean())).thenReturn(new ParceledListSlice<>(List.of(channel2))); when(mNotificationManager.mBackendService.getOrCreateNotificationChannels(any(), eq(pkg1), eq(userId1), anyBoolean())).thenReturn(new ParceledListSlice<>(List.of(channel3))); // set our context to pretend to be from package 1 and userId 0 mContext.setParameters(pkg1, pkg1, userId); Loading @@ -402,7 +406,7 @@ public class NotificationManagerTest { // Those should have been three different calls verify(mNotificationManager.mBackendService, times(3)) .getNotificationChannels(any(), any(), anyInt()); .getOrCreateNotificationChannels(any(), any(), anyInt(), anyBoolean()); } private Notification exampleNotification() { Loading services/core/java/com/android/server/notification/NotificationManagerService.java +8 −1 Original line number Diff line number Diff line Loading @@ -4983,6 +4983,12 @@ public class NotificationManagerService extends SystemService { @Override public ParceledListSlice<NotificationChannel> getNotificationChannels( String callingPkg, String targetPkg, int userId) { return getOrCreateNotificationChannels(callingPkg, targetPkg, userId, false); } @Override public ParceledListSlice<NotificationChannel> getOrCreateNotificationChannels( String callingPkg, String targetPkg, int userId, boolean createPrefsIfNeeded) { if (canNotifyAsPackage(callingPkg, targetPkg, userId) || isCallingUidSystem()) { int targetUid = -1; Loading @@ -4992,7 +4998,8 @@ public class NotificationManagerService extends SystemService { /* ignore */ } return mPreferencesHelper.getNotificationChannels( targetPkg, targetUid, false /* includeDeleted */, true); targetPkg, targetUid, false /* includeDeleted */, true, createPrefsIfNeeded); } throw new SecurityException("Pkg " + callingPkg + " cannot read channels for " + targetPkg + " in " + userId); Loading services/core/java/com/android/server/notification/PreferencesHelper.java +16 −1 Original line number Diff line number Diff line Loading @@ -1962,10 +1962,25 @@ public class PreferencesHelper implements RankingConfig { @Override public ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg, int uid, boolean includeDeleted, boolean includeBundles) { return getNotificationChannels(pkg, uid, includeDeleted, includeBundles, false); } protected ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg, int uid, boolean includeDeleted, boolean includeBundles, boolean createPrefsIfNeeded) { if (createPrefsIfNeeded && !android.app.Flags.nmBinderPerfCacheChannels()) { Slog.wtf(TAG, "getNotificationChannels called with createPrefsIfNeeded=true and flag off"); createPrefsIfNeeded = false; } Objects.requireNonNull(pkg); List<NotificationChannel> channels = new ArrayList<>(); synchronized (mLock) { PackagePreferences r = getPackagePreferencesLocked(pkg, uid); PackagePreferences r; if (createPrefsIfNeeded) { r = getOrCreatePackagePreferencesLocked(pkg, uid); } else { r = getPackagePreferencesLocked(pkg, uid); } if (r == null) { return ParceledListSlice.emptyList(); } Loading Loading
core/java/android/app/INotificationManager.aidl +1 −0 Original line number Diff line number Diff line Loading @@ -114,6 +114,7 @@ interface INotificationManager NotificationChannel getNotificationChannelForPackage(String pkg, int uid, String channelId, String conversationId, boolean includeDeleted); void deleteNotificationChannel(String pkg, String channelId); ParceledListSlice getNotificationChannels(String callingPkg, String targetPkg, int userId); ParceledListSlice getOrCreateNotificationChannels(String callingPkg, String targetPkg, int userId, boolean createPrefsIfNeeded); ParceledListSlice getNotificationChannelsForPackage(String pkg, int uid, boolean includeDeleted); int getNumNotificationChannelsForPackage(String pkg, int uid, boolean includeDeleted); int getDeletedChannelCount(String pkg, int uid); Loading
core/java/android/app/NotificationManager.java +12 −8 Original line number Diff line number Diff line Loading @@ -1211,7 +1211,8 @@ public class NotificationManager { mNotificationChannelListCache.query(new NotificationChannelQuery( mContext.getOpPackageName(), mContext.getPackageName(), mContext.getUserId()))); mContext.getUserId(), true))); // create (default channel) if needed } else { INotificationManager service = service(); try { Loading Loading @@ -1239,7 +1240,8 @@ public class NotificationManager { mNotificationChannelListCache.query(new NotificationChannelQuery( mContext.getOpPackageName(), mContext.getPackageName(), mContext.getUserId()))); mContext.getUserId(), true))); // create (default channel) if needed } else { INotificationManager service = service(); try { Loading @@ -1265,7 +1267,8 @@ public class NotificationManager { return mNotificationChannelListCache.query(new NotificationChannelQuery( mContext.getOpPackageName(), mContext.getPackageName(), mContext.getUserId())); mContext.getUserId(), false)); } else { INotificationManager service = service(); try { Loading Loading @@ -1405,8 +1408,8 @@ public class NotificationManager { public List<NotificationChannel> apply(NotificationChannelQuery query) { INotificationManager service = service(); try { return service.getNotificationChannels(query.callingPkg, query.targetPkg, query.userId).getList(); return service.getOrCreateNotificationChannels(query.callingPkg, query.targetPkg, query.userId, query.createIfNeeded).getList(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } Loading Loading @@ -1434,7 +1437,8 @@ public class NotificationManager { private record NotificationChannelQuery( String callingPkg, String targetPkg, int userId) {} int userId, boolean createIfNeeded) {} /** * @hide Loading
core/tests/coretests/src/android/app/NotificationManagerTest.java +24 −20 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package android.app; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.atLeast; Loading Loading @@ -269,8 +270,9 @@ public class NotificationManagerTest { // It doesn't matter what the returned contents are, as long as we return a channel. // This setup must set up getNotificationChannels(), as that's the method called. when(mNotificationManager.mBackendService.getNotificationChannels(any(), any(), anyInt())).thenReturn(new ParceledListSlice<>(List.of(exampleChannel()))); when(mNotificationManager.mBackendService.getOrCreateNotificationChannels(any(), any(), anyInt(), anyBoolean())).thenReturn( new ParceledListSlice<>(List.of(exampleChannel()))); // ask for the same channel 100 times without invalidating the cache for (int i = 0; i < 100; i++) { Loading @@ -282,7 +284,7 @@ public class NotificationManagerTest { NotificationChannel unused = mNotificationManager.getNotificationChannel("id"); verify(mNotificationManager.mBackendService, times(2)) .getNotificationChannels(any(), any(), anyInt()); .getOrCreateNotificationChannels(any(), any(), anyInt(), anyBoolean()); } @Test Loading @@ -295,23 +297,24 @@ public class NotificationManagerTest { NotificationChannel c2 = new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_NONE); when(mNotificationManager.mBackendService.getNotificationChannels(any(), any(), anyInt())).thenReturn(new ParceledListSlice<>(List.of(c1, c2))); when(mNotificationManager.mBackendService.getOrCreateNotificationChannels(any(), any(), anyInt(), anyBoolean())).thenReturn(new ParceledListSlice<>(List.of(c1, c2))); assertThat(mNotificationManager.getNotificationChannel("id1")).isEqualTo(c1); assertThat(mNotificationManager.getNotificationChannel("id2")).isEqualTo(c2); assertThat(mNotificationManager.getNotificationChannel("id3")).isNull(); verify(mNotificationManager.mBackendService, times(1)) .getNotificationChannels(any(), any(), anyInt()); .getOrCreateNotificationChannels(any(), any(), anyInt(), anyBoolean()); } @Test @EnableFlags(Flags.FLAG_NM_BINDER_PERF_CACHE_CHANNELS) public void getNotificationChannels_cachedUntilInvalidated() throws Exception { NotificationManager.invalidateNotificationChannelCache(); when(mNotificationManager.mBackendService.getNotificationChannels(any(), any(), anyInt())).thenReturn(new ParceledListSlice<>(List.of(exampleChannel()))); when(mNotificationManager.mBackendService.getOrCreateNotificationChannels(any(), any(), anyInt(), anyBoolean())).thenReturn( new ParceledListSlice<>(List.of(exampleChannel()))); // ask for channels 100 times without invalidating the cache for (int i = 0; i < 100; i++) { Loading @@ -323,7 +326,7 @@ public class NotificationManagerTest { List<NotificationChannel> res = mNotificationManager.getNotificationChannels(); verify(mNotificationManager.mBackendService, times(2)) .getNotificationChannels(any(), any(), anyInt()); .getOrCreateNotificationChannels(any(), any(), anyInt(), anyBoolean()); assertThat(res).containsExactlyElementsIn(List.of(exampleChannel())); } Loading @@ -341,8 +344,9 @@ public class NotificationManagerTest { NotificationChannel c2 = new NotificationChannel("other", "name2", NotificationManager.IMPORTANCE_DEFAULT); when(mNotificationManager.mBackendService.getNotificationChannels(any(), any(), anyInt())) .thenReturn(new ParceledListSlice<>(List.of(c1, conv1, c2))); when(mNotificationManager.mBackendService.getOrCreateNotificationChannels(any(), any(), anyInt(), anyBoolean())).thenReturn( new ParceledListSlice<>(List.of(c1, conv1, c2))); // Lookup for channel c1 and c2: returned as expected assertThat(mNotificationManager.getNotificationChannel("id")).isEqualTo(c1); Loading @@ -359,9 +363,9 @@ public class NotificationManagerTest { // Lookup of a nonexistent channel is null assertThat(mNotificationManager.getNotificationChannel("id3")).isNull(); // All of that should have been one call to getNotificationChannels() // All of that should have been one call to getOrCreateNotificationChannels() verify(mNotificationManager.mBackendService, times(1)) .getNotificationChannels(any(), any(), anyInt()); .getOrCreateNotificationChannels(any(), any(), anyInt(), anyBoolean()); } @Test Loading @@ -381,12 +385,12 @@ public class NotificationManagerTest { NotificationChannel channel3 = channel1.copy(); channel3.setName("name3"); when(mNotificationManager.mBackendService.getNotificationChannels(any(), eq(pkg1), eq(userId))).thenReturn(new ParceledListSlice<>(List.of(channel1))); when(mNotificationManager.mBackendService.getNotificationChannels(any(), eq(pkg2), eq(userId))).thenReturn(new ParceledListSlice<>(List.of(channel2))); when(mNotificationManager.mBackendService.getNotificationChannels(any(), eq(pkg1), eq(userId1))).thenReturn(new ParceledListSlice<>(List.of(channel3))); when(mNotificationManager.mBackendService.getOrCreateNotificationChannels(any(), eq(pkg1), eq(userId), anyBoolean())).thenReturn(new ParceledListSlice<>(List.of(channel1))); when(mNotificationManager.mBackendService.getOrCreateNotificationChannels(any(), eq(pkg2), eq(userId), anyBoolean())).thenReturn(new ParceledListSlice<>(List.of(channel2))); when(mNotificationManager.mBackendService.getOrCreateNotificationChannels(any(), eq(pkg1), eq(userId1), anyBoolean())).thenReturn(new ParceledListSlice<>(List.of(channel3))); // set our context to pretend to be from package 1 and userId 0 mContext.setParameters(pkg1, pkg1, userId); Loading @@ -402,7 +406,7 @@ public class NotificationManagerTest { // Those should have been three different calls verify(mNotificationManager.mBackendService, times(3)) .getNotificationChannels(any(), any(), anyInt()); .getOrCreateNotificationChannels(any(), any(), anyInt(), anyBoolean()); } private Notification exampleNotification() { Loading
services/core/java/com/android/server/notification/NotificationManagerService.java +8 −1 Original line number Diff line number Diff line Loading @@ -4983,6 +4983,12 @@ public class NotificationManagerService extends SystemService { @Override public ParceledListSlice<NotificationChannel> getNotificationChannels( String callingPkg, String targetPkg, int userId) { return getOrCreateNotificationChannels(callingPkg, targetPkg, userId, false); } @Override public ParceledListSlice<NotificationChannel> getOrCreateNotificationChannels( String callingPkg, String targetPkg, int userId, boolean createPrefsIfNeeded) { if (canNotifyAsPackage(callingPkg, targetPkg, userId) || isCallingUidSystem()) { int targetUid = -1; Loading @@ -4992,7 +4998,8 @@ public class NotificationManagerService extends SystemService { /* ignore */ } return mPreferencesHelper.getNotificationChannels( targetPkg, targetUid, false /* includeDeleted */, true); targetPkg, targetUid, false /* includeDeleted */, true, createPrefsIfNeeded); } throw new SecurityException("Pkg " + callingPkg + " cannot read channels for " + targetPkg + " in " + userId); Loading
services/core/java/com/android/server/notification/PreferencesHelper.java +16 −1 Original line number Diff line number Diff line Loading @@ -1962,10 +1962,25 @@ public class PreferencesHelper implements RankingConfig { @Override public ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg, int uid, boolean includeDeleted, boolean includeBundles) { return getNotificationChannels(pkg, uid, includeDeleted, includeBundles, false); } protected ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg, int uid, boolean includeDeleted, boolean includeBundles, boolean createPrefsIfNeeded) { if (createPrefsIfNeeded && !android.app.Flags.nmBinderPerfCacheChannels()) { Slog.wtf(TAG, "getNotificationChannels called with createPrefsIfNeeded=true and flag off"); createPrefsIfNeeded = false; } Objects.requireNonNull(pkg); List<NotificationChannel> channels = new ArrayList<>(); synchronized (mLock) { PackagePreferences r = getPackagePreferencesLocked(pkg, uid); PackagePreferences r; if (createPrefsIfNeeded) { r = getOrCreatePackagePreferencesLocked(pkg, uid); } else { r = getPackagePreferencesLocked(pkg, uid); } if (r == null) { return ParceledListSlice.emptyList(); } Loading