summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java119
-rw-r--r--services/core/java/com/android/server/notification/RankingHelper.java84
-rw-r--r--services/core/java/com/android/server/notification/ZenModeHelper.java14
3 files changed, 166 insertions, 51 deletions
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 3300cdb..2d15d13 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -36,6 +36,7 @@ import android.app.NotificationManager;
import android.app.NotificationManager.Policy;
import android.app.PendingIntent;
import android.app.StatusBarManager;
+import android.app.backup.BackupManager;
import android.app.usage.UsageEvents;
import android.app.usage.UsageStatsManagerInternal;
import android.content.BroadcastReceiver;
@@ -113,12 +114,16 @@ import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.ArrayDeque;
@@ -330,6 +335,37 @@ public class NotificationManagerService extends SystemService {
}
+ private void readPolicyXml(InputStream stream, boolean forRestore)
+ throws XmlPullParserException, NumberFormatException, IOException {
+ 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;
+ }
+ }
+ }
+ }
+ mZenModeHelper.readXml(parser, forRestore);
+ mRankingHelper.readXml(parser, forRestore);
+ }
+ }
+
private void loadPolicyFile() {
if (DBG) Slog.d(TAG, "loadPolicyFile");
synchronized(mPolicyFile) {
@@ -338,33 +374,7 @@ public class NotificationManagerService extends SystemService {
FileInputStream infile = null;
try {
infile = mPolicyFile.openRead();
- final XmlPullParser parser = Xml.newPullParser();
- parser.setInput(infile, 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;
- }
- }
- }
- }
- mZenModeHelper.readXml(parser);
- mRankingHelper.readXml(parser);
- }
+ readPolicyXml(infile, false /*forRestore*/);
} catch (FileNotFoundException e) {
// No data yet
} catch (IOException e) {
@@ -396,21 +406,26 @@ public class NotificationManagerService extends SystemService {
}
try {
- final XmlSerializer out = new FastXmlSerializer();
- out.setOutput(stream, StandardCharsets.UTF_8.name());
- out.startDocument(null, true);
- out.startTag(null, TAG_NOTIFICATION_POLICY);
- out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION));
- mZenModeHelper.writeXml(out);
- mRankingHelper.writeXml(out);
- out.endTag(null, TAG_NOTIFICATION_POLICY);
- out.endDocument();
+ writePolicyXml(stream, false /*forBackup*/);
mPolicyFile.finishWrite(stream);
} catch (IOException e) {
Slog.w(TAG, "Failed to save policy file, restoring backup", e);
mPolicyFile.failWrite(stream);
}
}
+ BackupManager.dataChanged(getContext().getPackageName());
+ }
+
+ private void writePolicyXml(OutputStream stream, boolean forBackup) throws IOException {
+ final XmlSerializer out = new FastXmlSerializer();
+ out.setOutput(stream, StandardCharsets.UTF_8.name());
+ out.startDocument(null, true);
+ out.startTag(null, TAG_NOTIFICATION_POLICY);
+ out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION));
+ mZenModeHelper.writeXml(out, forBackup);
+ mRankingHelper.writeXml(out, forBackup);
+ out.endTag(null, TAG_NOTIFICATION_POLICY);
+ out.endDocument();
}
/** Use this when you actually want to post a notification or toast.
@@ -722,6 +737,7 @@ public class NotificationManagerService extends SystemService {
}
mListeners.onPackagesChanged(queryReplace, pkgList);
mConditionProviders.onPackagesChanged(queryReplace, pkgList);
+ mRankingHelper.onPackagesChanged(queryReplace, pkgList);
}
}
};
@@ -1671,13 +1687,40 @@ public class NotificationManagerService extends SystemService {
// Backup/restore interface
@Override
public byte[] getBackupPayload(int user) {
- // TODO: build a payload of whatever is appropriate
+ if (DBG) Slog.d(TAG, "getBackupPayload u=" + user);
+ if (user != UserHandle.USER_OWNER) {
+ Slog.w(TAG, "getBackupPayload: cannot backup policy for user " + user);
+ return null;
+ }
+ final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ try {
+ writePolicyXml(baos, true /*forBackup*/);
+ return baos.toByteArray();
+ } catch (IOException e) {
+ Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
+ }
return null;
}
@Override
public void applyRestore(byte[] payload, int user) {
- // TODO: apply the restored payload as new current state
+ if (DBG) Slog.d(TAG, "applyRestore u=" + user + " payload="
+ + (payload != null ? new String(payload, StandardCharsets.UTF_8) : null));
+ if (payload == null) {
+ Slog.w(TAG, "applyRestore: no payload to restore for user " + user);
+ return;
+ }
+ if (user != UserHandle.USER_OWNER) {
+ Slog.w(TAG, "applyRestore: cannot restore policy for user " + user);
+ return;
+ }
+ final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
+ try {
+ readPolicyXml(bais, true /*forRestore*/);
+ savePolicyFile();
+ } catch (NumberFormatException | XmlPullParserException | IOException e) {
+ Slog.w(TAG, "applyRestore: error reading payload", e);
+ }
}
@Override
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index 88055ba..e503ac8 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -17,6 +17,8 @@ package com.android.server.notification;
import android.app.Notification;
import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Handler;
import android.os.Message;
import android.os.UserHandle;
@@ -61,6 +63,7 @@ public class RankingHelper implements RankingConfig {
private final ArrayMap<String, Record> mRecords = new ArrayMap<>(); // pkg|uid => Record
private final ArrayMap<String, NotificationRecord> mProxyByGroupTmp = new ArrayMap<>();
+ private final ArrayMap<String, Record> mRestoredWithoutUids = new ArrayMap<>(); // pkg => Record
private final Context mContext;
private final Handler mRankingHandler;
@@ -119,12 +122,15 @@ public class RankingHelper implements RankingConfig {
}
}
- public void readXml(XmlPullParser parser) throws XmlPullParserException, IOException {
+ public void readXml(XmlPullParser parser, boolean forRestore)
+ throws XmlPullParserException, IOException {
+ final PackageManager pm = mContext.getPackageManager();
int type = parser.getEventType();
if (type != XmlPullParser.START_TAG) return;
String tag = parser.getName();
if (!TAG_RANKING.equals(tag)) return;
mRecords.clear();
+ mRestoredWithoutUids.clear();
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
tag = parser.getName();
if (type == XmlPullParser.END_TAG && TAG_RANKING.equals(tag)) {
@@ -132,21 +138,38 @@ public class RankingHelper implements RankingConfig {
}
if (type == XmlPullParser.START_TAG) {
if (TAG_PACKAGE.equals(tag)) {
- int uid = safeInt(parser, ATT_UID, UserHandle.USER_ALL);
+ int uid = safeInt(parser, ATT_UID, Record.UNKNOWN_UID);
int priority = safeInt(parser, ATT_PRIORITY, DEFAULT_PRIORITY);
boolean peekable = safeBool(parser, ATT_PEEKABLE, DEFAULT_PEEKABLE);
int vis = safeInt(parser, ATT_VISIBILITY, DEFAULT_VISIBILITY);
String name = parser.getAttributeValue(null, ATT_NAME);
if (!TextUtils.isEmpty(name)) {
+ if (forRestore) {
+ try {
+ uid = pm.getPackageUid(name, UserHandle.USER_OWNER);
+ } catch (NameNotFoundException e) {
+ // noop
+ }
+ }
+ Record r = null;
+ if (uid == Record.UNKNOWN_UID) {
+ r = mRestoredWithoutUids.get(name);
+ if (r == null) {
+ r = new Record();
+ mRestoredWithoutUids.put(name, r);
+ }
+ } else {
+ r = getOrCreateRecord(name, uid);
+ }
if (priority != DEFAULT_PRIORITY) {
- getOrCreateRecord(name, uid).priority = priority;
+ r.priority = priority;
}
if (peekable != DEFAULT_PEEKABLE) {
- getOrCreateRecord(name, uid).peekable = peekable;
+ r.peekable = peekable;
}
if (vis != DEFAULT_VISIBILITY) {
- getOrCreateRecord(name, uid).visibility = vis;
+ r.visibility = vis;
}
}
}
@@ -182,13 +205,16 @@ public class RankingHelper implements RankingConfig {
}
}
- public void writeXml(XmlSerializer out) throws IOException {
+ public void writeXml(XmlSerializer out, boolean forBackup) throws IOException {
out.startTag(null, TAG_RANKING);
out.attribute(null, ATT_VERSION, Integer.toString(XML_VERSION));
final int N = mRecords.size();
for (int i = 0; i < N; i++) {
final Record r = mRecords.valueAt(i);
+ if (forBackup && UserHandle.getUserId(r.uid) != UserHandle.USER_OWNER) {
+ continue;
+ }
out.startTag(null, TAG_PACKAGE);
out.attribute(null, ATT_NAME, r.pkg);
if (r.priority != DEFAULT_PRIORITY) {
@@ -200,7 +226,9 @@ public class RankingHelper implements RankingConfig {
if (r.visibility != DEFAULT_VISIBILITY) {
out.attribute(null, ATT_VISIBILITY, Integer.toString(r.visibility));
}
- out.attribute(null, ATT_UID, Integer.toString(r.uid));
+ if (!forBackup) {
+ out.attribute(null, ATT_UID, Integer.toString(r.uid));
+ }
out.endTag(null, TAG_PACKAGE);
}
out.endTag(null, TAG_RANKING);
@@ -364,15 +392,21 @@ public class RankingHelper implements RankingConfig {
pw.print(prefix);
pw.println("per-package config:");
}
- final int N = mRecords.size();
+ dumpRecords(pw, prefix, filter, mRecords);
+ dumpRecords(pw, prefix, filter, mRestoredWithoutUids);
+ }
+
+ private static void dumpRecords(PrintWriter pw, String prefix,
+ NotificationManagerService.DumpFilter filter, ArrayMap<String, Record> records) {
+ final int N = records.size();
for (int i = 0; i < N; i++) {
- final Record r = mRecords.valueAt(i);
+ final Record r = records.valueAt(i);
if (filter == null || filter.matches(r.pkg)) {
pw.print(prefix);
pw.print(" ");
pw.print(r.pkg);
pw.print(" (");
- pw.print(r.uid);
+ pw.print(r.uid == Record.UNKNOWN_UID ? "UNKNOWN_UID" : Integer.toString(r.uid));
pw.print(')');
if (r.priority != DEFAULT_PRIORITY) {
pw.print(" priority=");
@@ -391,11 +425,39 @@ public class RankingHelper implements RankingConfig {
}
}
+ public void onPackagesChanged(boolean queryReplace, String[] pkgList) {
+ if (queryReplace || pkgList == null || pkgList.length == 0
+ || mRestoredWithoutUids.isEmpty()) {
+ return; // nothing to do
+ }
+ final PackageManager pm = mContext.getPackageManager();
+ boolean updated = false;
+ for (String pkg : pkgList) {
+ final Record r = mRestoredWithoutUids.get(pkg);
+ if (r != null) {
+ try {
+ r.uid = pm.getPackageUid(r.pkg, UserHandle.USER_OWNER);
+ mRestoredWithoutUids.remove(pkg);
+ mRecords.put(recordKey(r.pkg, r.uid), r);
+ updated = true;
+ } catch (NameNotFoundException e) {
+ // noop
+ }
+ }
+ }
+ if (updated) {
+ updateConfig();
+ }
+ }
+
private static class Record {
+ static int UNKNOWN_UID = UserHandle.USER_NULL;
+
String pkg;
- int uid;
+ int uid = UNKNOWN_UID;
int priority = DEFAULT_PRIORITY;
boolean peekable = DEFAULT_PEEKABLE;
int visibility = DEFAULT_VISIBILITY;
}
+
}
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 702c194..755b2ea 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -256,17 +256,27 @@ public class ZenModeHelper {
}
}
- public void readXml(XmlPullParser parser) throws XmlPullParserException, IOException {
+ public void readXml(XmlPullParser parser, boolean forRestore)
+ throws XmlPullParserException, IOException {
final ZenModeConfig config = ZenModeConfig.readXml(parser, mConfigMigration);
if (config != null) {
+ if (forRestore) {
+ if (config.user != UserHandle.USER_OWNER) {
+ return;
+ }
+ config.manualRule = null; // don't restore the manual rule
+ }
if (DEBUG) Log.d(TAG, "readXml");
setConfig(config, "readXml");
}
}
- public void writeXml(XmlSerializer out) throws IOException {
+ public void writeXml(XmlSerializer out, boolean forBackup) throws IOException {
final int N = mConfigs.size();
for (int i = 0; i < N; i++) {
+ if (forBackup && mConfigs.keyAt(i) != UserHandle.USER_OWNER) {
+ continue;
+ }
mConfigs.valueAt(i).writeXml(out);
}
}