Store not-yet-restored prefs for multiple users
This fixes the issue where restored personal notification
preferences could be lost if a managed profile restore was triggered
before the personal packages finished downloading.
Test: atest
Fixes: 142801019
Change-Id: Ic882c806e4f537dffcdca2f6ef1cdd98b0fdb3c7
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 887dbb3..0a3c581 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -22,6 +22,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UserIdInt;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationChannelGroup;
@@ -125,7 +126,7 @@
// pkg|uid => PackagePreferences
private final ArrayMap<String, PackagePreferences> mPackagePreferences = new ArrayMap<>();
- // pkg => PackagePreferences
+ // pkg|userId => PackagePreferences
private final ArrayMap<String, PackagePreferences> mRestoredWithoutUids = new ArrayMap<>();
private final Context mContext;
@@ -172,9 +173,6 @@
String tag = parser.getName();
if (!TAG_RANKING.equals(tag)) return;
synchronized (mPackagePreferences) {
- // Clobber groups and channels with the xml, but don't delete other data that wasn't
- // present at the time of serialization.
- mRestoredWithoutUids.clear();
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
tag = parser.getName();
if (type == XmlPullParser.END_TAG && TAG_RANKING.equals(tag)) {
@@ -200,7 +198,8 @@
}
boolean skipWarningLogged = false;
- PackagePreferences r = getOrCreatePackagePreferencesLocked(name, uid,
+ PackagePreferences r = getOrCreatePackagePreferencesLocked(
+ name, userId, uid,
XmlUtils.readIntAttribute(
parser, ATT_IMPORTANCE, DEFAULT_IMPORTANCE),
XmlUtils.readIntAttribute(parser, ATT_PRIORITY,
@@ -311,17 +310,27 @@
return mPackagePreferences.get(key);
}
- private PackagePreferences getOrCreatePackagePreferencesLocked(String pkg, int uid) {
- return getOrCreatePackagePreferencesLocked(pkg, uid,
+ private PackagePreferences getOrCreatePackagePreferencesLocked(String pkg,
+ int uid) {
+ return getOrCreatePackagePreferencesLocked(pkg, UserHandle.getUserId(uid), uid,
DEFAULT_IMPORTANCE, DEFAULT_PRIORITY, DEFAULT_VISIBILITY, DEFAULT_SHOW_BADGE,
DEFAULT_ALLOW_BUBBLE);
}
- private PackagePreferences getOrCreatePackagePreferencesLocked(String pkg, int uid,
- int importance, int priority, int visibility, boolean showBadge, boolean allowBubble) {
+ private PackagePreferences getOrCreatePackagePreferencesLocked(String pkg,
+ @UserIdInt int userId, int uid) {
+ return getOrCreatePackagePreferencesLocked(pkg, userId, uid,
+ DEFAULT_IMPORTANCE, DEFAULT_PRIORITY, DEFAULT_VISIBILITY, DEFAULT_SHOW_BADGE,
+ DEFAULT_ALLOW_BUBBLE);
+ }
+
+ private PackagePreferences getOrCreatePackagePreferencesLocked(String pkg,
+ @UserIdInt int userId, int uid, int importance, int priority, int visibility,
+ boolean showBadge, boolean allowBubble) {
final String key = packagePreferencesKey(pkg, uid);
PackagePreferences
- r = (uid == UNKNOWN_UID) ? mRestoredWithoutUids.get(pkg)
+ r = (uid == UNKNOWN_UID)
+ ? mRestoredWithoutUids.get(unrestoredPackageKey(pkg, userId))
: mPackagePreferences.get(key);
if (r == null) {
r = new PackagePreferences();
@@ -340,7 +349,7 @@
}
if (r.uid == UNKNOWN_UID) {
- mRestoredWithoutUids.put(pkg, r);
+ mRestoredWithoutUids.put(unrestoredPackageKey(pkg, userId), r);
} else {
mPackagePreferences.put(key, r);
}
@@ -382,6 +391,10 @@
private boolean createDefaultChannelIfNeededLocked(PackagePreferences r) throws
PackageManager.NameNotFoundException {
+ if (r.uid == UNKNOWN_UID) {
+ return false;
+ }
+
if (r.channels.containsKey(NotificationChannel.DEFAULT_CHANNEL_ID)) {
r.channels.get(NotificationChannel.DEFAULT_CHANNEL_ID).setName(mContext.getString(
com.android.internal.R.string.default_notification_channel_label));
@@ -1769,17 +1782,18 @@
synchronized (mPackagePreferences) {
mPackagePreferences.remove(packagePreferencesKey(pkg, uid));
}
- mRestoredWithoutUids.remove(pkg);
+ mRestoredWithoutUids.remove(unrestoredPackageKey(pkg, changeUserId));
updated = true;
}
} else {
for (String pkg : pkgList) {
// Package install
- final PackagePreferences r = mRestoredWithoutUids.get(pkg);
+ final PackagePreferences r =
+ mRestoredWithoutUids.get(unrestoredPackageKey(pkg, changeUserId));
if (r != null) {
try {
r.uid = mPm.getPackageUidAsUser(r.pkg, changeUserId);
- mRestoredWithoutUids.remove(pkg);
+ mRestoredWithoutUids.remove(unrestoredPackageKey(pkg, changeUserId));
synchronized (mPackagePreferences) {
mPackagePreferences.put(packagePreferencesKey(r.pkg, r.uid), r);
}
@@ -1910,6 +1924,10 @@
return pkg + "|" + uid;
}
+ private static String unrestoredPackageKey(String pkg, @UserIdInt int userId) {
+ return pkg + "|" + userId;
+ }
+
private static class PackagePreferences {
String pkg;
int uid = UNKNOWN_UID;
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 a1322b9..776c00e 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -2715,4 +2715,57 @@
assertNull(mHelper.getNotificationChannel(PKG_O, UID_O, extraChannel, true));
assertNull(mHelper.getNotificationChannel(PKG_O, UID_O, extraChannel1, true));
}
+
+ @Test
+ public void testRestoreMultiUser() throws Exception {
+ String pkg = "restore_pkg";
+ String channelId = "channelId";
+ int user0Importance = 3;
+ int user10Importance = 4;
+ when(mPm.getPackageUidAsUser(eq(pkg), anyInt())).thenReturn(UserHandle.USER_NULL);
+
+ // both users have the same package, but different notification settings
+ final String xmlUser0 = "<ranking version=\"1\">\n"
+ + "<package name=\"" + pkg + "\" >\n"
+ + "<channel id=\"" + channelId + "\" name=\"hi\""
+ + " importance=\"" + user0Importance + "\"/>"
+ + "</package>"
+ + "</ranking>";
+ final String xmlUser10 = "<ranking version=\"1\">\n"
+ + "<package name=\"" + pkg + "\" >\n"
+ + "<channel id=\"" + channelId + "\" name=\"hi\""
+ + " importance=\"" + user10Importance + "\"/>"
+ + "</package>"
+ + "</ranking>";
+
+ // trigger a restore for both users
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xmlUser0.getBytes())),
+ null);
+ parser.nextTag();
+ mHelper.readXml(parser, true, 0);
+ parser = Xml.newPullParser();
+ parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xmlUser10.getBytes())),
+ null);
+ parser.nextTag();
+ mHelper.readXml(parser, true, 10);
+
+ // "install" package on both users
+ String[] pkgList = new String[] {pkg};
+ int[] uidList0 = new int[] {UserHandle.PER_USER_RANGE};
+ int[] uidList10 = new int[] {UserHandle.PER_USER_RANGE + 1};
+ when(mPm.getPackageUidAsUser(pkg, 0)).thenReturn(uidList0[0]);
+ when(mPm.getPackageUidAsUser(pkg, 10)).thenReturn(uidList10[0]);
+ ApplicationInfo info = new ApplicationInfo();
+ info.targetSdkVersion = Build.VERSION_CODES.Q;
+ when(mPm.getApplicationInfoAsUser(eq(pkg), anyInt(), anyInt())).thenReturn(info);
+
+ mHelper.onPackagesChanged(false, 0, pkgList, uidList0);
+ mHelper.onPackagesChanged(false, 10, pkgList, uidList10);
+
+ assertEquals(user0Importance,
+ mHelper.getNotificationChannel(pkg, uidList0[0], channelId, false).getImportance());
+ assertEquals(user10Importance, mHelper.getNotificationChannel(
+ pkg, uidList10[0], channelId, false).getImportance());
+ }
}