Merge "Make WebViewFactory more robust." into lmp-dev
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 87d14b9..0ca800f 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -329,7 +329,7 @@
 
         try {
             String type = ActivityManagerNative.getDefault().getProviderMimeType(
-                    url, UserHandle.myUserId());
+                    ContentProvider.getUriWithoutUserId(url), resolveUserId(url));
             return type;
         } catch (RemoteException e) {
             // Arbitrary and not worth documenting, as Activity
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index c7c7a92..4455901 100755
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -8971,8 +8971,10 @@
     }
 
     /**
-     * Allows app to retrieve the MIME type of a URI without having permission
-     * to access its content provider.
+     * Allows apps to retrieve the MIME type of a URI.
+     * If an app is in the same user as the ContentProvider, or if it is allowed to interact across
+     * users, then it does not need permission to access the ContentProvider.
+     * Either, it needs cross-user uri grants.
      *
      * CTS tests for this functionality can be run with "runtest cts-appsecurity".
      *
@@ -8981,12 +8983,22 @@
      */
     public String getProviderMimeType(Uri uri, int userId) {
         enforceNotIsolatedCaller("getProviderMimeType");
-        userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
-                userId, false, ALLOW_NON_FULL_IN_PROFILE, "getProviderMimeType", null);
         final String name = uri.getAuthority();
-        final long ident = Binder.clearCallingIdentity();
+        int callingUid = Binder.getCallingUid();
+        int callingPid = Binder.getCallingPid();
+        long ident = 0;
+        boolean clearedIdentity = false;
+        userId = unsafeConvertIncomingUser(userId);
+        if (UserHandle.getUserId(callingUid) != userId) {
+            if (checkComponentPermission(INTERACT_ACROSS_USERS, callingPid,
+                    callingUid, -1, true) == PackageManager.PERMISSION_GRANTED
+                    || checkComponentPermission(INTERACT_ACROSS_USERS_FULL, callingPid,
+                    callingUid, -1, true) == PackageManager.PERMISSION_GRANTED) {
+                clearedIdentity = true;
+                ident = Binder.clearCallingIdentity();
+            }
+        }
         ContentProviderHolder holder = null;
-
         try {
             holder = getContentProviderExternalUnchecked(name, null, userId);
             if (holder != null) {
@@ -8996,10 +9008,17 @@
             Log.w(TAG, "Content provider dead retrieving " + uri, e);
             return null;
         } finally {
-            if (holder != null) {
-                removeContentProviderExternalUnchecked(name, null, userId);
+            // We need to clear the identity to call removeContentProviderExternalUnchecked
+            if (!clearedIdentity) {
+                ident = Binder.clearCallingIdentity();
             }
-            Binder.restoreCallingIdentity(ident);
+            try {
+                if (holder != null) {
+                    removeContentProviderExternalUnchecked(name, null, userId);
+                }
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
         }
 
         return null;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 44b7f01..36dec3e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -4635,12 +4635,12 @@
         // 2.) we are defering a needed dexopt
         // 3.) we are skipping an unneeded dexopt
         final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
-        for (String path : paths) {
-            for (String dexCodeInstructionSet : dexCodeInstructionSets) {
-                if (!forceDex && pkg.mDexOptPerformed.contains(dexCodeInstructionSet)) {
-                    continue;
-                }
+        for (String dexCodeInstructionSet : dexCodeInstructionSets) {
+            if (!forceDex && pkg.mDexOptPerformed.contains(dexCodeInstructionSet)) {
+                continue;
+            }
 
+            for (String path : paths) {
                 try {
                     // This will return DEXOPT_NEEDED if we either cannot find any odex file for this
                     // patckage or the one we find does not match the image checksum (i.e. it was
@@ -4661,10 +4661,9 @@
                             // just result in an error again. Also, don't bother dexopting for other
                             // paths & ISAs.
                             return DEX_OPT_FAILED;
-                        } else {
-                            performedDexOpt = true;
-                            pkg.mDexOptPerformed.add(dexCodeInstructionSet);
                         }
+
+                        performedDexOpt = true;
                     } else if (!defer && isDexOptNeeded == DexFile.PATCHOAT_NEEDED) {
                         Log.i(TAG, "Running patchoat on: " + pkg.applicationInfo.packageName);
                         final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
@@ -4676,10 +4675,9 @@
                             // just result in an error again. Also, don't bother dexopting for other
                             // paths & ISAs.
                             return DEX_OPT_FAILED;
-                        } else {
-                            performedDexOpt = true;
-                            pkg.mDexOptPerformed.add(dexCodeInstructionSet);
                         }
+
+                        performedDexOpt = true;
                     }
 
                     // We're deciding to defer a needed dexopt. Don't bother dexopting for other
@@ -4706,6 +4704,13 @@
                     return DEX_OPT_FAILED;
                 }
             }
+
+            // At this point we haven't failed dexopt and we haven't deferred dexopt. We must
+            // either have either succeeded dexopt, or have had isDexOptNeededInternal tell us
+            // it isn't required. We therefore mark that this package doesn't need dexopt unless
+            // it's forced. performedDexOpt will tell us whether we performed dex-opt or skipped
+            // it.
+            pkg.mDexOptPerformed.add(dexCodeInstructionSet);
         }
 
         // If we've gotten here, we're sure that no error occurred and that we haven't