diff options
| author | 2024-07-08 20:27:04 +0000 | |
|---|---|---|
| committer | 2024-07-08 20:27:04 +0000 | |
| commit | 177af6b61a94ee76fc8c5a059d592c2eda2af96e (patch) | |
| tree | 2a46343472d1ce2315cf033b23491b931ad22af5 | |
| parent | b283f3d313904f0623e979e301a90634e1a01215 (diff) | |
| parent | 490c3ee65e26f0a3db5819510eef2355a149dc4b (diff) | |
Merge "Synchronize access to notif settings" into main
| -rw-r--r-- | services/core/java/com/android/server/notification/PreferencesHelper.java | 215 | ||||
| -rw-r--r-- | services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java | 59 |
2 files changed, 169 insertions, 105 deletions
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java index 3a0c1d0e8a36..c09504fa36c8 100644 --- a/services/core/java/com/android/server/notification/PreferencesHelper.java +++ b/services/core/java/com/android/server/notification/PreferencesHelper.java @@ -196,9 +196,12 @@ public class PreferencesHelper implements RankingConfig { int USER_LOCKED_BUBBLE = 0x00000002; } + private final Object mLock = new Object(); // pkg|uid => PackagePreferences + @GuardedBy("mLock") private final ArrayMap<String, PackagePreferences> mPackagePreferences = new ArrayMap<>(); // pkg|userId => PackagePreferences + @GuardedBy("mLock") private final ArrayMap<String, PackagePreferences> mRestoredWithoutUids = new ArrayMap<>(); private final Context mContext; @@ -270,7 +273,7 @@ public class PreferencesHelper implements RankingConfig { Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE, NotificationManagerService.REVIEW_NOTIF_STATE_SHOULD_SHOW); } - synchronized (mPackagePreferences) { + synchronized (mLock) { while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) { tag = parser.getName(); if (type == XmlPullParser.END_TAG && TAG_RANKING.equals(tag)) { @@ -492,6 +495,7 @@ public class PreferencesHelper implements RankingConfig { DEFAULT_BUBBLE_PREFERENCE, mClock.millis()); } + @GuardedBy("mLock") private PackagePreferences getOrCreatePackagePreferencesLocked(String pkg, @UserIdInt int userId, int uid, int importance, int priority, int visibility, boolean showBadge, int bubblePreference, long creationTime) { @@ -661,7 +665,7 @@ public class PreferencesHelper implements RankingConfig { notifPermissions = mPermissionHelper.getNotificationPermissionValues(userId); } - synchronized (mPackagePreferences) { + synchronized (mLock) { final int N = mPackagePreferences.size(); for (int i = 0; i < N; i++) { final PackagePreferences r = mPackagePreferences.valueAt(i); @@ -670,11 +674,10 @@ public class PreferencesHelper implements RankingConfig { } writePackageXml(r, out, notifPermissions, forBackup); } - } - if (Flags.persistIncompleteRestoreData() && !forBackup) { - synchronized (mRestoredWithoutUids) { - final int N = mRestoredWithoutUids.size(); - for (int i = 0; i < N; i++) { + + if (Flags.persistIncompleteRestoreData() && !forBackup) { + final int M = mRestoredWithoutUids.size(); + for (int i = 0; i < M; i++) { final PackagePreferences r = mRestoredWithoutUids.valueAt(i); writePackageXml(r, out, notifPermissions, false); } @@ -777,7 +780,7 @@ public class PreferencesHelper implements RankingConfig { */ public void setBubblesAllowed(String pkg, int uid, int bubblePreference) { boolean changed; - synchronized (mPackagePreferences) { + synchronized (mLock) { PackagePreferences p = getOrCreatePackagePreferencesLocked(pkg, uid); changed = p.bubblePreference != bubblePreference; p.bubblePreference = bubblePreference; @@ -797,20 +800,20 @@ public class PreferencesHelper implements RankingConfig { */ @Override public int getBubblePreference(String pkg, int uid) { - synchronized (mPackagePreferences) { + synchronized (mLock) { return getOrCreatePackagePreferencesLocked(pkg, uid).bubblePreference; } } public int getAppLockedFields(String pkg, int uid) { - synchronized (mPackagePreferences) { + synchronized (mLock) { return getOrCreatePackagePreferencesLocked(pkg, uid).lockedAppFields; } } @Override public boolean canShowBadge(String packageName, int uid) { - synchronized (mPackagePreferences) { + synchronized (mLock) { return getOrCreatePackagePreferencesLocked(packageName, uid).showBadge; } } @@ -818,7 +821,7 @@ public class PreferencesHelper implements RankingConfig { @Override public void setShowBadge(String packageName, int uid, boolean showBadge) { boolean changed = false; - synchronized (mPackagePreferences) { + synchronized (mLock) { PackagePreferences pkgPrefs = getOrCreatePackagePreferencesLocked(packageName, uid); if (pkgPrefs.showBadge != showBadge) { pkgPrefs.showBadge = showBadge; @@ -831,28 +834,28 @@ public class PreferencesHelper implements RankingConfig { } public boolean isInInvalidMsgState(String packageName, int uid) { - synchronized (mPackagePreferences) { + synchronized (mLock) { PackagePreferences r = getOrCreatePackagePreferencesLocked(packageName, uid); return r.hasSentInvalidMessage && !r.hasSentValidMessage; } } public boolean hasUserDemotedInvalidMsgApp(String packageName, int uid) { - synchronized (mPackagePreferences) { + synchronized (mLock) { PackagePreferences r = getOrCreatePackagePreferencesLocked(packageName, uid); return isInInvalidMsgState(packageName, uid) ? r.userDemotedMsgApp : false; } } public void setInvalidMsgAppDemoted(String packageName, int uid, boolean isDemoted) { - synchronized (mPackagePreferences) { + synchronized (mLock) { PackagePreferences r = getOrCreatePackagePreferencesLocked(packageName, uid); r.userDemotedMsgApp = isDemoted; } } public boolean setInvalidMessageSent(String packageName, int uid) { - synchronized (mPackagePreferences) { + synchronized (mLock) { PackagePreferences r = getOrCreatePackagePreferencesLocked(packageName, uid); boolean valueChanged = r.hasSentInvalidMessage == false; r.hasSentInvalidMessage = true; @@ -862,7 +865,7 @@ public class PreferencesHelper implements RankingConfig { } public boolean setValidMessageSent(String packageName, int uid) { - synchronized (mPackagePreferences) { + synchronized (mLock) { PackagePreferences r = getOrCreatePackagePreferencesLocked(packageName, uid); boolean valueChanged = r.hasSentValidMessage == false; r.hasSentValidMessage = true; @@ -873,7 +876,7 @@ public class PreferencesHelper implements RankingConfig { @VisibleForTesting boolean hasSentInvalidMsg(String packageName, int uid) { - synchronized (mPackagePreferences) { + synchronized (mLock) { PackagePreferences r = getOrCreatePackagePreferencesLocked(packageName, uid); return r.hasSentInvalidMessage; } @@ -881,7 +884,7 @@ public class PreferencesHelper implements RankingConfig { @VisibleForTesting boolean hasSentValidMsg(String packageName, int uid) { - synchronized (mPackagePreferences) { + synchronized (mLock) { PackagePreferences r = getOrCreatePackagePreferencesLocked(packageName, uid); return r.hasSentValidMessage; } @@ -889,7 +892,7 @@ public class PreferencesHelper implements RankingConfig { @VisibleForTesting boolean didUserEverDemoteInvalidMsgApp(String packageName, int uid) { - synchronized (mPackagePreferences) { + synchronized (mLock) { PackagePreferences r = getOrCreatePackagePreferencesLocked(packageName, uid); return r.userDemotedMsgApp; } @@ -897,7 +900,7 @@ public class PreferencesHelper implements RankingConfig { /** Sets whether this package has sent a notification with valid bubble metadata. */ public boolean setValidBubbleSent(String packageName, int uid) { - synchronized (mPackagePreferences) { + synchronized (mLock) { PackagePreferences r = getOrCreatePackagePreferencesLocked(packageName, uid); boolean valueChanged = !r.hasSentValidBubble; r.hasSentValidBubble = true; @@ -906,14 +909,14 @@ public class PreferencesHelper implements RankingConfig { } boolean hasSentValidBubble(String packageName, int uid) { - synchronized (mPackagePreferences) { + synchronized (mLock) { PackagePreferences r = getOrCreatePackagePreferencesLocked(packageName, uid); return r.hasSentValidBubble; } } boolean isImportanceLocked(String pkg, int uid) { - synchronized (mPackagePreferences) { + synchronized (mLock) { PackagePreferences r = getOrCreatePackagePreferencesLocked(pkg, uid); return r.fixedImportance || r.defaultAppLockedImportance; } @@ -924,7 +927,7 @@ public class PreferencesHelper implements RankingConfig { if (groupId == null) { return false; } - synchronized (mPackagePreferences) { + synchronized (mLock) { PackagePreferences r = getOrCreatePackagePreferencesLocked(packageName, uid); NotificationChannelGroup group = r.groups.get(groupId); if (group == null) { @@ -935,13 +938,13 @@ public class PreferencesHelper implements RankingConfig { } int getPackagePriority(String pkg, int uid) { - synchronized (mPackagePreferences) { + synchronized (mLock) { return getOrCreatePackagePreferencesLocked(pkg, uid).priority; } } int getPackageVisibility(String pkg, int uid) { - synchronized (mPackagePreferences) { + synchronized (mLock) { return getOrCreatePackagePreferencesLocked(pkg, uid).visibility; } } @@ -956,7 +959,7 @@ public class PreferencesHelper implements RankingConfig { throw new IllegalArgumentException("group.getName() can't be empty"); } boolean needsDndChange = false; - synchronized (mPackagePreferences) { + synchronized (mLock) { PackagePreferences r = getOrCreatePackagePreferencesLocked(pkg, uid); if (r == null) { throw new IllegalArgumentException("Invalid package"); @@ -1010,7 +1013,7 @@ public class PreferencesHelper implements RankingConfig { && channel.getImportance() <= IMPORTANCE_MAX, "Invalid importance level"); boolean needsPolicyFileChange = false, wasUndeleted = false, needsDndChange = false; - synchronized (mPackagePreferences) { + synchronized (mLock) { PackagePreferences r = getOrCreatePackagePreferencesLocked(pkg, uid); if (r == null) { throw new IllegalArgumentException("Invalid package"); @@ -1154,7 +1157,7 @@ public class PreferencesHelper implements RankingConfig { void unlockNotificationChannelImportance(String pkg, int uid, String updatedChannelId) { Objects.requireNonNull(updatedChannelId); - synchronized (mPackagePreferences) { + synchronized (mLock) { PackagePreferences r = getOrCreatePackagePreferencesLocked(pkg, uid); if (r == null) { throw new IllegalArgumentException("Invalid package"); @@ -1176,7 +1179,7 @@ public class PreferencesHelper implements RankingConfig { Objects.requireNonNull(updatedChannel.getId()); boolean changed = false; boolean needsDndChange = false; - synchronized (mPackagePreferences) { + synchronized (mLock) { PackagePreferences r = getOrCreatePackagePreferencesLocked(pkg, uid); if (r == null) { throw new IllegalArgumentException("Invalid package"); @@ -1351,7 +1354,7 @@ public class PreferencesHelper implements RankingConfig { String channelId, String conversationId, boolean returnParentIfNoConversationChannel, boolean includeDeleted) { Preconditions.checkNotNull(pkg); - synchronized (mPackagePreferences) { + synchronized (mLock) { PackagePreferences r = getOrCreatePackagePreferencesLocked(pkg, uid); if (r == null) { return null; @@ -1392,7 +1395,7 @@ public class PreferencesHelper implements RankingConfig { Preconditions.checkNotNull(pkg); Preconditions.checkNotNull(conversationId); List<NotificationChannel> channels = new ArrayList<>(); - synchronized (mPackagePreferences) { + synchronized (mLock) { PackagePreferences r = getOrCreatePackagePreferencesLocked(pkg, uid); if (r == null) { return channels; @@ -1412,7 +1415,7 @@ public class PreferencesHelper implements RankingConfig { int callingUid, boolean fromSystemOrSystemUi) { boolean deletedChannel = false; boolean channelBypassedDnd = false; - synchronized (mPackagePreferences) { + synchronized (mLock) { PackagePreferences r = getPackagePreferencesLocked(pkg, uid); if (r == null) { return false; @@ -1448,7 +1451,7 @@ public class PreferencesHelper implements RankingConfig { public void permanentlyDeleteNotificationChannel(String pkg, int uid, String channelId) { Objects.requireNonNull(pkg); Objects.requireNonNull(channelId); - synchronized (mPackagePreferences) { + synchronized (mLock) { PackagePreferences r = getPackagePreferencesLocked(pkg, uid); if (r == null) { return; @@ -1460,7 +1463,7 @@ public class PreferencesHelper implements RankingConfig { @Override public void permanentlyDeleteNotificationChannels(String pkg, int uid) { Objects.requireNonNull(pkg); - synchronized (mPackagePreferences) { + synchronized (mLock) { PackagePreferences r = getPackagePreferencesLocked(pkg, uid); if (r == null) { return; @@ -1491,7 +1494,7 @@ public class PreferencesHelper implements RankingConfig { boolean fixed = mPermissionHelper.isPermissionFixed( pi.packageName, user.getUserHandle().getIdentifier()); if (fixed) { - synchronized (mPackagePreferences) { + synchronized (mLock) { PackagePreferences p = getOrCreatePackagePreferencesLocked( pi.packageName, pi.applicationInfo.uid); p.fixedImportance = true; @@ -1506,7 +1509,7 @@ public class PreferencesHelper implements RankingConfig { public void updateDefaultApps(int userId, ArraySet<String> toRemove, ArraySet<Pair<String, Integer>> toAdd) { - synchronized (mPackagePreferences) { + synchronized (mLock) { for (PackagePreferences p : mPackagePreferences.values()) { if (userId == UserHandle.getUserId(p.uid)) { if (toRemove != null && toRemove.contains(p.pkg)) { @@ -1536,7 +1539,7 @@ public class PreferencesHelper implements RankingConfig { public NotificationChannelGroup getNotificationChannelGroupWithChannels(String pkg, int uid, String groupId, boolean includeDeleted) { Objects.requireNonNull(pkg); - synchronized (mPackagePreferences) { + synchronized (mLock) { PackagePreferences r = getPackagePreferencesLocked(pkg, uid); if (r == null || groupId == null || !r.groups.containsKey(groupId)) { return null; @@ -1559,7 +1562,7 @@ public class PreferencesHelper implements RankingConfig { public NotificationChannelGroup getNotificationChannelGroup(String groupId, String pkg, int uid) { Objects.requireNonNull(pkg); - synchronized (mPackagePreferences) { + synchronized (mLock) { PackagePreferences r = getPackagePreferencesLocked(pkg, uid); if (r == null) { return null; @@ -1573,7 +1576,7 @@ public class PreferencesHelper implements RankingConfig { boolean includeBlocked, Set<String> activeChannelFilter) { Objects.requireNonNull(pkg); Map<String, NotificationChannelGroup> groups = new ArrayMap<>(); - synchronized (mPackagePreferences) { + synchronized (mLock) { PackagePreferences r = getPackagePreferencesLocked(pkg, uid); if (r == null) { return ParceledListSlice.emptyList(); @@ -1624,7 +1627,7 @@ public class PreferencesHelper implements RankingConfig { String groupId, int callingUid, boolean fromSystemOrSystemUi) { List<NotificationChannel> deletedChannels = new ArrayList<>(); boolean groupBypassedDnd = false; - synchronized (mPackagePreferences) { + synchronized (mLock) { PackagePreferences r = getPackagePreferencesLocked(pkg, uid); if (r == null || TextUtils.isEmpty(groupId)) { return deletedChannels; @@ -1656,7 +1659,7 @@ public class PreferencesHelper implements RankingConfig { public Collection<NotificationChannelGroup> getNotificationChannelGroups(String pkg, int uid) { List<NotificationChannelGroup> groups = new ArrayList<>(); - synchronized (mPackagePreferences) { + synchronized (mLock) { PackagePreferences r = getPackagePreferencesLocked(pkg, uid); if (r == null) { return groups; @@ -1667,7 +1670,7 @@ public class PreferencesHelper implements RankingConfig { } public NotificationChannelGroup getGroupForChannel(String pkg, int uid, String channelId) { - synchronized (mPackagePreferences) { + synchronized (mLock) { PackagePreferences p = getPackagePreferencesLocked(pkg, uid); if (p != null) { NotificationChannel nc = p.channels.get(channelId); @@ -1686,7 +1689,7 @@ public class PreferencesHelper implements RankingConfig { public ArrayList<ConversationChannelWrapper> getConversations(IntArray userIds, boolean onlyImportant) { - synchronized (mPackagePreferences) { + synchronized (mLock) { ArrayList<ConversationChannelWrapper> conversations = new ArrayList<>(); for (PackagePreferences p : mPackagePreferences.values()) { if (userIds.binarySearch(UserHandle.getUserId(p.uid)) >= 0) { @@ -1730,7 +1733,7 @@ public class PreferencesHelper implements RankingConfig { public ArrayList<ConversationChannelWrapper> getConversations(String pkg, int uid) { Objects.requireNonNull(pkg); - synchronized (mPackagePreferences) { + synchronized (mLock) { PackagePreferences r = getPackagePreferencesLocked(pkg, uid); if (r == null) { return new ArrayList<>(); @@ -1772,7 +1775,7 @@ public class PreferencesHelper implements RankingConfig { public @NonNull List<String> deleteConversations(String pkg, int uid, Set<String> conversationIds, int callingUid, boolean fromSystemOrSystemUi) { List<String> deletedChannelIds = new ArrayList<>(); - synchronized (mPackagePreferences) { + synchronized (mLock) { PackagePreferences r = getPackagePreferencesLocked(pkg, uid); if (r == null) { return deletedChannelIds; @@ -1805,7 +1808,7 @@ public class PreferencesHelper implements RankingConfig { boolean includeDeleted) { Objects.requireNonNull(pkg); List<NotificationChannel> channels = new ArrayList<>(); - synchronized (mPackagePreferences) { + synchronized (mLock) { PackagePreferences r = getPackagePreferencesLocked(pkg, uid); if (r == null) { return ParceledListSlice.emptyList(); @@ -1827,7 +1830,7 @@ public class PreferencesHelper implements RankingConfig { public ParceledListSlice<NotificationChannel> getNotificationChannelsBypassingDnd(String pkg, int uid) { List<NotificationChannel> channels = new ArrayList<>(); - synchronized (mPackagePreferences) { + synchronized (mLock) { final PackagePreferences r = mPackagePreferences.get( packagePreferencesKey(pkg, uid)); if (r != null) { @@ -1848,7 +1851,7 @@ public class PreferencesHelper implements RankingConfig { * upgrades. */ public boolean onlyHasDefaultChannel(String pkg, int uid) { - synchronized (mPackagePreferences) { + synchronized (mLock) { PackagePreferences r = getOrCreatePackagePreferencesLocked(pkg, uid); if (r.channels.size() == (notificationClassification() ? 5 : 1) && r.channels.containsKey(NotificationChannel.DEFAULT_CHANNEL_ID)) { @@ -1861,7 +1864,7 @@ public class PreferencesHelper implements RankingConfig { public int getDeletedChannelCount(String pkg, int uid) { Objects.requireNonNull(pkg); int deletedCount = 0; - synchronized (mPackagePreferences) { + synchronized (mLock) { PackagePreferences r = getPackagePreferencesLocked(pkg, uid); if (r == null) { return deletedCount; @@ -1880,7 +1883,7 @@ public class PreferencesHelper implements RankingConfig { public int getBlockedChannelCount(String pkg, int uid) { Objects.requireNonNull(pkg); int blockedCount = 0; - synchronized (mPackagePreferences) { + synchronized (mLock) { PackagePreferences r = getPackagePreferencesLocked(pkg, uid); if (r == null) { return blockedCount; @@ -1923,7 +1926,7 @@ public class PreferencesHelper implements RankingConfig { ArraySet<Pair<String, Integer>> candidatePkgs = new ArraySet<>(); final IntArray currentUserIds = mUserProfiles.getCurrentProfileIds(); - synchronized (mPackagePreferences) { + synchronized (mLock) { final int numPackagePreferences = mPackagePreferences.size(); for (int i = 0; i < numPackagePreferences; i++) { final PackagePreferences r = mPackagePreferences.valueAt(i); @@ -1992,7 +1995,7 @@ public class PreferencesHelper implements RankingConfig { * considered for sentiment adjustments (and thus never show a blocking helper). */ public void setAppImportanceLocked(String packageName, int uid) { - synchronized (mPackagePreferences) { + synchronized (mLock) { PackagePreferences prefs = getOrCreatePackagePreferencesLocked(packageName, uid); if ((prefs.lockedAppFields & LockableAppFields.USER_LOCKED_IMPORTANCE) != 0) { return; @@ -2008,7 +2011,7 @@ public class PreferencesHelper implements RankingConfig { * Returns the delegate for a given package, if it's allowed by the package and the user. */ public @Nullable String getNotificationDelegate(String sourcePkg, int sourceUid) { - synchronized (mPackagePreferences) { + synchronized (mLock) { PackagePreferences prefs = getPackagePreferencesLocked(sourcePkg, sourceUid); if (prefs == null || prefs.delegate == null) { @@ -2026,7 +2029,7 @@ public class PreferencesHelper implements RankingConfig { */ public void setNotificationDelegate(String sourcePkg, int sourceUid, String delegatePkg, int delegateUid) { - synchronized (mPackagePreferences) { + synchronized (mLock) { PackagePreferences prefs = getOrCreatePackagePreferencesLocked(sourcePkg, sourceUid); prefs.delegate = new Delegate(delegatePkg, delegateUid, true); } @@ -2036,7 +2039,7 @@ public class PreferencesHelper implements RankingConfig { * Used by an app to turn off its notification delegate. */ public void revokeNotificationDelegate(String sourcePkg, int sourceUid) { - synchronized (mPackagePreferences) { + synchronized (mLock) { PackagePreferences prefs = getPackagePreferencesLocked(sourcePkg, sourceUid); if (prefs != null && prefs.delegate != null) { prefs.delegate.mEnabled = false; @@ -2050,7 +2053,7 @@ public class PreferencesHelper implements RankingConfig { */ public boolean isDelegateAllowed(String sourcePkg, int sourceUid, String potentialDelegatePkg, int potentialDelegateUid) { - synchronized (mPackagePreferences) { + synchronized (mLock) { PackagePreferences prefs = getPackagePreferencesLocked(sourcePkg, sourceUid); return prefs != null && prefs.isValidDelegate(potentialDelegatePkg, @@ -2096,24 +2099,25 @@ public class PreferencesHelper implements RankingConfig { pw.println("per-package config version: " + XML_VERSION); pw.println("PackagePreferences:"); - synchronized (mPackagePreferences) { + synchronized (mLock) { dumpPackagePreferencesLocked(pw, prefix, filter, mPackagePreferences, pkgPermissions); + pw.println("Restored without uid:"); + dumpPackagePreferencesLocked(pw, prefix, filter, mRestoredWithoutUids, null); } - pw.println("Restored without uid:"); - dumpPackagePreferencesLocked(pw, prefix, filter, mRestoredWithoutUids, null); } public void dump(ProtoOutputStream proto, @NonNull NotificationManagerService.DumpFilter filter, ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> pkgPermissions) { - synchronized (mPackagePreferences) { + synchronized (mLock) { dumpPackagePreferencesLocked(proto, RankingHelperProto.RECORDS, filter, mPackagePreferences, pkgPermissions); + dumpPackagePreferencesLocked(proto, RankingHelperProto.RECORDS_RESTORED_WITHOUT_UID, + filter, mRestoredWithoutUids, null); } - dumpPackagePreferencesLocked(proto, RankingHelperProto.RECORDS_RESTORED_WITHOUT_UID, filter, - mRestoredWithoutUids, null); } + @GuardedBy("mLock") private void dumpPackagePreferencesLocked(PrintWriter pw, String prefix, @NonNull NotificationManagerService.DumpFilter filter, ArrayMap<String, PackagePreferences> packagePreferences, @@ -2298,7 +2302,7 @@ public class PreferencesHelper implements RankingConfig { pkgsWithPermissionsToHandle = pkgPermissions.keySet(); } int pulledEvents = 0; - synchronized (mPackagePreferences) { + synchronized (mLock) { for (int i = 0; i < mPackagePreferences.size(); i++) { if (pulledEvents > NOTIFICATION_PREFERENCES_PULL_LIMIT) { break; @@ -2378,7 +2382,7 @@ public class PreferencesHelper implements RankingConfig { * {@link StatsEvent}. */ public void pullPackageChannelPreferencesStats(List<StatsEvent> events) { - synchronized (mPackagePreferences) { + synchronized (mLock) { int totalChannelsPulled = 0; for (int i = 0; i < mPackagePreferences.size(); i++) { if (totalChannelsPulled > NOTIFICATION_CHANNEL_PULL_LIMIT) { @@ -2414,7 +2418,7 @@ public class PreferencesHelper implements RankingConfig { * {@link StatsEvent}. */ public void pullPackageChannelGroupPreferencesStats(List<StatsEvent> events) { - synchronized (mPackagePreferences) { + synchronized (mLock) { int totalGroupsPulled = 0; for (int i = 0; i < mPackagePreferences.size(); i++) { if (totalGroupsPulled > NOTIFICATION_CHANNEL_GROUP_PULL_LIMIT) { @@ -2443,10 +2447,12 @@ public class PreferencesHelper implements RankingConfig { ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> pkgPermissions) { JSONObject ranking = new JSONObject(); JSONArray PackagePreferencess = new JSONArray(); - try { - ranking.put("noUid", mRestoredWithoutUids.size()); - } catch (JSONException e) { - // pass + synchronized (mLock) { + try { + ranking.put("noUid", mRestoredWithoutUids.size()); + } catch (JSONException e) { + // pass + } } // Track data that we've handled from the permissions-based list @@ -2455,7 +2461,7 @@ public class PreferencesHelper implements RankingConfig { pkgsWithPermissionsToHandle = pkgPermissions.keySet(); } - synchronized (mPackagePreferences) { + synchronized (mLock) { final int N = mPackagePreferences.size(); for (int i = 0; i < N; i++) { final PackagePreferences r = mPackagePreferences.valueAt(i); @@ -2561,7 +2567,7 @@ public class PreferencesHelper implements RankingConfig { } public Map<Integer, String> getPackageBans() { - synchronized (mPackagePreferences) { + synchronized (mLock) { final int N = mPackagePreferences.size(); ArrayMap<Integer, String> packageBans = new ArrayMap<>(N); for (int i = 0; i < N; i++) { @@ -2620,7 +2626,7 @@ public class PreferencesHelper implements RankingConfig { private Map<String, Integer> getPackageChannels() { ArrayMap<String, Integer> packageChannels = new ArrayMap<>(); - synchronized (mPackagePreferences) { + synchronized (mLock) { for (int i = 0; i < mPackagePreferences.size(); i++) { final PackagePreferences r = mPackagePreferences.valueAt(i); int channelCount = 0; @@ -2636,7 +2642,7 @@ public class PreferencesHelper implements RankingConfig { } public void onUserRemoved(int userId) { - synchronized (mPackagePreferences) { + synchronized (mLock) { int N = mPackagePreferences.size(); for (int i = N - 1; i >= 0; i--) { PackagePreferences PackagePreferences = mPackagePreferences.valueAt(i); @@ -2648,7 +2654,7 @@ public class PreferencesHelper implements RankingConfig { } protected void onLocaleChanged(Context context, int userId) { - synchronized (mPackagePreferences) { + synchronized (mLock) { int N = mPackagePreferences.size(); for (int i = 0; i < N; i++) { PackagePreferences PackagePreferences = mPackagePreferences.valueAt(i); @@ -2678,22 +2684,24 @@ public class PreferencesHelper implements RankingConfig { for (int i = 0; i < size; i++) { final String pkg = pkgList[i]; final int uid = uidList[i]; - synchronized (mPackagePreferences) { + synchronized (mLock) { mPackagePreferences.remove(packagePreferencesKey(pkg, uid)); + mRestoredWithoutUids.remove(unrestoredPackageKey(pkg, changeUserId)); } - mRestoredWithoutUids.remove(unrestoredPackageKey(pkg, changeUserId)); updated = true; } } else { for (String pkg : pkgList) { - // Package install - final PackagePreferences r = - mRestoredWithoutUids.get(unrestoredPackageKey(pkg, changeUserId)); - if (r != null) { - try { - r.uid = mPm.getPackageUidAsUser(r.pkg, changeUserId); - mRestoredWithoutUids.remove(unrestoredPackageKey(pkg, changeUserId)); - synchronized (mPackagePreferences) { + try { + // Package install + int uid = mPm.getPackageUidAsUser(pkg, changeUserId); + PackagePermission p = null; + synchronized (mLock) { + final PackagePreferences r = + mRestoredWithoutUids.get(unrestoredPackageKey(pkg, changeUserId)); + if (r != null) { + r.uid = uid; + mRestoredWithoutUids.remove(unrestoredPackageKey(pkg, changeUserId)); mPackagePreferences.put(packagePreferencesKey(r.pkg, r.uid), r); // Try to restore any unrestored sound resources @@ -2715,32 +2723,29 @@ public class PreferencesHelper implements RankingConfig { channel.setSound(restoredUri, channel.getAudioAttributes()); } } - } - if (r.migrateToPm) { - try { - PackagePermission p = new PackagePermission( + + if (r.migrateToPm) { + p = new PackagePermission( r.pkg, UserHandle.getUserId(r.uid), r.importance != IMPORTANCE_NONE, hasUserConfiguredSettings(r)); - mPermissionHelper.setNotificationPermission(p); - } catch (Exception e) { - Slog.e(TAG, "could not migrate setting for " + r.pkg, e); } + updated = true; } - updated = true; - } catch (Exception e) { - Slog.e(TAG, "could not restore " + r.pkg, e); } + if (p != null) { + mPermissionHelper.setNotificationPermission(p); + } + } catch (Exception e) { + Slog.e(TAG, "could not restore " + pkg, e); } // Package upgrade try { - synchronized (mPackagePreferences) { - PackagePreferences fullPackagePreferences = getPackagePreferencesLocked(pkg, - mPm.getPackageUidAsUser(pkg, changeUserId)); - if (fullPackagePreferences != null) { - updated |= createDefaultChannelIfNeededLocked(fullPackagePreferences); - updated |= deleteDefaultChannelIfNeededLocked(fullPackagePreferences); - } + PackagePreferences fullPackagePreferences = getPackagePreferencesLocked(pkg, + mPm.getPackageUidAsUser(pkg, changeUserId)); + if (fullPackagePreferences != null) { + updated |= createDefaultChannelIfNeededLocked(fullPackagePreferences); + updated |= deleteDefaultChannelIfNeededLocked(fullPackagePreferences); } } catch (PackageManager.NameNotFoundException e) { } @@ -2754,7 +2759,7 @@ public class PreferencesHelper implements RankingConfig { } public void clearData(String pkg, int uid) { - synchronized (mPackagePreferences) { + synchronized (mLock) { PackagePreferences p = getPackagePreferencesLocked(pkg, uid); if (p != null) { p.channels = new ArrayMap<>(); @@ -2941,7 +2946,7 @@ public class PreferencesHelper implements RankingConfig { } public void unlockAllNotificationChannels() { - synchronized (mPackagePreferences) { + synchronized (mLock) { final int numPackagePreferences = mPackagePreferences.size(); for (int i = 0; i < numPackagePreferences; i++) { final PackagePreferences r = mPackagePreferences.valueAt(i); @@ -2958,7 +2963,7 @@ public class PreferencesHelper implements RankingConfig { PackageManager.PackageInfoFlags.of(PackageManager.MATCH_ALL), user.getUserHandle().getIdentifier()); for (PackageInfo pi : packages) { - synchronized (mPackagePreferences) { + synchronized (mLock) { PackagePreferences p = getOrCreatePackagePreferencesLocked( pi.packageName, pi.applicationInfo.uid); if (p.migrateToPm && p.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 d151345c287e..559c32413d70 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java @@ -188,6 +188,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.ThreadLocalRandom; @SmallTest @@ -489,6 +490,34 @@ public class PreferencesHelperTest extends UiServiceTestCase { when(mPm.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid); } + private static void testThreadSafety(Runnable operationToTest, int nThreads, + int nRunsPerThread) throws Exception { + final CountDownLatch startLatch = new CountDownLatch(1); + final CountDownLatch doneLatch = new CountDownLatch(nThreads); + + for (int i = 0; i < nThreads; i++) { + Runnable threadRunnable = () -> { + try { + startLatch.await(); + for (int j = 0; j < nRunsPerThread; j++) { + operationToTest.run(); + } + } catch (InterruptedException e) { + e.printStackTrace(); + } finally { + doneLatch.countDown(); + } + }; + new Thread(threadRunnable, "Test Thread #" + i).start(); + } + + // Ready set go + startLatch.countDown(); + + // Wait for all test threads to be done. + doneLatch.await(); + } + @Test public void testWriteXml_onlyBackupsTargetUser() throws Exception { // Setup package notifications. @@ -6193,6 +6222,36 @@ public class PreferencesHelperTest extends UiServiceTestCase { .isEqualTo(IMPORTANCE_LOW); } + + @Test + public void testRestoredWithoutUid_threadSafety() throws Exception { + when(mPm.getPackageUidAsUser(anyString(), anyInt())).thenReturn(UNKNOWN_UID); + when(mPm.getApplicationInfoAsUser(anyString(), anyInt(), anyInt())).thenThrow( + new PackageManager.NameNotFoundException()); + when(mClock.millis()).thenReturn(System.currentTimeMillis()); + testThreadSafety(() -> { + String id = "id"; + String xml = "<ranking version=\"1\">\n" + + "<package name=\"" + Thread.currentThread()+ "\" show_badge=\"true\">\n" + + "<channel id=\"" + id + "\" name=\"name\" importance=\"2\" " + + "show_badge=\"true\" />\n" + + "</package>\n" + + "<package name=\"" + PKG_P + "\" show_badge=\"true\">\n" + + "</package>\n" + + "</ranking>\n"; + + try { + loadByteArrayXml(xml.getBytes(), true, USER_SYSTEM); + } catch (Exception e) { + throw new RuntimeException(e); + } + + // trigger a removal from the list + mXmlHelper.onPackagesChanged(true, USER_SYSTEM, new String[]{PKG_P}, + new int[]{UNKNOWN_UID}); + }, 20, 50); + } + private static NotificationChannel cloneChannel(NotificationChannel original) { Parcel parcel = Parcel.obtain(); try { |