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);