Loading services/core/java/com/android/server/notification/NotificationManagerService.java +81 −38 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -330,16 +335,10 @@ public class NotificationManagerService extends SystemService { } private void loadPolicyFile() { if (DBG) Slog.d(TAG, "loadPolicyFile"); synchronized(mPolicyFile) { mBlockedPackages.clear(); FileInputStream infile = null; try { infile = mPolicyFile.openRead(); private void readPolicyXml(InputStream stream, boolean forRestore) throws XmlPullParserException, NumberFormatException, IOException { final XmlPullParser parser = Xml.newPullParser(); parser.setInput(infile, StandardCharsets.UTF_8.name()); parser.setInput(stream, StandardCharsets.UTF_8.name()); int type; String tag; Loading @@ -362,9 +361,20 @@ public class NotificationManagerService extends SystemService { } } } mZenModeHelper.readXml(parser); mRankingHelper.readXml(parser); mZenModeHelper.readXml(parser, forRestore); mRankingHelper.readXml(parser, forRestore); } } private void loadPolicyFile() { if (DBG) Slog.d(TAG, "loadPolicyFile"); synchronized(mPolicyFile) { mBlockedPackages.clear(); FileInputStream infile = null; try { infile = mPolicyFile.openRead(); readPolicyXml(infile, false /*forRestore*/); } catch (FileNotFoundException e) { // No data yet } catch (IOException e) { Loading Loading @@ -396,21 +406,26 @@ public class NotificationManagerService extends SystemService { } try { 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); mRankingHelper.writeXml(out); mZenModeHelper.writeXml(out, forBackup); mRankingHelper.writeXml(out, forBackup); out.endTag(null, TAG_NOTIFICATION_POLICY); out.endDocument(); mPolicyFile.finishWrite(stream); } catch (IOException e) { Slog.w(TAG, "Failed to save policy file, restoring backup", e); mPolicyFile.failWrite(stream); } } } /** Use this when you actually want to post a notification or toast. Loading Loading @@ -722,6 +737,7 @@ public class NotificationManagerService extends SystemService { } mListeners.onPackagesChanged(queryReplace, pkgList); mConditionProviders.onPackagesChanged(queryReplace, pkgList); mRankingHelper.onPackagesChanged(queryReplace, pkgList); } } }; Loading Loading @@ -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 Loading services/core/java/com/android/server/notification/RankingHelper.java +73 −11 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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)) { Loading @@ -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; } } } Loading Loading @@ -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) { Loading @@ -200,7 +226,9 @@ public class RankingHelper implements RankingConfig { if (r.visibility != DEFAULT_VISIBILITY) { out.attribute(null, ATT_VISIBILITY, Integer.toString(r.visibility)); } if (!forBackup) { out.attribute(null, ATT_UID, Integer.toString(r.uid)); } out.endTag(null, TAG_PACKAGE); } out.endTag(null, TAG_RANKING); Loading Loading @@ -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="); Loading @@ -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; } } services/core/java/com/android/server/notification/ZenModeHelper.java +12 −2 Original line number Diff line number Diff line Loading @@ -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); } } Loading Loading
services/core/java/com/android/server/notification/NotificationManagerService.java +81 −38 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -330,16 +335,10 @@ public class NotificationManagerService extends SystemService { } private void loadPolicyFile() { if (DBG) Slog.d(TAG, "loadPolicyFile"); synchronized(mPolicyFile) { mBlockedPackages.clear(); FileInputStream infile = null; try { infile = mPolicyFile.openRead(); private void readPolicyXml(InputStream stream, boolean forRestore) throws XmlPullParserException, NumberFormatException, IOException { final XmlPullParser parser = Xml.newPullParser(); parser.setInput(infile, StandardCharsets.UTF_8.name()); parser.setInput(stream, StandardCharsets.UTF_8.name()); int type; String tag; Loading @@ -362,9 +361,20 @@ public class NotificationManagerService extends SystemService { } } } mZenModeHelper.readXml(parser); mRankingHelper.readXml(parser); mZenModeHelper.readXml(parser, forRestore); mRankingHelper.readXml(parser, forRestore); } } private void loadPolicyFile() { if (DBG) Slog.d(TAG, "loadPolicyFile"); synchronized(mPolicyFile) { mBlockedPackages.clear(); FileInputStream infile = null; try { infile = mPolicyFile.openRead(); readPolicyXml(infile, false /*forRestore*/); } catch (FileNotFoundException e) { // No data yet } catch (IOException e) { Loading Loading @@ -396,21 +406,26 @@ public class NotificationManagerService extends SystemService { } try { 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); mRankingHelper.writeXml(out); mZenModeHelper.writeXml(out, forBackup); mRankingHelper.writeXml(out, forBackup); out.endTag(null, TAG_NOTIFICATION_POLICY); out.endDocument(); mPolicyFile.finishWrite(stream); } catch (IOException e) { Slog.w(TAG, "Failed to save policy file, restoring backup", e); mPolicyFile.failWrite(stream); } } } /** Use this when you actually want to post a notification or toast. Loading Loading @@ -722,6 +737,7 @@ public class NotificationManagerService extends SystemService { } mListeners.onPackagesChanged(queryReplace, pkgList); mConditionProviders.onPackagesChanged(queryReplace, pkgList); mRankingHelper.onPackagesChanged(queryReplace, pkgList); } } }; Loading Loading @@ -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 Loading
services/core/java/com/android/server/notification/RankingHelper.java +73 −11 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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)) { Loading @@ -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; } } } Loading Loading @@ -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) { Loading @@ -200,7 +226,9 @@ public class RankingHelper implements RankingConfig { if (r.visibility != DEFAULT_VISIBILITY) { out.attribute(null, ATT_VISIBILITY, Integer.toString(r.visibility)); } if (!forBackup) { out.attribute(null, ATT_UID, Integer.toString(r.uid)); } out.endTag(null, TAG_PACKAGE); } out.endTag(null, TAG_RANKING); Loading Loading @@ -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="); Loading @@ -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; } }
services/core/java/com/android/server/notification/ZenModeHelper.java +12 −2 Original line number Diff line number Diff line Loading @@ -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); } } Loading