summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Yuri Lin <yurilin@google.com> 2025-01-13 13:29:35 -0800
committer Android (Google) Code Review <android-gerrit@google.com> 2025-01-13 13:29:35 -0800
commit4d71ef003c9f4d3d2e59c04844febca6ef7bfaf3 (patch)
tree1fb3f29af8027855ee6f9c5f98a6ae21f2bda181
parent2fb05f5a565bb47caa5de6076de278c673def147 (diff)
parentfc3527116a6a0d1eb5eeaa81c054a6ce83d5cc40 (diff)
Merge "Optionally create package preferences in getNotificationChannels()" into main
-rw-r--r--core/java/android/app/INotificationManager.aidl1
-rw-r--r--core/java/android/app/NotificationManager.java20
-rw-r--r--core/tests/coretests/src/android/app/NotificationManagerTest.java44
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java9
-rw-r--r--services/core/java/com/android/server/notification/PreferencesHelper.java17
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java36
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.