Make grant default permission more robust.

Change-Id: If492ee3305774419671bbdb72b438c8e540005e9
diff --git a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
index 3ea384c..d2b8783 100644
--- a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
@@ -403,6 +403,8 @@
                     }
                 }
             }
+
+            mService.mSettings.onDefaultRuntimePermissionsGrantedLPr(userId);
         }
     }
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 40ff3f4..97fb261 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -14023,6 +14023,8 @@
             Log.d(TAG, "compatibility mode:" + compatibilityModeEnabled);
         }
 
+        int[] grantPermissionsUserIds = EMPTY_INT_ARRAY;
+
         synchronized (mPackages) {
             // Verify that all of the preferred activity components actually
             // exist.  It is possible for applications to be updated and at
@@ -14052,15 +14054,19 @@
                             mSettings.mPreferredActivities.keyAt(i));
                 }
             }
+
+            for (int userId : UserManagerService.getInstance().getUserIds()) {
+                if (!mSettings.areDefaultRuntimePermissionsGrantedLPr(userId)) {
+                    grantPermissionsUserIds = ArrayUtils.appendInt(
+                            grantPermissionsUserIds, userId);
+                }
+            }
         }
         sUserManager.systemReady();
 
         // If we upgraded grant all default permissions before kicking off.
-        if (isFirstBoot() || (CLEAR_RUNTIME_PERMISSIONS_ON_UPGRADE && mIsUpgrade)) {
-            updatePermissionsLPw(null, null, UPDATE_PERMISSIONS_ALL);
-            for (int userId : UserManagerService.getInstance().getUserIds()) {
-                mDefaultPermissionPolicy.grantDefaultPermissions(userId);
-            }
+        for (int userId : grantPermissionsUserIds) {
+            mDefaultPermissionPolicy.grantDefaultPermissions(userId);
         }
 
         // Kick off any messages waiting for system ready
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index dcd7799..5814785 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -195,6 +195,7 @@
     private static final String ATTR_BLOCK_UNINSTALL = "blockUninstall";
     private static final String ATTR_DOMAIN_VERIFICATON_STATE = "domainVerificationStatus";
     private static final String ATTR_PACKAGE_NAME= "packageName";
+    private static final String ATTR_FINGERPRINT = "fingerprint";
 
     private final Object mLock;
 
@@ -1177,6 +1178,16 @@
         }
     }
 
+    boolean areDefaultRuntimePermissionsGrantedLPr(int userId) {
+        return mRuntimePermissionsPersistence
+                .areDefaultRuntimPermissionsGrantedLPr(userId);
+    }
+
+    void onDefaultRuntimePermissionsGrantedLPr(int userId) {
+        mRuntimePermissionsPersistence
+                .onDefaultRuntimePermissionsGrantedLPr(userId);
+    }
+
     /**
      * Returns whether the current database has is older than {@code version}
      * for apps on internal storage.
@@ -4334,15 +4345,33 @@
         private final Object mLock;
 
         @GuardedBy("mLock")
-        private SparseBooleanArray mWriteScheduled = new SparseBooleanArray();
+        private final SparseBooleanArray mWriteScheduled = new SparseBooleanArray();
 
         @GuardedBy("mLock")
-        private SparseLongArray mLastNotWrittenMutationTimesMillis = new SparseLongArray();
+        // The mapping keys are user ids.
+        private final SparseLongArray mLastNotWrittenMutationTimesMillis = new SparseLongArray();
+
+        @GuardedBy("mLock")
+        // The mapping keys are user ids.
+        private final SparseArray<String> mFingerprints = new SparseArray<>();
+
+        @GuardedBy("mLock")
+        // The mapping keys are user ids.
+        private final SparseBooleanArray mDefaultPermissionsGranted = new SparseBooleanArray();
 
         public RuntimePermissionPersistence(Object lock) {
             mLock = lock;
         }
 
+        public boolean areDefaultRuntimPermissionsGrantedLPr(int userId) {
+            return mDefaultPermissionsGranted.get(userId);
+        }
+
+        public void onDefaultRuntimePermissionsGrantedLPr(int userId) {
+            mFingerprints.put(userId, Build.FINGERPRINT);
+            writePermissionsForUserAsyncLPr(userId);
+        }
+
         public void writePermissionsForUserSyncLPr(int userId) {
             mHandler.removeMessages(userId);
             writePermissionsSync(userId);
@@ -4427,6 +4456,9 @@
                 serializer.startDocument(null, true);
                 serializer.startTag(null, TAG_RUNTIME_PERMISSIONS);
 
+                String fingerprint = mFingerprints.get(userId);
+                serializer.attribute(null, ATTR_FINGERPRINT, fingerprint);
+
                 final int packageCount = permissionsForPackage.size();
                 for (int i = 0; i < packageCount; i++) {
                     String packageName = permissionsForPackage.keyAt(i);
@@ -4451,7 +4483,10 @@
                 serializer.endDocument();
                 destination.finishWrite(out);
 
-                // Any error while writing is fatal.
+                if (Build.FINGERPRINT.equals(fingerprint)) {
+                    mDefaultPermissionsGranted.put(userId, true);
+                }
+            // Any error while writing is fatal.
             } catch (Throwable t) {
                 Slog.wtf(PackageManagerService.TAG,
                         "Failed to write settings, restoring backup", t);
@@ -4529,6 +4564,13 @@
                 }
 
                 switch (parser.getName()) {
+                    case TAG_RUNTIME_PERMISSIONS: {
+                        String fingerprint = parser.getAttributeValue(null, ATTR_FINGERPRINT);
+                        mFingerprints.put(userId, fingerprint);
+                        final boolean defaultsGranted = Build.FINGERPRINT.equals(fingerprint);
+                        mDefaultPermissionsGranted.put(userId, defaultsGranted);
+                    } break;
+
                     case TAG_PACKAGE: {
                         String name = parser.getAttributeValue(null, ATTR_NAME);
                         PackageSetting ps = mPackages.get(name);