Loading services/core/java/com/android/server/notification/PermissionHelper.java +70 −8 Original line number Diff line number Diff line Loading @@ -21,22 +21,27 @@ import static android.content.pm.PackageManager.GET_PERMISSIONS; import static android.permission.PermissionManager.PERMISSION_GRANTED; import android.Manifest; import android.annotation.NonNull; import android.annotation.UserIdInt; import android.content.pm.IPackageManager; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.ParceledListSlice; import android.os.RemoteException; import android.os.UserHandle; import android.permission.IPermissionManager; import android.util.ArrayMap; import android.util.Pair; import android.util.Slog; import com.android.server.pm.permission.PermissionManagerServiceInternal; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; /** * NotificationManagerService helper for querying/setting the app-level notification permission Loading @@ -44,7 +49,7 @@ import java.util.Map; public final class PermissionHelper { private static final String TAG = "PermissionHelper"; private static String NOTIFICATION_PERMISSION = Manifest.permission.POST_NOTIFICATIONS; private static final String NOTIFICATION_PERMISSION = Manifest.permission.POST_NOTIFICATIONS; private final PermissionManagerServiceInternal mPmi; private final IPackageManager mPackageManager; Loading Loading @@ -77,9 +82,9 @@ public final class PermissionHelper { * Returns all of the apps that have requested the notification permission in a given user. * Must not be called with a lock held. Format: uid, packageName */ public Map<Integer, String> getAppsRequestingPermission(int userId) { Set<Pair<Integer, String>> getAppsRequestingPermission(int userId) { assertFlag(); Map<Integer, String> requested = new HashMap<>(); Set<Pair<Integer, String>> requested = new HashSet<>(); List<PackageInfo> pkgs = getInstalledPackages(userId); for (PackageInfo pi : pkgs) { // when data was stored in PreferencesHelper, we only had data for apps that Loading @@ -90,7 +95,7 @@ public final class PermissionHelper { } for (String perm : pi.requestedPermissions) { if (NOTIFICATION_PERMISSION.equals(perm)) { requested.put(pi.applicationInfo.uid, pi.packageName); requested.add(new Pair<>(pi.applicationInfo.uid, pi.packageName)); break; } } Loading @@ -115,9 +120,9 @@ public final class PermissionHelper { * Returns a list of apps that hold the notification permission. Must not be called * with a lock held. Format: uid, packageName. */ public Map<Integer, String> getAppsGrantedPermission(int userId) { Set<Pair<Integer, String>> getAppsGrantedPermission(int userId) { assertFlag(); Map<Integer, String> granted = new HashMap<>(); Set<Pair<Integer, String>> granted = new HashSet<>(); ParceledListSlice<PackageInfo> parceledList = null; try { parceledList = mPackageManager.getPackagesHoldingPermissions( Loading @@ -129,11 +134,24 @@ public final class PermissionHelper { return granted; } for (PackageInfo pi : parceledList.getList()) { granted.put(pi.applicationInfo.uid, pi.packageName); granted.add(new Pair<>(pi.applicationInfo.uid, pi.packageName)); } return granted; } public @NonNull ArrayMap<Pair<Integer, String>, Boolean> getNotificationPermissionValues( int userId) { assertFlag(); ArrayMap<Pair<Integer, String>, Boolean> notifPermissions = new ArrayMap<>(); Set<Pair<Integer, String>> allRequestingUids = getAppsRequestingPermission(userId); Set<Pair<Integer, String>> allApprovedUids = getAppsGrantedPermission(userId); for (Pair<Integer, String> pair : allRequestingUids) { notifPermissions.put(pair, allApprovedUids.contains(pair)); } return notifPermissions; } /** * Grants or revokes the notification permission for a given package/user. UserSet should * only be true if this method is being called to migrate existing user choice, because it Loading @@ -159,6 +177,12 @@ public final class PermissionHelper { } } public void setNotificationPermission(PackagePermission pkgPerm) { assertFlag(); setNotificationPermission( pkgPerm.packageName, pkgPerm.userId, pkgPerm.granted, pkgPerm.userSet); } public boolean isPermissionFixed(String packageName, @UserIdInt int userId) { assertFlag(); try { Loading @@ -177,4 +201,42 @@ public final class PermissionHelper { throw new IllegalStateException("Method called without checking flag value"); } } public static class PackagePermission { public final String packageName; public final @UserIdInt int userId; public final boolean granted; public final boolean userSet; public PackagePermission(String pkg, int userId, boolean granted, boolean userSet) { this.packageName = pkg; this.userId = userId; this.granted = granted; this.userSet = userSet; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; PackagePermission that = (PackagePermission) o; return userId == that.userId && granted == that.granted && userSet == that.userSet && Objects.equals(packageName, that.packageName); } @Override public int hashCode() { return Objects.hash(packageName, userId, granted, userSet); } @Override public String toString() { return "PackagePermission{" + "packageName='" + packageName + '\'' + ", userId=" + userId + ", granted=" + granted + ", userSet=" + userSet + '}'; } } } services/core/java/com/android/server/notification/PreferencesHelper.java +107 −78 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import static android.app.NotificationChannel.PLACEHOLDER_CONVERSATION_ID; import static android.app.NotificationChannel.USER_LOCKED_IMPORTANCE; import static android.app.NotificationManager.BUBBLE_PREFERENCE_ALL; import static android.app.NotificationManager.BUBBLE_PREFERENCE_NONE; import static android.app.NotificationManager.IMPORTANCE_DEFAULT; import static android.app.NotificationManager.IMPORTANCE_NONE; import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED; import static android.util.StatsLog.ANNOTATION_ID_IS_UID; Loading Loading @@ -68,6 +69,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.MetricsLogger; import com.android.internal.util.Preconditions; import com.android.internal.util.XmlUtils; import com.android.server.notification.PermissionHelper.PackagePermission; import org.json.JSONArray; import org.json.JSONException; Loading @@ -89,7 +91,7 @@ import java.util.concurrent.ConcurrentHashMap; public class PreferencesHelper implements RankingConfig { private static final String TAG = "NotificationPrefHelper"; private static final int XML_VERSION = 2; private final int XML_VERSION; /** What version to check to do the upgrade for bubbles. */ private static final int XML_VERSION_BUBBLES_UPGRADE = 1; @VisibleForTesting Loading Loading @@ -201,6 +203,12 @@ public class PreferencesHelper implements RankingConfig { mAppOps = appOpsManager; mStatsEventBuilderFactory = statsEventBuilderFactory; if (mPermissionHelper.isMigrationEnabled()) { XML_VERSION = 3; } else { XML_VERSION = 2; } updateBadgingEnabled(); updateBubblesEnabled(); updateMediaNotificationFilteringEnabled(); Loading @@ -217,11 +225,13 @@ public class PreferencesHelper implements RankingConfig { final int xmlVersion = parser.getAttributeInt(null, ATT_VERSION, -1); boolean upgradeForBubbles = xmlVersion == XML_VERSION_BUBBLES_UPGRADE; boolean migrateToPermission = (xmlVersion < XML_VERSION); ArrayList<PermissionHelper.PackagePermission> pkgPerms = new ArrayList<>(); synchronized (mPackagePreferences) { while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) { tag = parser.getName(); if (type == XmlPullParser.END_TAG && TAG_RANKING.equals(tag)) { return; break; } if (type == XmlPullParser.START_TAG) { if (TAG_STATUS_ICONS.equals(tag)) { Loading Loading @@ -252,11 +262,12 @@ public class PreferencesHelper implements RankingConfig { ? BUBBLE_PREFERENCE_ALL : parser.getAttributeInt( null, ATT_ALLOW_BUBBLE, DEFAULT_BUBBLE_PREFERENCE); int appImportance = parser.getAttributeInt( null, ATT_IMPORTANCE, DEFAULT_IMPORTANCE); PackagePreferences r = getOrCreatePackagePreferencesLocked( name, userId, uid, parser.getAttributeInt( null, ATT_IMPORTANCE, DEFAULT_IMPORTANCE), appImportance, parser.getAttributeInt( null, ATT_PRIORITY, DEFAULT_PRIORITY), parser.getAttributeInt( Loading @@ -264,8 +275,6 @@ public class PreferencesHelper implements RankingConfig { parser.getAttributeBoolean( null, ATT_SHOW_BADGE, DEFAULT_SHOW_BADGE), bubblePref); r.importance = parser.getAttributeInt( null, ATT_IMPORTANCE, DEFAULT_IMPORTANCE); r.priority = parser.getAttributeInt( null, ATT_PRIORITY, DEFAULT_PRIORITY); r.visibility = parser.getAttributeInt( Loading Loading @@ -340,6 +349,7 @@ public class PreferencesHelper implements RankingConfig { } } } // Delegate if (TAG_DELEGATE.equals(tagName)) { int delegateId = Loading Loading @@ -367,12 +377,30 @@ public class PreferencesHelper implements RankingConfig { } catch (PackageManager.NameNotFoundException e) { Slog.e(TAG, "deleteDefaultChannelIfNeededLocked - Exception: " + e); } if (migrateToPermission) { boolean hasChangedChannel = false; for (NotificationChannel channel : r.channels.values()) { if (channel.getUserLockedFields() != 0) { hasChangedChannel = true; break; } } PackagePermission pkgPerm = new PackagePermission( r.pkg, userId, appImportance != IMPORTANCE_NONE, hasChangedChannel || appImportance == IMPORTANCE_NONE); pkgPerms.add(pkgPerm); } else { r.importance = appImportance; } } } } } } throw new IllegalStateException("Failed to reach END_DOCUMENT"); for (PackagePermission p : pkgPerms) { mPermissionHelper.setNotificationPermission(p); } } private boolean isShortcutOk(NotificationChannel channel) { Loading Loading @@ -402,18 +430,12 @@ public class PreferencesHelper implements RankingConfig { private PackagePreferences getOrCreatePackagePreferencesLocked(String pkg, int uid) { // TODO (b/194833441): use permissionhelper instead of DEFAULT_IMPORTANCE return getOrCreatePackagePreferencesLocked(pkg, UserHandle.getUserId(uid), uid, DEFAULT_IMPORTANCE, DEFAULT_PRIORITY, DEFAULT_VISIBILITY, DEFAULT_SHOW_BADGE, DEFAULT_BUBBLE_PREFERENCE); } 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_BUBBLE_PREFERENCE); } private PackagePreferences getOrCreatePackagePreferencesLocked(String pkg, @UserIdInt int userId, int uid, int importance, int priority, int visibility, boolean showBadge, int bubblePreference) { Loading Loading @@ -535,6 +557,10 @@ public class PreferencesHelper implements RankingConfig { out.attributeBoolean(null, ATT_HIDE_SILENT, mHideSilentStatusBarIcons); out.endTag(null, TAG_STATUS_ICONS); } ArrayMap<Pair<Integer, String>, Boolean> notifPermissions = new ArrayMap<>(); if (mPermissionHelper.isMigrationEnabled() && forBackup) { notifPermissions = mPermissionHelper.getNotificationPermissionValues(userId); } synchronized (mPackagePreferences) { final int N = mPackagePreferences.size(); Loading @@ -543,25 +569,19 @@ public class PreferencesHelper implements RankingConfig { if (forBackup && UserHandle.getUserId(r.uid) != userId) { continue; } final boolean hasNonDefaultSettings = r.importance != DEFAULT_IMPORTANCE || r.priority != DEFAULT_PRIORITY || r.visibility != DEFAULT_VISIBILITY || r.showBadge != DEFAULT_SHOW_BADGE || r.lockedAppFields != DEFAULT_LOCKED_APP_FIELDS || r.channels.size() > 0 || r.groups.size() > 0 || r.delegate != null || r.bubblePreference != DEFAULT_BUBBLE_PREFERENCE || r.hasSentInvalidMessage || r.userDemotedMsgApp || r.hasSentValidMessage; if (hasNonDefaultSettings) { out.startTag(null, TAG_PACKAGE); out.attribute(null, ATT_NAME, r.pkg); if (!notifPermissions.isEmpty()) { Pair<Integer, String> app = new Pair(r.uid, r.pkg); out.attributeInt(null, ATT_IMPORTANCE, notifPermissions.get(app) ? IMPORTANCE_DEFAULT : IMPORTANCE_NONE); notifPermissions.remove(app); } else { if (r.importance != DEFAULT_IMPORTANCE) { out.attributeInt(null, ATT_IMPORTANCE, r.importance); } } if (r.priority != DEFAULT_PRIORITY) { out.attributeInt(null, ATT_PRIORITY, r.priority); } Loading Loading @@ -616,6 +636,15 @@ public class PreferencesHelper implements RankingConfig { out.endTag(null, TAG_PACKAGE); } } // Some apps have permissions set but don't have expanded notification settings if (!notifPermissions.isEmpty()) { for (Pair<Integer, String> app : notifPermissions.keySet()) { out.startTag(null, TAG_PACKAGE); out.attribute(null, ATT_NAME, app.second); out.attributeInt(null, ATT_IMPORTANCE, notifPermissions.get(app) ? IMPORTANCE_DEFAULT : IMPORTANCE_NONE); out.endTag(null, TAG_PACKAGE); } } out.endTag(null, TAG_RANKING); } Loading Loading @@ -1904,7 +1933,7 @@ public class PreferencesHelper implements RankingConfig { public void dump(PrintWriter pw, String prefix, @NonNull NotificationManagerService.DumpFilter filter) { pw.print(prefix); pw.println("per-package config:"); pw.println("per-package config version: " + XML_VERSION); pw.println("PackagePreferences:"); synchronized (mPackagePreferences) { Loading @@ -1924,7 +1953,7 @@ public class PreferencesHelper implements RankingConfig { mRestoredWithoutUids); } private static void dumpPackagePreferencesLocked(PrintWriter pw, String prefix, private void dumpPackagePreferencesLocked(PrintWriter pw, String prefix, @NonNull NotificationManagerService.DumpFilter filter, ArrayMap<String, PackagePreferences> packagePreferences) { final int N = packagePreferences.size(); Loading @@ -1937,7 +1966,7 @@ public class PreferencesHelper implements RankingConfig { pw.print(" ("); pw.print(r.uid == UNKNOWN_UID ? "UNKNOWN_UID" : Integer.toString(r.uid)); pw.print(')'); if (r.importance != DEFAULT_IMPORTANCE) { if (!mPermissionHelper.isMigrationEnabled() && r.importance != DEFAULT_IMPORTANCE) { pw.print(" importance="); pw.print(NotificationListenerService.Ranking.importanceToString(r.importance)); } Loading services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java +59 −6 Original line number Diff line number Diff line Loading @@ -38,10 +38,11 @@ import android.Manifest; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.ParceledListSlice; import android.permission.IPermissionManager; import android.test.suitebuilder.annotation.SmallTest; import android.util.Pair; import android.util.Slog; import androidx.test.runner.AndroidJUnit4; Loading @@ -50,6 +51,7 @@ import com.android.server.pm.permission.PermissionManagerServiceInternal; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import org.junit.Before; Loading @@ -66,6 +68,7 @@ import java.lang.reflect.Type; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; @SmallTest @RunWith(AndroidJUnit4.class) Loading Loading @@ -107,6 +110,9 @@ public class PermissionHelperTest extends UiServiceTestCase { args.add(false); } else if (type.getTypeName().equals("int")) { args.add(1); } else if (type.getTypeName().equals( "com.android.server.notification.PermissionHelper$PackagePermission")) { args.add(null); } } try { Loading Loading @@ -158,15 +164,16 @@ public class PermissionHelperTest extends UiServiceTestCase { aiSecond.uid = 2; second.applicationInfo = aiSecond; Map<Integer, String> expected = ImmutableMap.of(1, "first", 2, "second"); Set<Pair<Integer, String>> expected = ImmutableSet.of(new Pair(1, "first"), new Pair(2, "second")); ParceledListSlice<PackageInfo> infos = new ParceledListSlice<>( ImmutableList.of(notThis, none, first, second)); when(mPackageManager.getInstalledPackages(eq(GET_PERMISSIONS), anyInt())).thenReturn(infos); Map<Integer, String> actual = mPermissionHelper.getAppsRequestingPermission(0); Set<Pair<Integer, String>> actual = mPermissionHelper.getAppsRequestingPermission(0); assertThat(actual).containsExactlyEntriesIn(expected); assertThat(actual).containsExactlyElementsIn(expected); } @Test Loading Loading @@ -202,10 +209,11 @@ public class PermissionHelperTest extends UiServiceTestCase { eq(new String[] {Manifest.permission.POST_NOTIFICATIONS}), anyInt(), eq(userId))) .thenReturn(infos); Map<Integer, String> expected = ImmutableMap.of(1, "first", 2, "second"); Set<Pair<Integer, String>> expected = ImmutableSet.of(new Pair(1, "first"), new Pair(2, "second")); assertThat(mPermissionHelper.getAppsGrantedPermission(userId)) .containsExactlyEntriesIn(expected); .containsExactlyElementsIn(expected); } @Test Loading Loading @@ -268,4 +276,49 @@ public class PermissionHelperTest extends UiServiceTestCase { assertThat(mPermissionHelper.isPermissionFixed("pkg", 0)).isTrue(); } @Test public void testGetNotificationPermissionValues() throws Exception { int userId = 1; PackageInfo first = new PackageInfo(); first.packageName = "first"; first.requestedPermissions = new String[] {"something else", Manifest.permission.POST_NOTIFICATIONS}; ApplicationInfo aiFirst = new ApplicationInfo(); aiFirst.uid = 1; first.applicationInfo = aiFirst; PackageInfo second = new PackageInfo(); second.packageName = "second"; second.requestedPermissions = new String[] {Manifest.permission.POST_NOTIFICATIONS}; ApplicationInfo aiSecond = new ApplicationInfo(); aiSecond.uid = 2; second.applicationInfo = aiSecond; PackageInfo third = new PackageInfo(); third.packageName = "third"; third.requestedPermissions = new String[] {Manifest.permission.POST_NOTIFICATIONS}; ApplicationInfo aiThird = new ApplicationInfo(); aiThird.uid = 3; third.applicationInfo = aiThird; ParceledListSlice<PackageInfo> infos = new ParceledListSlice<>( ImmutableList.of(first, second)); when(mPackageManager.getPackagesHoldingPermissions( eq(new String[] {Manifest.permission.POST_NOTIFICATIONS}), anyInt(), eq(userId))) .thenReturn(infos); ParceledListSlice<PackageInfo> requesting = new ParceledListSlice<>( ImmutableList.of(first, second, third)); when(mPackageManager.getInstalledPackages(eq(GET_PERMISSIONS), anyInt())) .thenReturn(requesting); Map<Pair<Integer, String>, Boolean> expected = ImmutableMap.of(new Pair(1, "first"), true, new Pair(2, "second"), true, new Pair(3, "third"), false); Map<Pair<Integer, String>, Boolean> actual = mPermissionHelper.getNotificationPermissionValues(userId); assertThat(actual).containsExactlyEntriesIn(expected); } } services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java +394 −0 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
services/core/java/com/android/server/notification/PermissionHelper.java +70 −8 Original line number Diff line number Diff line Loading @@ -21,22 +21,27 @@ import static android.content.pm.PackageManager.GET_PERMISSIONS; import static android.permission.PermissionManager.PERMISSION_GRANTED; import android.Manifest; import android.annotation.NonNull; import android.annotation.UserIdInt; import android.content.pm.IPackageManager; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.ParceledListSlice; import android.os.RemoteException; import android.os.UserHandle; import android.permission.IPermissionManager; import android.util.ArrayMap; import android.util.Pair; import android.util.Slog; import com.android.server.pm.permission.PermissionManagerServiceInternal; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; /** * NotificationManagerService helper for querying/setting the app-level notification permission Loading @@ -44,7 +49,7 @@ import java.util.Map; public final class PermissionHelper { private static final String TAG = "PermissionHelper"; private static String NOTIFICATION_PERMISSION = Manifest.permission.POST_NOTIFICATIONS; private static final String NOTIFICATION_PERMISSION = Manifest.permission.POST_NOTIFICATIONS; private final PermissionManagerServiceInternal mPmi; private final IPackageManager mPackageManager; Loading Loading @@ -77,9 +82,9 @@ public final class PermissionHelper { * Returns all of the apps that have requested the notification permission in a given user. * Must not be called with a lock held. Format: uid, packageName */ public Map<Integer, String> getAppsRequestingPermission(int userId) { Set<Pair<Integer, String>> getAppsRequestingPermission(int userId) { assertFlag(); Map<Integer, String> requested = new HashMap<>(); Set<Pair<Integer, String>> requested = new HashSet<>(); List<PackageInfo> pkgs = getInstalledPackages(userId); for (PackageInfo pi : pkgs) { // when data was stored in PreferencesHelper, we only had data for apps that Loading @@ -90,7 +95,7 @@ public final class PermissionHelper { } for (String perm : pi.requestedPermissions) { if (NOTIFICATION_PERMISSION.equals(perm)) { requested.put(pi.applicationInfo.uid, pi.packageName); requested.add(new Pair<>(pi.applicationInfo.uid, pi.packageName)); break; } } Loading @@ -115,9 +120,9 @@ public final class PermissionHelper { * Returns a list of apps that hold the notification permission. Must not be called * with a lock held. Format: uid, packageName. */ public Map<Integer, String> getAppsGrantedPermission(int userId) { Set<Pair<Integer, String>> getAppsGrantedPermission(int userId) { assertFlag(); Map<Integer, String> granted = new HashMap<>(); Set<Pair<Integer, String>> granted = new HashSet<>(); ParceledListSlice<PackageInfo> parceledList = null; try { parceledList = mPackageManager.getPackagesHoldingPermissions( Loading @@ -129,11 +134,24 @@ public final class PermissionHelper { return granted; } for (PackageInfo pi : parceledList.getList()) { granted.put(pi.applicationInfo.uid, pi.packageName); granted.add(new Pair<>(pi.applicationInfo.uid, pi.packageName)); } return granted; } public @NonNull ArrayMap<Pair<Integer, String>, Boolean> getNotificationPermissionValues( int userId) { assertFlag(); ArrayMap<Pair<Integer, String>, Boolean> notifPermissions = new ArrayMap<>(); Set<Pair<Integer, String>> allRequestingUids = getAppsRequestingPermission(userId); Set<Pair<Integer, String>> allApprovedUids = getAppsGrantedPermission(userId); for (Pair<Integer, String> pair : allRequestingUids) { notifPermissions.put(pair, allApprovedUids.contains(pair)); } return notifPermissions; } /** * Grants or revokes the notification permission for a given package/user. UserSet should * only be true if this method is being called to migrate existing user choice, because it Loading @@ -159,6 +177,12 @@ public final class PermissionHelper { } } public void setNotificationPermission(PackagePermission pkgPerm) { assertFlag(); setNotificationPermission( pkgPerm.packageName, pkgPerm.userId, pkgPerm.granted, pkgPerm.userSet); } public boolean isPermissionFixed(String packageName, @UserIdInt int userId) { assertFlag(); try { Loading @@ -177,4 +201,42 @@ public final class PermissionHelper { throw new IllegalStateException("Method called without checking flag value"); } } public static class PackagePermission { public final String packageName; public final @UserIdInt int userId; public final boolean granted; public final boolean userSet; public PackagePermission(String pkg, int userId, boolean granted, boolean userSet) { this.packageName = pkg; this.userId = userId; this.granted = granted; this.userSet = userSet; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; PackagePermission that = (PackagePermission) o; return userId == that.userId && granted == that.granted && userSet == that.userSet && Objects.equals(packageName, that.packageName); } @Override public int hashCode() { return Objects.hash(packageName, userId, granted, userSet); } @Override public String toString() { return "PackagePermission{" + "packageName='" + packageName + '\'' + ", userId=" + userId + ", granted=" + granted + ", userSet=" + userSet + '}'; } } }
services/core/java/com/android/server/notification/PreferencesHelper.java +107 −78 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import static android.app.NotificationChannel.PLACEHOLDER_CONVERSATION_ID; import static android.app.NotificationChannel.USER_LOCKED_IMPORTANCE; import static android.app.NotificationManager.BUBBLE_PREFERENCE_ALL; import static android.app.NotificationManager.BUBBLE_PREFERENCE_NONE; import static android.app.NotificationManager.IMPORTANCE_DEFAULT; import static android.app.NotificationManager.IMPORTANCE_NONE; import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED; import static android.util.StatsLog.ANNOTATION_ID_IS_UID; Loading Loading @@ -68,6 +69,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.MetricsLogger; import com.android.internal.util.Preconditions; import com.android.internal.util.XmlUtils; import com.android.server.notification.PermissionHelper.PackagePermission; import org.json.JSONArray; import org.json.JSONException; Loading @@ -89,7 +91,7 @@ import java.util.concurrent.ConcurrentHashMap; public class PreferencesHelper implements RankingConfig { private static final String TAG = "NotificationPrefHelper"; private static final int XML_VERSION = 2; private final int XML_VERSION; /** What version to check to do the upgrade for bubbles. */ private static final int XML_VERSION_BUBBLES_UPGRADE = 1; @VisibleForTesting Loading Loading @@ -201,6 +203,12 @@ public class PreferencesHelper implements RankingConfig { mAppOps = appOpsManager; mStatsEventBuilderFactory = statsEventBuilderFactory; if (mPermissionHelper.isMigrationEnabled()) { XML_VERSION = 3; } else { XML_VERSION = 2; } updateBadgingEnabled(); updateBubblesEnabled(); updateMediaNotificationFilteringEnabled(); Loading @@ -217,11 +225,13 @@ public class PreferencesHelper implements RankingConfig { final int xmlVersion = parser.getAttributeInt(null, ATT_VERSION, -1); boolean upgradeForBubbles = xmlVersion == XML_VERSION_BUBBLES_UPGRADE; boolean migrateToPermission = (xmlVersion < XML_VERSION); ArrayList<PermissionHelper.PackagePermission> pkgPerms = new ArrayList<>(); synchronized (mPackagePreferences) { while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) { tag = parser.getName(); if (type == XmlPullParser.END_TAG && TAG_RANKING.equals(tag)) { return; break; } if (type == XmlPullParser.START_TAG) { if (TAG_STATUS_ICONS.equals(tag)) { Loading Loading @@ -252,11 +262,12 @@ public class PreferencesHelper implements RankingConfig { ? BUBBLE_PREFERENCE_ALL : parser.getAttributeInt( null, ATT_ALLOW_BUBBLE, DEFAULT_BUBBLE_PREFERENCE); int appImportance = parser.getAttributeInt( null, ATT_IMPORTANCE, DEFAULT_IMPORTANCE); PackagePreferences r = getOrCreatePackagePreferencesLocked( name, userId, uid, parser.getAttributeInt( null, ATT_IMPORTANCE, DEFAULT_IMPORTANCE), appImportance, parser.getAttributeInt( null, ATT_PRIORITY, DEFAULT_PRIORITY), parser.getAttributeInt( Loading @@ -264,8 +275,6 @@ public class PreferencesHelper implements RankingConfig { parser.getAttributeBoolean( null, ATT_SHOW_BADGE, DEFAULT_SHOW_BADGE), bubblePref); r.importance = parser.getAttributeInt( null, ATT_IMPORTANCE, DEFAULT_IMPORTANCE); r.priority = parser.getAttributeInt( null, ATT_PRIORITY, DEFAULT_PRIORITY); r.visibility = parser.getAttributeInt( Loading Loading @@ -340,6 +349,7 @@ public class PreferencesHelper implements RankingConfig { } } } // Delegate if (TAG_DELEGATE.equals(tagName)) { int delegateId = Loading Loading @@ -367,12 +377,30 @@ public class PreferencesHelper implements RankingConfig { } catch (PackageManager.NameNotFoundException e) { Slog.e(TAG, "deleteDefaultChannelIfNeededLocked - Exception: " + e); } if (migrateToPermission) { boolean hasChangedChannel = false; for (NotificationChannel channel : r.channels.values()) { if (channel.getUserLockedFields() != 0) { hasChangedChannel = true; break; } } PackagePermission pkgPerm = new PackagePermission( r.pkg, userId, appImportance != IMPORTANCE_NONE, hasChangedChannel || appImportance == IMPORTANCE_NONE); pkgPerms.add(pkgPerm); } else { r.importance = appImportance; } } } } } } throw new IllegalStateException("Failed to reach END_DOCUMENT"); for (PackagePermission p : pkgPerms) { mPermissionHelper.setNotificationPermission(p); } } private boolean isShortcutOk(NotificationChannel channel) { Loading Loading @@ -402,18 +430,12 @@ public class PreferencesHelper implements RankingConfig { private PackagePreferences getOrCreatePackagePreferencesLocked(String pkg, int uid) { // TODO (b/194833441): use permissionhelper instead of DEFAULT_IMPORTANCE return getOrCreatePackagePreferencesLocked(pkg, UserHandle.getUserId(uid), uid, DEFAULT_IMPORTANCE, DEFAULT_PRIORITY, DEFAULT_VISIBILITY, DEFAULT_SHOW_BADGE, DEFAULT_BUBBLE_PREFERENCE); } 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_BUBBLE_PREFERENCE); } private PackagePreferences getOrCreatePackagePreferencesLocked(String pkg, @UserIdInt int userId, int uid, int importance, int priority, int visibility, boolean showBadge, int bubblePreference) { Loading Loading @@ -535,6 +557,10 @@ public class PreferencesHelper implements RankingConfig { out.attributeBoolean(null, ATT_HIDE_SILENT, mHideSilentStatusBarIcons); out.endTag(null, TAG_STATUS_ICONS); } ArrayMap<Pair<Integer, String>, Boolean> notifPermissions = new ArrayMap<>(); if (mPermissionHelper.isMigrationEnabled() && forBackup) { notifPermissions = mPermissionHelper.getNotificationPermissionValues(userId); } synchronized (mPackagePreferences) { final int N = mPackagePreferences.size(); Loading @@ -543,25 +569,19 @@ public class PreferencesHelper implements RankingConfig { if (forBackup && UserHandle.getUserId(r.uid) != userId) { continue; } final boolean hasNonDefaultSettings = r.importance != DEFAULT_IMPORTANCE || r.priority != DEFAULT_PRIORITY || r.visibility != DEFAULT_VISIBILITY || r.showBadge != DEFAULT_SHOW_BADGE || r.lockedAppFields != DEFAULT_LOCKED_APP_FIELDS || r.channels.size() > 0 || r.groups.size() > 0 || r.delegate != null || r.bubblePreference != DEFAULT_BUBBLE_PREFERENCE || r.hasSentInvalidMessage || r.userDemotedMsgApp || r.hasSentValidMessage; if (hasNonDefaultSettings) { out.startTag(null, TAG_PACKAGE); out.attribute(null, ATT_NAME, r.pkg); if (!notifPermissions.isEmpty()) { Pair<Integer, String> app = new Pair(r.uid, r.pkg); out.attributeInt(null, ATT_IMPORTANCE, notifPermissions.get(app) ? IMPORTANCE_DEFAULT : IMPORTANCE_NONE); notifPermissions.remove(app); } else { if (r.importance != DEFAULT_IMPORTANCE) { out.attributeInt(null, ATT_IMPORTANCE, r.importance); } } if (r.priority != DEFAULT_PRIORITY) { out.attributeInt(null, ATT_PRIORITY, r.priority); } Loading Loading @@ -616,6 +636,15 @@ public class PreferencesHelper implements RankingConfig { out.endTag(null, TAG_PACKAGE); } } // Some apps have permissions set but don't have expanded notification settings if (!notifPermissions.isEmpty()) { for (Pair<Integer, String> app : notifPermissions.keySet()) { out.startTag(null, TAG_PACKAGE); out.attribute(null, ATT_NAME, app.second); out.attributeInt(null, ATT_IMPORTANCE, notifPermissions.get(app) ? IMPORTANCE_DEFAULT : IMPORTANCE_NONE); out.endTag(null, TAG_PACKAGE); } } out.endTag(null, TAG_RANKING); } Loading Loading @@ -1904,7 +1933,7 @@ public class PreferencesHelper implements RankingConfig { public void dump(PrintWriter pw, String prefix, @NonNull NotificationManagerService.DumpFilter filter) { pw.print(prefix); pw.println("per-package config:"); pw.println("per-package config version: " + XML_VERSION); pw.println("PackagePreferences:"); synchronized (mPackagePreferences) { Loading @@ -1924,7 +1953,7 @@ public class PreferencesHelper implements RankingConfig { mRestoredWithoutUids); } private static void dumpPackagePreferencesLocked(PrintWriter pw, String prefix, private void dumpPackagePreferencesLocked(PrintWriter pw, String prefix, @NonNull NotificationManagerService.DumpFilter filter, ArrayMap<String, PackagePreferences> packagePreferences) { final int N = packagePreferences.size(); Loading @@ -1937,7 +1966,7 @@ public class PreferencesHelper implements RankingConfig { pw.print(" ("); pw.print(r.uid == UNKNOWN_UID ? "UNKNOWN_UID" : Integer.toString(r.uid)); pw.print(')'); if (r.importance != DEFAULT_IMPORTANCE) { if (!mPermissionHelper.isMigrationEnabled() && r.importance != DEFAULT_IMPORTANCE) { pw.print(" importance="); pw.print(NotificationListenerService.Ranking.importanceToString(r.importance)); } Loading
services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java +59 −6 Original line number Diff line number Diff line Loading @@ -38,10 +38,11 @@ import android.Manifest; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.ParceledListSlice; import android.permission.IPermissionManager; import android.test.suitebuilder.annotation.SmallTest; import android.util.Pair; import android.util.Slog; import androidx.test.runner.AndroidJUnit4; Loading @@ -50,6 +51,7 @@ import com.android.server.pm.permission.PermissionManagerServiceInternal; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import org.junit.Before; Loading @@ -66,6 +68,7 @@ import java.lang.reflect.Type; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; @SmallTest @RunWith(AndroidJUnit4.class) Loading Loading @@ -107,6 +110,9 @@ public class PermissionHelperTest extends UiServiceTestCase { args.add(false); } else if (type.getTypeName().equals("int")) { args.add(1); } else if (type.getTypeName().equals( "com.android.server.notification.PermissionHelper$PackagePermission")) { args.add(null); } } try { Loading Loading @@ -158,15 +164,16 @@ public class PermissionHelperTest extends UiServiceTestCase { aiSecond.uid = 2; second.applicationInfo = aiSecond; Map<Integer, String> expected = ImmutableMap.of(1, "first", 2, "second"); Set<Pair<Integer, String>> expected = ImmutableSet.of(new Pair(1, "first"), new Pair(2, "second")); ParceledListSlice<PackageInfo> infos = new ParceledListSlice<>( ImmutableList.of(notThis, none, first, second)); when(mPackageManager.getInstalledPackages(eq(GET_PERMISSIONS), anyInt())).thenReturn(infos); Map<Integer, String> actual = mPermissionHelper.getAppsRequestingPermission(0); Set<Pair<Integer, String>> actual = mPermissionHelper.getAppsRequestingPermission(0); assertThat(actual).containsExactlyEntriesIn(expected); assertThat(actual).containsExactlyElementsIn(expected); } @Test Loading Loading @@ -202,10 +209,11 @@ public class PermissionHelperTest extends UiServiceTestCase { eq(new String[] {Manifest.permission.POST_NOTIFICATIONS}), anyInt(), eq(userId))) .thenReturn(infos); Map<Integer, String> expected = ImmutableMap.of(1, "first", 2, "second"); Set<Pair<Integer, String>> expected = ImmutableSet.of(new Pair(1, "first"), new Pair(2, "second")); assertThat(mPermissionHelper.getAppsGrantedPermission(userId)) .containsExactlyEntriesIn(expected); .containsExactlyElementsIn(expected); } @Test Loading Loading @@ -268,4 +276,49 @@ public class PermissionHelperTest extends UiServiceTestCase { assertThat(mPermissionHelper.isPermissionFixed("pkg", 0)).isTrue(); } @Test public void testGetNotificationPermissionValues() throws Exception { int userId = 1; PackageInfo first = new PackageInfo(); first.packageName = "first"; first.requestedPermissions = new String[] {"something else", Manifest.permission.POST_NOTIFICATIONS}; ApplicationInfo aiFirst = new ApplicationInfo(); aiFirst.uid = 1; first.applicationInfo = aiFirst; PackageInfo second = new PackageInfo(); second.packageName = "second"; second.requestedPermissions = new String[] {Manifest.permission.POST_NOTIFICATIONS}; ApplicationInfo aiSecond = new ApplicationInfo(); aiSecond.uid = 2; second.applicationInfo = aiSecond; PackageInfo third = new PackageInfo(); third.packageName = "third"; third.requestedPermissions = new String[] {Manifest.permission.POST_NOTIFICATIONS}; ApplicationInfo aiThird = new ApplicationInfo(); aiThird.uid = 3; third.applicationInfo = aiThird; ParceledListSlice<PackageInfo> infos = new ParceledListSlice<>( ImmutableList.of(first, second)); when(mPackageManager.getPackagesHoldingPermissions( eq(new String[] {Manifest.permission.POST_NOTIFICATIONS}), anyInt(), eq(userId))) .thenReturn(infos); ParceledListSlice<PackageInfo> requesting = new ParceledListSlice<>( ImmutableList.of(first, second, third)); when(mPackageManager.getInstalledPackages(eq(GET_PERMISSIONS), anyInt())) .thenReturn(requesting); Map<Pair<Integer, String>, Boolean> expected = ImmutableMap.of(new Pair(1, "first"), true, new Pair(2, "second"), true, new Pair(3, "third"), false); Map<Pair<Integer, String>, Boolean> actual = mPermissionHelper.getNotificationPermissionValues(userId); assertThat(actual).containsExactlyEntriesIn(expected); } }
services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java +394 −0 File changed.Preview size limit exceeded, changes collapsed. Show changes