Fix default app notification locking on new devices

- Fresh devices, no restore, create app prefs if app hasn't done
it already
- Apply app level locking to channels created via readxml on restore

Test: atest, factory reset device and verify that default dialer app is
locked without requiring a reboot. restore backup and verify that it's
still locked
Fixes: 127855529

Change-Id: Ieca3e064eb5b5aa5877a4b575bf6223f62259668
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 9fc30eb..e2033c6 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -46,6 +46,7 @@
 import static android.content.Context.BIND_FOREGROUND_SERVICE;
 import static android.content.pm.PackageManager.FEATURE_LEANBACK;
 import static android.content.pm.PackageManager.FEATURE_TELEVISION;
+import static android.content.pm.PackageManager.MATCH_ALL;
 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
@@ -191,6 +192,7 @@
 import android.util.AtomicFile;
 import android.util.IntArray;
 import android.util.Log;
+import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.Xml;
@@ -1880,7 +1882,7 @@
             mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
             mZenModeHelper.onSystemReady();
             mRoleObserver = new RoleObserver(getContext().getSystemService(RoleManager.class),
-                    getContext().getMainExecutor());
+                    mPackageManager, getContext().getMainExecutor());
             mRoleObserver.init();
         } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
             // This observer will force an update when observe is called, causing us to
@@ -8219,11 +8221,14 @@
         private ArrayMap<String, ArrayMap<Integer, ArraySet<String>>> mNonBlockableDefaultApps;
 
         private final RoleManager mRm;
+        private final IPackageManager mPm;
         private final Executor mExecutor;
 
         RoleObserver(@NonNull RoleManager roleManager,
+                @NonNull IPackageManager pkgMgr,
                 @NonNull @CallbackExecutor Executor executor) {
             mRm = roleManager;
+            mPm = pkgMgr;
             mExecutor = executor;
         }
 
@@ -8237,8 +8242,12 @@
                     Integer userId = users.get(j).getUserHandle().getIdentifier();
                     ArraySet<String> approvedForUserId = new ArraySet<>(mRm.getRoleHoldersAsUser(
                             NON_BLOCKABLE_DEFAULT_ROLES[i], UserHandle.of(userId)));
+                    ArraySet<Pair<String, Integer>> approvedAppUids = new ArraySet<>();
+                    for (String pkg : approvedForUserId) {
+                        approvedAppUids.add(new Pair(pkg, getUidForPackage(pkg, userId)));
+                    }
                     userToApprovedList.put(userId, approvedForUserId);
-                    mPreferencesHelper.updateDefaultApps(userId, null, approvedForUserId);
+                    mPreferencesHelper.updateDefaultApps(userId, null, approvedAppUids);
                 }
             }
 
@@ -8281,7 +8290,7 @@
                     prevApprovedForRole.getOrDefault(user.getIdentifier(), new ArraySet<>());
 
             ArraySet<String> toRemove = new ArraySet<>();
-            ArraySet<String> toAdd = new ArraySet<>();
+            ArraySet<Pair<String, Integer>> toAdd = new ArraySet<>();
 
             for (String previous : previouslyApproved) {
                 if (!roleHolders.contains(previous)) {
@@ -8290,7 +8299,8 @@
             }
             for (String nowApproved : roleHolders) {
                 if (!previouslyApproved.contains(nowApproved)) {
-                    toAdd.add(nowApproved);
+                    toAdd.add(new Pair(nowApproved,
+                            getUidForPackage(nowApproved, user.getIdentifier())));
                 }
             }
 
@@ -8304,6 +8314,15 @@
             // RoleManager is the source of truth for this data so we don't need to trigger a
             // write of the notification policy xml for this change
         }
+
+        private int getUidForPackage(String pkg, int userId) {
+            try {
+                return mPm.getPackageUid(pkg, MATCH_ALL, userId);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "role manager has bad default " + pkg + " " + userId);
+            }
+            return -1;
+        }
     }
 
     public static final class DumpFilter {
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 9e16632..627b65c 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -38,6 +38,7 @@
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
+import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseBooleanArray;
 import android.util.proto.ProtoOutputStream;
@@ -236,6 +237,8 @@
                                         } else {
                                             channel.populateFromXml(parser);
                                         }
+                                        channel.setImportanceLockedByCriticalDeviceFunction(
+                                                r.defaultAppLockedImportance);
                                         r.channels.put(id, channel);
                                     }
                                 }
@@ -882,7 +885,8 @@
         }
     }
 
-    public void updateDefaultApps(int userId, ArraySet<String> toRemove, ArraySet<String> toAdd) {
+    public void updateDefaultApps(int userId, ArraySet<String> toRemove,
+            ArraySet<Pair<String, Integer>> toAdd) {
         synchronized (mPackagePreferences) {
             for (PackagePreferences p : mPackagePreferences.values()) {
                 if (userId == UserHandle.getUserId(p.uid)) {
@@ -891,11 +895,16 @@
                         for (NotificationChannel channel : p.channels.values()) {
                             channel.setImportanceLockedByCriticalDeviceFunction(false);
                         }
-                    } else if (toAdd != null && toAdd.contains(p.pkg)) {
-                        p.defaultAppLockedImportance = true;
-                        for (NotificationChannel channel : p.channels.values()) {
-                            channel.setImportanceLockedByCriticalDeviceFunction(true);
-                        }
+                    }
+                }
+            }
+            if (toAdd != null) {
+                for (Pair<String, Integer> approvedApp : toAdd) {
+                    PackagePreferences p = getOrCreatePackagePreferencesLocked(approvedApp.first,
+                            approvedApp.second);
+                    p.defaultAppLockedImportance = true;
+                    for (NotificationChannel channel : p.channels.values()) {
+                        channel.setImportanceLockedByCriticalDeviceFunction(true);
                     }
                 }
             }
@@ -1426,8 +1435,22 @@
                     pw.print(" visibility=");
                     pw.print(Notification.visibilityToString(r.visibility));
                 }
-                pw.print(" showBadge=");
-                pw.print(Boolean.toString(r.showBadge));
+                if (r.showBadge != DEFAULT_SHOW_BADGE) {
+                    pw.print(" showBadge=");
+                    pw.print(r.showBadge);
+                }
+                if (r.defaultAppLockedImportance != DEFAULT_APP_LOCKED_IMPORTANCE) {
+                    pw.print(" defaultAppLocked=");
+                    pw.print(r.defaultAppLockedImportance);
+                }
+                if (r.oemLockedImportance != DEFAULT_OEM_LOCKED_IMPORTANCE) {
+                    pw.print(" oemLocked=");
+                    pw.print(r.oemLockedImportance);
+                }
+                if (!r.futureOemLockedChannels.isEmpty()) {
+                    pw.print(" futureLockedChannels=");
+                    pw.print(r.futureOemLockedChannels);
+                }
                 pw.println();
                 for (NotificationChannel channel : r.channels.values()) {
                     pw.print(prefix);