Support B&R of notifications in non-system users
- Only backup and restore global state for the system user.
- Ignore user id in data for restore (as user 0 on source device could
be restoring to user 10 on target device for example).
- Don't restore managed services for managed users.
Bug: 123349308
Test: 1) atest $(find \
frameworks/base/services/tests/uiservicestests/src/com/android/server/notification \
-name '*Test.java')
2) Manual: Test backup and restore of DND configurations and app
notifications in system and non-system user.
TODO: More testing
Change-Id: Iea2933f2d8709f830a65815871ce974c00f6ce83
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index c222e69..cf09b8f 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -306,18 +306,21 @@
}
}
- public void writeXml(XmlSerializer out, boolean forBackup) throws IOException {
+ public void writeXml(XmlSerializer out, boolean forBackup, int userId) throws IOException {
out.startTag(null, getConfig().xmlTag);
out.attribute(null, ATT_VERSION, String.valueOf(DB_VERSION));
if (forBackup) {
- trimApprovedListsAccordingToInstalledServices();
+ trimApprovedListsAccordingToInstalledServices(userId);
}
final int N = mApproved.size();
for (int i = 0 ; i < N; i++) {
- final int userId = mApproved.keyAt(i);
+ final int approvedUserId = mApproved.keyAt(i);
+ if (forBackup && approvedUserId != userId) {
+ continue;
+ }
final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.valueAt(i);
if (approvedByType != null) {
final int M = approvedByType.size();
@@ -328,14 +331,14 @@
String allowedItems = String.join(ENABLED_SERVICES_SEPARATOR, approved);
out.startTag(null, TAG_MANAGED_SERVICES);
out.attribute(null, ATT_APPROVED_LIST, allowedItems);
- out.attribute(null, ATT_USER_ID, Integer.toString(userId));
+ out.attribute(null, ATT_USER_ID, Integer.toString(approvedUserId));
out.attribute(null, ATT_IS_PRIMARY, Boolean.toString(isPrimary));
out.endTag(null, TAG_MANAGED_SERVICES);
if (!forBackup && isPrimary) {
// Also write values to settings, for observers who haven't migrated yet
Settings.Secure.putStringForUser(mContext.getContentResolver(),
- getConfig().secureSettingName, allowedItems, userId);
+ getConfig().secureSettingName, allowedItems, approvedUserId);
}
}
@@ -350,15 +353,12 @@
loadAllowedComponentsFromSettings();
}
- public void readXml(XmlPullParser parser, Predicate<String> allowedManagedServicePackages)
+ public void readXml(
+ XmlPullParser parser,
+ Predicate<String> allowedManagedServicePackages,
+ boolean forRestore,
+ int userId)
throws XmlPullParserException, IOException {
- // upgrade xml
- int xmlVersion = XmlUtils.readIntAttribute(parser, ATT_VERSION, 0);
- final List<UserInfo> activeUsers = mUm.getUsers(true);
- for (UserInfo userInfo : activeUsers) {
- upgradeXml(xmlVersion, userInfo.getUserHandle().getIdentifier());
- }
-
// read grants
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
@@ -372,14 +372,16 @@
Slog.i(TAG, "Read " + mConfig.caption + " permissions from xml");
final String approved = XmlUtils.readStringAttribute(parser, ATT_APPROVED_LIST);
- final int userId = XmlUtils.readIntAttribute(parser, ATT_USER_ID, 0);
+ // Ignore parser's user id for restore.
+ final int resolvedUserId = forRestore
+ ? userId : XmlUtils.readIntAttribute(parser, ATT_USER_ID, 0);
final boolean isPrimary =
XmlUtils.readBooleanAttribute(parser, ATT_IS_PRIMARY, true);
if (allowedManagedServicePackages == null ||
allowedManagedServicePackages.test(getPackageName(approved))) {
- if (mUm.getUserInfo(userId) != null) {
- addApprovedList(approved, userId, isPrimary);
+ if (mUm.getUserInfo(resolvedUserId) != null) {
+ addApprovedList(approved, resolvedUserId, isPrimary);
}
mUseXml = true;
}
@@ -389,8 +391,6 @@
rebindServices(false, USER_ALL);
}
- protected void upgradeXml(final int xmlVersion, final int userId) {}
-
private void loadAllowedComponentsFromSettings() {
for (UserInfo user : mUm.getUsers()) {
final ContentResolver cr = mContext.getContentResolver();
@@ -784,26 +784,23 @@
return allowedPackages;
}
- private void trimApprovedListsAccordingToInstalledServices() {
- int N = mApproved.size();
- for (int i = 0 ; i < N; i++) {
- final int userId = mApproved.keyAt(i);
- final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.valueAt(i);
- int M = approvedByType.size();
- for (int j = 0; j < M; j++) {
- final ArraySet<String> approved = approvedByType.valueAt(j);
- int P = approved.size();
- for (int k = P - 1; k >= 0; k--) {
- final String approvedPackageOrComponent = approved.valueAt(k);
- if (!isValidEntry(approvedPackageOrComponent, userId)){
- approved.removeAt(k);
- Slog.v(TAG, "Removing " + approvedPackageOrComponent
- + " from approved list; no matching services found");
- } else {
- if (DEBUG) {
- Slog.v(TAG, "Keeping " + approvedPackageOrComponent
- + " on approved list; matching services found");
- }
+ private void trimApprovedListsAccordingToInstalledServices(int userId) {
+ final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(userId);
+ if (approvedByType == null) {
+ return;
+ }
+ for (int i = 0; i < approvedByType.size(); i++) {
+ final ArraySet<String> approved = approvedByType.valueAt(i);
+ for (int j = approved.size() - 1; j >= 0; j--) {
+ final String approvedPackageOrComponent = approved.valueAt(j);
+ if (!isValidEntry(approvedPackageOrComponent, userId)){
+ approved.removeAt(j);
+ Slog.v(TAG, "Removing " + approvedPackageOrComponent
+ + " from approved list; no matching services found");
+ } else {
+ if (DEBUG) {
+ Slog.v(TAG, "Keeping " + approvedPackageOrComponent
+ + " on approved list; matching services found");
}
}
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index ba187c0..34d3681 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -213,6 +213,7 @@
import com.android.server.notification.ManagedServices.ManagedServiceInfo;
import com.android.server.notification.ManagedServices.UserProfiles;
import com.android.server.pm.PackageManagerService;
+import com.android.server.pm.UserManagerService;
import com.android.server.policy.PhoneWindowManager;
import com.android.server.statusbar.StatusBarManagerInternal;
import com.android.server.uri.UriGrantsManagerInternal;
@@ -538,30 +539,49 @@
}
}
- void readPolicyXml(InputStream stream, boolean forRestore)
+ UserManagerService getUserManagerService() {
+ return UserManagerService.getInstance();
+ }
+
+ void readPolicyXml(InputStream stream, boolean forRestore, int userId)
throws XmlPullParserException, NumberFormatException, IOException {
final XmlPullParser parser = Xml.newPullParser();
parser.setInput(stream, StandardCharsets.UTF_8.name());
XmlUtils.beginDocument(parser, TAG_NOTIFICATION_POLICY);
boolean migratedManagedServices = false;
+ boolean ineligibleForManagedServices = forRestore
+ && getUserManagerService().isManagedProfile(userId);
int outerDepth = parser.getDepth();
while (XmlUtils.nextElementWithin(parser, outerDepth)) {
if (ZenModeConfig.ZEN_TAG.equals(parser.getName())) {
- mZenModeHelper.readXml(parser, forRestore);
+ mZenModeHelper.readXml(parser, forRestore, userId);
} else if (PreferencesHelper.TAG_RANKING.equals(parser.getName())){
- mPreferencesHelper.readXml(parser, forRestore);
+ mPreferencesHelper.readXml(parser, forRestore, userId);
}
if (mListeners.getConfig().xmlTag.equals(parser.getName())) {
- mListeners.readXml(parser, mAllowedManagedServicePackages);
+ if (ineligibleForManagedServices) {
+ continue;
+ }
+ mListeners.readXml(parser, mAllowedManagedServicePackages, forRestore, userId);
migratedManagedServices = true;
} else if (mAssistants.getConfig().xmlTag.equals(parser.getName())) {
- mAssistants.readXml(parser, mAllowedManagedServicePackages);
+ if (ineligibleForManagedServices) {
+ continue;
+ }
+ mAssistants.readXml(parser, mAllowedManagedServicePackages, forRestore, userId);
migratedManagedServices = true;
} else if (mConditionProviders.getConfig().xmlTag.equals(parser.getName())) {
- mConditionProviders.readXml(parser, mAllowedManagedServicePackages);
+ if (ineligibleForManagedServices) {
+ continue;
+ }
+ mConditionProviders.readXml(
+ parser, mAllowedManagedServicePackages, forRestore, userId);
migratedManagedServices = true;
}
if (LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG.equals(parser.getName())) {
+ if (forRestore && userId != UserHandle.USER_SYSTEM) {
+ continue;
+ }
mLockScreenAllowSecureNotifications =
safeBoolean(parser.getAttributeValue(null,
LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_VALUE), true);
@@ -584,7 +604,7 @@
InputStream infile = null;
try {
infile = mPolicyFile.openRead();
- readPolicyXml(infile, false /*forRestore*/);
+ readPolicyXml(infile, false /*forRestore*/, UserHandle.USER_ALL);
} catch (FileNotFoundException e) {
// No data yet
// Load default managed services approvals
@@ -615,7 +635,7 @@
}
try {
- writePolicyXml(stream, false /*forBackup*/);
+ writePolicyXml(stream, false /*forBackup*/, UserHandle.USER_ALL);
mPolicyFile.finishWrite(stream);
} catch (IOException e) {
Slog.w(TAG, "Failed to save policy file, restoring backup", e);
@@ -626,18 +646,21 @@
});
}
- private void writePolicyXml(OutputStream stream, boolean forBackup) throws IOException {
+ private void writePolicyXml(OutputStream stream, boolean forBackup, int userId)
+ 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, null);
- mPreferencesHelper.writeXml(out, forBackup);
- mListeners.writeXml(out, forBackup);
- mAssistants.writeXml(out, forBackup);
- mConditionProviders.writeXml(out, forBackup);
- writeSecureNotificationsPolicy(out);
+ mZenModeHelper.writeXml(out, forBackup, null, userId);
+ mPreferencesHelper.writeXml(out, forBackup, userId);
+ mListeners.writeXml(out, forBackup, userId);
+ mAssistants.writeXml(out, forBackup, userId);
+ mConditionProviders.writeXml(out, forBackup, userId);
+ if (!forBackup || userId == UserHandle.USER_SYSTEM) {
+ writeSecureNotificationsPolicy(out);
+ }
out.endTag(null, TAG_NOTIFICATION_POLICY);
out.endDocument();
}
@@ -3497,14 +3520,9 @@
public byte[] getBackupPayload(int user) {
checkCallerIsSystem();
if (DBG) Slog.d(TAG, "getBackupPayload u=" + user);
- //TODO: http://b/22388012
- if (user != USER_SYSTEM) {
- Slog.w(TAG, "getBackupPayload: cannot backup policy for user " + user);
- return null;
- }
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
- writePolicyXml(baos, true /*forBackup*/);
+ writePolicyXml(baos, true /*forBackup*/, user);
return baos.toByteArray();
} catch (IOException e) {
Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
@@ -3521,14 +3539,9 @@
Slog.w(TAG, "applyRestore: no payload to restore for user " + user);
return;
}
- //TODO: http://b/22388012
- if (user != USER_SYSTEM) {
- Slog.w(TAG, "applyRestore: cannot restore policy for user " + user);
- return;
- }
final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
try {
- readPolicyXml(bais, true /*forRestore*/);
+ readPolicyXml(bais, true /*forRestore*/, user);
handleSavePolicyFile();
} catch (NumberFormatException | XmlPullParserException | IOException e) {
Slog.w(TAG, "applyRestore: error reading payload", e);
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 6ed4f5c..5555936 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -141,7 +141,7 @@
syncChannelsBypassingDnd(mContext.getUserId());
}
- public void readXml(XmlPullParser parser, boolean forRestore)
+ public void readXml(XmlPullParser parser, boolean forRestore, int userId)
throws XmlPullParserException, IOException {
int type = parser.getEventType();
if (type != XmlPullParser.START_TAG) return;
@@ -158,6 +158,9 @@
}
if (type == XmlPullParser.START_TAG) {
if (TAG_STATUS_ICONS.equals(tag)) {
+ if (forRestore && userId != UserHandle.USER_SYSTEM) {
+ continue;
+ }
mHideSilentStatusBarIcons = XmlUtils.readBooleanAttribute(
parser, ATT_HIDE_SILENT, DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS);
} else if (TAG_PACKAGE.equals(tag)) {
@@ -166,9 +169,7 @@
if (!TextUtils.isEmpty(name)) {
if (forRestore) {
try {
- //TODO: http://b/22388012
- uid = mPm.getPackageUidAsUser(name,
- UserHandle.USER_SYSTEM);
+ uid = mPm.getPackageUidAsUser(name, userId);
} catch (PackageManager.NameNotFoundException e) {
// noop
}
@@ -379,10 +380,11 @@
r.channels.put(channel.getId(), channel);
}
- public void writeXml(XmlSerializer out, boolean forBackup) throws IOException {
+ public void writeXml(XmlSerializer out, boolean forBackup, int userId) throws IOException {
out.startTag(null, TAG_RANKING);
out.attribute(null, ATT_VERSION, Integer.toString(XML_VERSION));
- if (mHideSilentStatusBarIcons != DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS) {
+ if (mHideSilentStatusBarIcons != DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS
+ && (!forBackup || userId == UserHandle.USER_SYSTEM)) {
out.startTag(null, TAG_STATUS_ICONS);
out.attribute(null, ATT_HIDE_SILENT, String.valueOf(mHideSilentStatusBarIcons));
out.endTag(null, TAG_STATUS_ICONS);
@@ -392,8 +394,7 @@
final int N = mPackagePreferences.size();
for (int i = 0; i < N; i++) {
final PackagePreferences r = mPackagePreferences.valueAt(i);
- //TODO: http://b/22388012
- if (forBackup && UserHandle.getUserId(r.uid) != UserHandle.USER_SYSTEM) {
+ if (forBackup && UserHandle.getUserId(r.uid) != userId) {
continue;
}
final boolean hasNonDefaultSettings =
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index afc0b72..ea7bf2d2 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -104,7 +104,7 @@
protected final RingerModeDelegate mRingerModeDelegate = new
RingerModeDelegate();
@VisibleForTesting protected final ZenModeConditions mConditions;
- private final SparseArray<ZenModeConfig> mConfigs = new SparseArray<>();
+ @VisibleForTesting final SparseArray<ZenModeConfig> mConfigs = new SparseArray<>();
private final Metrics mMetrics = new Metrics();
private final ConditionProviders.Config mServiceConfig;
@@ -662,17 +662,14 @@
}
}
- public void readXml(XmlPullParser parser, boolean forRestore)
+ public void readXml(XmlPullParser parser, boolean forRestore, int userId)
throws XmlPullParserException, IOException {
ZenModeConfig config = ZenModeConfig.readXml(parser);
String reason = "readXml";
if (config != null) {
if (forRestore) {
- //TODO: http://b/22388012
- if (config.user != UserHandle.USER_SYSTEM) {
- return;
- }
+ config.user = userId;
config.manualRule = null; // don't restore the manual rule
}
@@ -707,13 +704,15 @@
reason += ", reset to default rules";
}
+ // Resolve user id for settings.
+ userId = userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId;
if (config.version < ZenModeConfig.XML_VERSION) {
- Settings.Secure.putInt(mContext.getContentResolver(),
- Settings.Secure.SHOW_ZEN_UPGRADE_NOTIFICATION, 1);
+ Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ Settings.Secure.SHOW_ZEN_UPGRADE_NOTIFICATION, 1, userId);
} else {
// devices not restoring/upgrading already have updated zen settings
- Settings.Secure.putInt(mContext.getContentResolver(),
- Settings.Secure.ZEN_SETTINGS_UPDATED, 1);
+ Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ Settings.Secure.ZEN_SETTINGS_UPDATED, 1, userId);
}
if (DEBUG) Log.d(TAG, reason);
synchronized (mConfig) {
@@ -722,11 +721,11 @@
}
}
- public void writeXml(XmlSerializer out, boolean forBackup, Integer version) throws IOException {
+ public void writeXml(XmlSerializer out, boolean forBackup, Integer version, int userId)
+ throws IOException {
final int N = mConfigs.size();
for (int i = 0; i < N; i++) {
- //TODO: http://b/22388012
- if (forBackup && mConfigs.keyAt(i) != UserHandle.USER_SYSTEM) {
+ if (forBackup && mConfigs.keyAt(i) != userId) {
continue;
}
mConfigs.valueAt(i).writeXml(out, version);