diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 703d81223e0e2..e8a65287b52b7 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -160,6 +160,7 @@ import java.util.Arrays; import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Map.Entry; import java.util.Objects; import java.util.Set; @@ -276,9 +277,6 @@ public class NotificationManagerService extends SystemService { // Persistent storage for notification policy private AtomicFile mPolicyFile; - // Temporary holder for config coming from old policy files. - private HashSet mBlockedPackages = new HashSet(); - private static final int DB_VERSION = 1; private static final String TAG_NOTIFICATION_POLICY = "notification-policy"; @@ -354,27 +352,7 @@ public class NotificationManagerService extends SystemService { final XmlPullParser parser = Xml.newPullParser(); parser.setInput(stream, StandardCharsets.UTF_8.name()); - int type; - String tag; - int version = DB_VERSION; - while ((type = parser.next()) != END_DOCUMENT) { - tag = parser.getName(); - if (type == START_TAG) { - if (TAG_NOTIFICATION_POLICY.equals(tag)) { - version = Integer.parseInt( - parser.getAttributeValue(null, ATTR_VERSION)); - } else if (TAG_BLOCKED_PKGS.equals(tag)) { - while ((type = parser.next()) != END_DOCUMENT) { - tag = parser.getName(); - if (TAG_PACKAGE.equals(tag)) { - mBlockedPackages.add( - parser.getAttributeValue(null, ATTR_NAME)); - } else if (TAG_BLOCKED_PKGS.equals(tag) && type == END_TAG) { - break; - } - } - } - } + while (parser.next() != END_DOCUMENT) { mZenModeHelper.readXml(parser, forRestore); mRankingHelper.readXml(parser, forRestore); } @@ -383,7 +361,6 @@ public class NotificationManagerService extends SystemService { private void loadPolicyFile() { if (DBG) Slog.d(TAG, "loadPolicyFile"); synchronized(mPolicyFile) { - mBlockedPackages.clear(); FileInputStream infile = null; try { @@ -941,7 +918,7 @@ public class NotificationManagerService extends SystemService { final File systemDir = new File(Environment.getDataDirectory(), "system"); mPolicyFile = new AtomicFile(new File(systemDir, "notification_policy.xml")); - importOldBlockDb(); + syncBlockDb(); // This is a MangedServices object that keeps track of the listeners. mListeners = new NotificationListeners(); @@ -1041,22 +1018,43 @@ public class NotificationManagerService extends SystemService { } /** - * Read the old XML-based app block database and import those blockages into the AppOps system. + * Make sure the XML config and the the AppOps system agree about blocks. */ - private void importOldBlockDb() { + private void syncBlockDb() { loadPolicyFile(); - PackageManager pm = getContext().getPackageManager(); - for (String pkg : mBlockedPackages) { - PackageInfo info = null; - try { - info = pm.getPackageInfo(pkg, 0); - setNotificationsEnabledForPackageImpl(pkg, info.applicationInfo.uid, false); - } catch (NameNotFoundException e) { - // forget you + // sync bans from ranker into app opps + Map packageBans = mRankingHelper.getPackageBans(); + for(Entry ban : packageBans.entrySet()) { + final int uid = ban.getKey(); + final String packageName = ban.getValue(); + setNotificationsEnabledForPackageImpl(packageName, uid, false); + } + + // sync bans from app opps into ranker + packageBans.clear(); + for (UserInfo user : UserManager.get(getContext()).getUsers()) { + final int userId = user.getUserHandle().getIdentifier(); + final PackageManager packageManager = getContext().getPackageManager(); + List packages = packageManager.getInstalledPackagesAsUser(0, userId); + final int packageCount = packages.size(); + for (int p = 0; p < packageCount; p++) { + final String packageName = packages.get(p).packageName; + try { + final int uid = packageManager.getPackageUidAsUser(packageName, userId); + if (!checkNotificationOp(packageName, uid)) { + packageBans.put(uid, packageName); + } + } catch (NameNotFoundException e) { + // forget you + } } } - mBlockedPackages.clear(); + for (Entry ban : packageBans.entrySet()) { + mRankingHelper.setImportance(ban.getValue(), ban.getKey(), IMPORTANCE_NONE); + } + + savePolicyFile(); } @Override @@ -1261,6 +1259,8 @@ public class NotificationManagerService extends SystemService { checkCallerIsSystem(); setNotificationsEnabledForPackageImpl(pkg, uid, enabled); + mRankingHelper.setEnabled(pkg, uid, enabled); + savePolicyFile(); } /** @@ -2034,21 +2034,8 @@ public class NotificationManagerService extends SystemService { JSONObject dump = new JSONObject(); try { dump.put("service", "Notification Manager"); - JSONArray bans = new JSONArray(); - try { - ArrayMap> packageBans = getPackageBans(filter); - for (Integer userId : packageBans.keySet()) { - for (String packageName : packageBans.get(userId)) { - JSONObject ban = new JSONObject(); - ban.put("userId", userId); - ban.put("packageName", packageName); - bans.put(ban); - } - } - } catch (NameNotFoundException e) { - // pass - } - dump.put("bans", bans); + dump.put("bans", mRankingHelper.dumpBansJson(filter)); + dump.put("ranking", mRankingHelper.dumpJson(filter)); dump.put("stats", mUsageStats.dumpJson(filter)); } catch (JSONException e) { e.printStackTrace(); @@ -2175,47 +2162,9 @@ public class NotificationManagerService extends SystemService { r.dump(pw, " ", getContext(), filter.redact); } } - - try { - pw.println("\n Banned Packages:"); - ArrayMap> packageBans = getPackageBans(filter); - for (Integer userId : packageBans.keySet()) { - for (String packageName : packageBans.get(userId)) { - pw.println(" " + userId + ": " + packageName); - } - } - } catch (NameNotFoundException e) { - // pass - } } } - private ArrayMap> getPackageBans(DumpFilter filter) - throws NameNotFoundException { - ArrayMap> packageBans = new ArrayMap<>(); - ArrayList packageNames = new ArrayList<>(); - for (UserInfo user : UserManager.get(getContext()).getUsers()) { - final int userId = user.getUserHandle().getIdentifier(); - final PackageManager packageManager = getContext().getPackageManager(); - List packages = packageManager.getInstalledPackagesAsUser(0, userId); - final int packageCount = packages.size(); - for (int p = 0; p < packageCount; p++) { - final String packageName = packages.get(p).packageName; - if (filter == null || filter.matches(packageName)) { - final int uid = packageManager.getPackageUidAsUser(packageName, userId); - if (!checkNotificationOp(packageName, uid)) { - packageNames.add(packageName); - } - } - } - if (!packageNames.isEmpty()) { - packageBans.put(userId, packageNames); - packageNames = new ArrayList<>(); - } - } - return packageBans; - } - /** * The private API only accessible to the system process. */ diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java index fd96a784122f1..4a41705ea321c 100644 --- a/services/core/java/com/android/server/notification/RankingHelper.java +++ b/services/core/java/com/android/server/notification/RankingHelper.java @@ -25,6 +25,11 @@ import android.text.TextUtils; import android.util.ArrayMap; import android.util.Slog; +import com.android.server.notification.NotificationManagerService.DumpFilter; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; @@ -33,6 +38,8 @@ import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collections; +import java.util.Map; +import java.util.Map.Entry; public class RankingHelper implements RankingConfig { private static final String TAG = "RankingHelper"; @@ -358,6 +365,14 @@ public class RankingHelper implements RankingConfig { updateConfig(); } + public void setEnabled(String packageName, int uid, boolean enabled) { + boolean wasEnabled = getImportance(packageName, uid) != Ranking.IMPORTANCE_NONE; + if (wasEnabled == enabled) { + return; + } + setImportance(packageName, uid, enabled ? DEFAULT_IMPORTANCE : Ranking.IMPORTANCE_NONE); + } + public void dump(PrintWriter pw, String prefix, NotificationManagerService.DumpFilter filter) { if (filter == null) { final int N = mSignalExtractors.length; @@ -398,17 +413,97 @@ public class RankingHelper implements RankingConfig { } if (r.priority != DEFAULT_PRIORITY) { pw.print(" priority="); - pw.print(Ranking.importanceToString(r.priority)); + pw.print(Notification.priorityToString(r.priority)); } if (r.visibility != DEFAULT_VISIBILITY) { pw.print(" visibility="); - pw.print(Ranking.importanceToString(r.visibility)); + pw.print(Notification.visibilityToString(r.visibility)); } pw.println(); } } } + public JSONObject dumpJson(NotificationManagerService.DumpFilter filter) { + JSONObject ranking = new JSONObject(); + JSONArray records = new JSONArray(); + try { + ranking.put("noUid", mRestoredWithoutUids.size()); + } catch (JSONException e) { + // pass + } + final int N = mRecords.size(); + for (int i = 0; i < N; i++) { + final Record r = mRecords.valueAt(i); + if (filter == null || filter.matches(r.pkg)) { + JSONObject record = new JSONObject(); + try { + record.put("userId", UserHandle.getUserId(r.uid)); + record.put("packageName", r.pkg); + if (r.importance != DEFAULT_IMPORTANCE) { + record.put("importance", Ranking.importanceToString(r.importance)); + } + if (r.priority != DEFAULT_PRIORITY) { + record.put("priority", Notification.priorityToString(r.priority)); + } + if (r.visibility != DEFAULT_VISIBILITY) { + record.put("visibility", Notification.visibilityToString(r.visibility)); + } + } catch (JSONException e) { + // pass + } + records.put(record); + } + } + try { + ranking.put("records", records); + } catch (JSONException e) { + // pass + } + return ranking; + } + + /** + * Dump only the ban information as structured JSON for the stats collector. + * + * This is intentionally redundant with {#link dumpJson} because the old + * scraper will expect this format. + * + * @param filter + * @return + */ + public JSONArray dumpBansJson(NotificationManagerService.DumpFilter filter) { + JSONArray bans = new JSONArray(); + Map packageBans = getPackageBans(); + for(Entry ban : packageBans.entrySet()) { + final int userId = UserHandle.getUserId(ban.getKey()); + final String packageName = ban.getValue(); + if (filter == null || filter.matches(packageName)) { + JSONObject banJson = new JSONObject(); + try { + banJson.put("userId", userId); + banJson.put("packageName", packageName); + } catch (JSONException e) { + e.printStackTrace(); + } + bans.put(banJson); + } + } + return bans; + } + + public Map getPackageBans() { + final int N = mRecords.size(); + ArrayMap packageBans = new ArrayMap<>(N); + for (int i = 0; i < N; i++) { + final Record r = mRecords.valueAt(i); + if (r.importance == Ranking.IMPORTANCE_NONE) { + packageBans.put(r.uid, r.pkg); + } + } + return packageBans; + } + public void onPackagesChanged(boolean queryReplace, String[] pkgList) { if (queryReplace || pkgList == null || pkgList.length == 0 || mRestoredWithoutUids.isEmpty()) {