diff options
| author | 2025-01-13 13:29:35 -0800 | |
|---|---|---|
| committer | 2025-01-13 13:29:35 -0800 | |
| commit | 4d71ef003c9f4d3d2e59c04844febca6ef7bfaf3 (patch) | |
| tree | 1fb3f29af8027855ee6f9c5f98a6ae21f2bda181 | |
| parent | 2fb05f5a565bb47caa5de6076de278c673def147 (diff) | |
| parent | fc3527116a6a0d1eb5eeaa81c054a6ce83d5cc40 (diff) | |
Merge "Optionally create package preferences in getNotificationChannels()" into main
6 files changed, 97 insertions, 30 deletions
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl index 0451ac0d6897..1738a92b7672 100644 --- a/core/java/android/app/INotificationManager.aidl +++ b/core/java/android/app/INotificationManager.aidl @@ -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); diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java index aede8aa70ede..d22926791cc3 100644 --- a/core/java/android/app/NotificationManager.java +++ b/core/java/android/app/NotificationManager.java @@ -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 { @@ -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 { @@ -1263,9 +1265,10 @@ public class NotificationManager { public List<NotificationChannel> getNotificationChannels() { if (Flags.nmBinderPerfCacheChannels()) { return mNotificationChannelListCache.query(new NotificationChannelQuery( - mContext.getOpPackageName(), - mContext.getPackageName(), - mContext.getUserId())); + mContext.getOpPackageName(), + mContext.getPackageName(), + mContext.getUserId(), + false)); } else { INotificationManager service = service(); try { @@ -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(); } @@ -1434,7 +1437,8 @@ public class NotificationManager { private record NotificationChannelQuery( String callingPkg, String targetPkg, - int userId) {} + int userId, + boolean createIfNeeded) {} /** * @hide diff --git a/core/tests/coretests/src/android/app/NotificationManagerTest.java b/core/tests/coretests/src/android/app/NotificationManagerTest.java index 3d6e1225bd92..18ba6a16bf72 100644 --- a/core/tests/coretests/src/android/app/NotificationManagerTest.java +++ b/core/tests/coretests/src/android/app/NotificationManagerTest.java @@ -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; @@ -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++) { @@ -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 @@ -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++) { @@ -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())); } @@ -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); @@ -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 @@ -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); @@ -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() { diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 05aa4134cbd5..32d3970ce549 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -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; @@ -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); diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java index 45b155049c72..3b34dcd17705 100644 --- a/services/core/java/com/android/server/notification/PreferencesHelper.java +++ b/services/core/java/com/android/server/notification/PreferencesHelper.java @@ -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(); } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java index 4bc286117ac6..704b580a80b0 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java @@ -116,6 +116,7 @@ import android.content.IContentProvider; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.content.pm.ParceledListSlice; import android.content.pm.Signature; import android.content.pm.UserInfo; import android.content.res.Resources; @@ -6834,6 +6835,41 @@ public class PreferencesHelperTest extends UiServiceTestCase { assertThat(mHelper.hasCacheBeenInvalidated()).isFalse(); } + @Test + @EnableFlags(android.app.Flags.FLAG_NM_BINDER_PERF_CACHE_CHANNELS) + public void testGetNotificationChannels_createIfNeeded() { + // Test setup hasn't created any channels or read package preferences yet. + // If we ask for notification channels _without_ creating, we should get no result. + ParceledListSlice<NotificationChannel> channels = mHelper.getNotificationChannels(PKG_N_MR1, + UID_N_MR1, false, false, /* createPrefsIfNeeded= */ false); + assertThat(channels.getList().size()).isEqualTo(0); + + // If we ask it to create package preferences, we expect the default channel to be created + // for N_MR1. + channels = mHelper.getNotificationChannels(PKG_N_MR1, UID_N_MR1, false, + false, /* createPrefsIfNeeded= */ true); + assertThat(channels.getList().size()).isEqualTo(1); + assertThat(channels.getList().getFirst().getId()).isEqualTo( + NotificationChannel.DEFAULT_CHANNEL_ID); + } + + @Test + @DisableFlags(android.app.Flags.FLAG_NM_BINDER_PERF_CACHE_CHANNELS) + public void testGetNotificationChannels_neverCreatesWhenFlagOff() { + ParceledListSlice<NotificationChannel> channels; + try { + channels = mHelper.getNotificationChannels(PKG_N_MR1, UID_N_MR1, false, + false, /* createPrefsIfNeeded= */ true); + } catch (Exception e) { + // Slog.wtf kicks in, presumably + } finally { + channels = mHelper.getNotificationChannels(PKG_N_MR1, UID_N_MR1, false, + false, /* createPrefsIfNeeded= */ false); + assertThat(channels.getList().size()).isEqualTo(0); + } + + } + // Test version of PreferencesHelper whose only functional difference is that it does not // interact with the real IpcDataCache, and instead tracks whether or not the cache has been // invalidated since creation or the last reset. |