Stop double-loading device admins

loadSettingsLocked() was being called twice for USER_OWNER at
systemReady(), doubling the number of admin entries at every boot.

Also guards against double-adding admins which appear twice in the
same XML file, favouring more recently-refreshed entries for
backward compatibility.

Previously an application calling in with 'refreshing = true' would
double-insert whatever admin was being refreshed into its user's list
of device admins. This is fixed too.

@bug 16416936

Change-Id: Idd147aa130e6bce7bcc40532f0a7fb07117b3151
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 2a11252..5f876ff 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -1103,6 +1103,8 @@
             type = parser.next();
             int outerDepth = parser.getDepth();
             policy.mLockTaskPackages.clear();
+            policy.mAdminList.clear();
+            policy.mAdminMap.clear();
             while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
                    && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
                 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
@@ -1124,7 +1126,6 @@
                             ActiveAdmin ap = new ActiveAdmin(dai);
                             ap.readFromXml(parser);
                             policy.mAdminMap.put(ap.info.getComponent(), ap);
-                            policy.mAdminList.add(ap);
                         }
                     } catch (RuntimeException e) {
                         Slog.w(LOG_TAG, "Failed loading admin " + name, e);
@@ -1184,6 +1185,9 @@
             // Ignore
         }
 
+        // Generate a list of admins from the admin map
+        policy.mAdminList.addAll(policy.mAdminMap.values());
+
         // Validate that what we stored for the password quality matches
         // sufficiently what is currently set.  Note that this is only
         // a sanity check in case the two get out of sync; this should
@@ -1268,10 +1272,8 @@
         if (!mHasFeature) {
             return;
         }
-        synchronized (this) {
-            loadSettingsLocked(getUserData(UserHandle.USER_OWNER), UserHandle.USER_OWNER);
-            loadDeviceOwner();
-        }
+        getUserData(UserHandle.USER_OWNER);
+        loadDeviceOwner();
         cleanUpOldUsers();
         mAppOpsService = IAppOpsService.Stub.asInterface(
                 ServiceManager.getService(Context.APP_OPS_SERVICE));
@@ -1436,14 +1438,12 @@
                 ActiveAdmin newAdmin = new ActiveAdmin(info);
                 policy.mAdminMap.put(adminReceiver, newAdmin);
                 int replaceIndex = -1;
-                if (refreshing) {
-                    final int N = policy.mAdminList.size();
-                    for (int i=0; i < N; i++) {
-                        ActiveAdmin oldAdmin = policy.mAdminList.get(i);
-                        if (oldAdmin.info.getComponent().equals(adminReceiver)) {
-                            replaceIndex = i;
-                            break;
-                        }
+                final int N = policy.mAdminList.size();
+                for (int i=0; i < N; i++) {
+                    ActiveAdmin oldAdmin = policy.mAdminList.get(i);
+                    if (oldAdmin.info.getComponent().equals(adminReceiver)) {
+                        replaceIndex = i;
+                        break;
                     }
                 }
                 if (replaceIndex == -1) {