Add new internal resolve method

Instant apps are unique in that any application can start them
with a VIEW/BROWSABLE while only very few apps can see an
instant app using queryIntentActivites, etc... In order to
support this dichotomy, we need an internal hook to resolution
for activity start.

Test: cts-tradefed run commandAndExit cts-dev -m CtsAppSecurityHostTestCases -t android.appsecurity.cts.EphemeralTest
Bug: 25119046
Change-Id: If6974c09c733ff0417ef72cabb9d9e9aca86c37c
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index 94fe572..6272822 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -306,4 +306,10 @@
      */
     public abstract boolean setEnabledOverlayPackages(int userId, String targetPackageName,
             List<String> overlayPackageNames);
+
+    /**
+     * Resolves an intent, allowing instant apps to be resolved.
+     */
+    public abstract ResolveInfo resolveIntent(Intent intent, String resolvedType,
+            int flags, int userId);
 }
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 1e33bb9..6f79bc27 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1196,13 +1196,11 @@
     }
 
     ResolveInfo resolveIntent(Intent intent, String resolvedType, int userId, int flags) {
-        try {
-            return AppGlobals.getPackageManager().resolveIntent(intent, resolvedType,
+        synchronized (mService) {
+            return mService.getPackageManagerInternalLocked().resolveIntent(intent, resolvedType,
                     PackageManager.MATCH_INSTANT | PackageManager.MATCH_DEFAULT_ONLY | flags
                     | ActivityManagerService.STOCK_PM_FLAGS, userId);
-        } catch (RemoteException e) {
         }
-        return null;
     }
 
     ActivityInfo resolveActivity(Intent intent, String resolvedType, int startFlags,
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index fe2fb66..33bd350 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -4012,8 +4012,17 @@
 
     /**
      * Update given flags when being used to request {@link ResolveInfo}.
+     * <p>Instant apps are resolved specially, depending upon context. Minimally,
+     * {@code}flags{@code} must have the {@link PackageManager#MATCH_INSTANT}
+     * flag set. However, this flag is only honoured in three circumstances:
+     * <ul>
+     * <li>when called from a system process</li>
+     * <li>when the caller holds the permission {@code android.permission.ACCESS_INSTANT_APPS}</li>
+     * <li>when resolution occurs to start an activity with a {@code android.intent.action.VIEW}
+     * action and a {@code android.intent.category.BROWSABLE} category</li>
+     * </ul>
      */
-    int updateFlagsForResolve(int flags, int userId, Object cookie) {
+    int updateFlagsForResolve(int flags, int userId, Intent intent, boolean includeInstantApp) {
         // Safe mode means we shouldn't match any third-party components
         if (mSafeMode) {
             flags |= PackageManager.MATCH_SYSTEM_ONLY;
@@ -4025,15 +4034,24 @@
             flags |= PackageManager.MATCH_INSTANT;
         } else {
             // Otherwise, prevent leaking ephemeral components
+            final boolean isSpecialProcess =
+                    callingUid == Process.SYSTEM_UID
+                    || callingUid == Process.SHELL_UID
+                    || callingUid == 0;
+            final boolean allowMatchInstant =
+                    (includeInstantApp
+                            && Intent.ACTION_VIEW.equals(intent.getAction())
+                            && intent.hasCategory(Intent.CATEGORY_BROWSABLE)
+                            && hasWebURI(intent))
+                    || isSpecialProcess
+                    || mContext.checkCallingOrSelfPermission(
+                            android.Manifest.permission.ACCESS_INSTANT_APPS) == PERMISSION_GRANTED;
             flags &= ~PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY;
-            if (callingUid != Process.SYSTEM_UID
-                    && callingUid != Process.SHELL_UID
-                    && callingUid != 0) {
-                // Unless called from the system process
+            if (!allowMatchInstant) {
                 flags &= ~PackageManager.MATCH_INSTANT;
             }
         }
-        return updateFlagsForComponent(flags, userId, cookie);
+        return updateFlagsForComponent(flags, userId, intent /*cookie*/);
     }
 
     @Override
@@ -5558,17 +5576,23 @@
     @Override
     public ResolveInfo resolveIntent(Intent intent, String resolvedType,
             int flags, int userId) {
+        return resolveIntentInternal(
+                intent, resolvedType, flags, userId, false /*includeInstantApp*/);
+    }
+
+    private ResolveInfo resolveIntentInternal(Intent intent, String resolvedType,
+            int flags, int userId, boolean includeInstantApp) {
         try {
             Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveIntent");
 
             if (!sUserManager.exists(userId)) return null;
-            flags = updateFlagsForResolve(flags, userId, intent);
+            flags = updateFlagsForResolve(flags, userId, intent, includeInstantApp);
             enforceCrossUserPermission(Binder.getCallingUid(), userId,
                     false /*requireFullPermission*/, false /*checkShell*/, "resolve intent");
 
             Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "queryIntentActivities");
             final List<ResolveInfo> query = queryIntentActivitiesInternal(intent, resolvedType,
-                    flags, userId);
+                    flags, userId, includeInstantApp);
             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
 
             final ResolveInfo bestChoice =
@@ -5590,7 +5614,7 @@
         }
         intent = updateIntentForResolve(intent);
         final String resolvedType = intent.resolveTypeIfNeeded(mContext.getContentResolver());
-        final int flags = updateFlagsForResolve(0, userId, intent);
+        final int flags = updateFlagsForResolve(0, userId, intent, false);
         final List<ResolveInfo> query = queryIntentActivitiesInternal(intent, resolvedType, flags,
                 userId);
         synchronized (mPackages) {
@@ -5749,6 +5773,13 @@
                 if (ri != null) {
                     return ri;
                 }
+                // If we have an ephemeral app, use it
+                for (int i = 0; i < N; i++) {
+                    ri = query.get(i);
+                    if (ri.activityInfo.applicationInfo.isInstantApp()) {
+                        return ri;
+                    }
+                }
                 ri = new ResolveInfo(mResolveInfo);
                 ri.activityInfo = new ActivityInfo(ri.activityInfo);
                 ri.activityInfo.labelRes = ResolverActivity.getLabelRes(intent.getAction());
@@ -5867,7 +5898,7 @@
             List<ResolveInfo> query, int priority, boolean always,
             boolean removeMatches, boolean debug, int userId) {
         if (!sUserManager.exists(userId)) return null;
-        flags = updateFlagsForResolve(flags, userId, intent);
+        flags = updateFlagsForResolve(flags, userId, intent, false);
         intent = updateIntentForResolve(intent);
         // writer
         synchronized (mPackages) {
@@ -6035,7 +6066,7 @@
             // cross-profile app linking works only towards the parent.
             final UserInfo parent = getProfileParent(sourceUserId);
             synchronized(mPackages) {
-                int flags = updateFlagsForResolve(0, parent.id, intent);
+                int flags = updateFlagsForResolve(0, parent.id, intent, false);
                 CrossProfileDomainInfo xpDomainInfo = getCrossProfileDomainPreferredLpr(
                         intent, resolvedType, flags, sourceUserId, parent.id);
                 return xpDomainInfo != null;
@@ -6094,9 +6125,14 @@
 
     private @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent,
             String resolvedType, int flags, int userId) {
+        return queryIntentActivitiesInternal(intent, resolvedType, flags, userId, false);
+    }
+
+    private @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent,
+            String resolvedType, int flags, int userId, boolean includeInstantApp) {
         if (!sUserManager.exists(userId)) return Collections.emptyList();
         final String instantAppPkgName = getInstantAppPackageName(Binder.getCallingUid());
-        flags = updateFlagsForResolve(flags, userId, intent);
+        flags = updateFlagsForResolve(flags, userId, intent, includeInstantApp);
         enforceCrossUserPermission(Binder.getCallingUid(), userId,
                 false /* requireFullPermission */, false /* checkShell */,
                 "query intent activities");
@@ -6723,7 +6759,7 @@
             Intent[] specifics, String[] specificTypes, Intent intent,
             String resolvedType, int flags, int userId) {
         if (!sUserManager.exists(userId)) return Collections.emptyList();
-        flags = updateFlagsForResolve(flags, userId, intent);
+        flags = updateFlagsForResolve(flags, userId, intent, false);
         enforceCrossUserPermission(Binder.getCallingUid(), userId,
                 false /* requireFullPermission */, false /* checkShell */,
                 "query intent activity options");
@@ -6903,7 +6939,7 @@
     private @NonNull List<ResolveInfo> queryIntentReceiversInternal(Intent intent,
             String resolvedType, int flags, int userId) {
         if (!sUserManager.exists(userId)) return Collections.emptyList();
-        flags = updateFlagsForResolve(flags, userId, intent);
+        flags = updateFlagsForResolve(flags, userId, intent, false);
         ComponentName comp = intent.getComponent();
         if (comp == null) {
             if (intent.getSelector() != null) {
@@ -6940,7 +6976,7 @@
     @Override
     public ResolveInfo resolveService(Intent intent, String resolvedType, int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
-        flags = updateFlagsForResolve(flags, userId, intent);
+        flags = updateFlagsForResolve(flags, userId, intent, false);
         List<ResolveInfo> query = queryIntentServicesInternal(intent, resolvedType, flags, userId);
         if (query != null) {
             if (query.size() >= 1) {
@@ -6962,7 +6998,7 @@
     private @NonNull List<ResolveInfo> queryIntentServicesInternal(Intent intent,
             String resolvedType, int flags, int userId) {
         if (!sUserManager.exists(userId)) return Collections.emptyList();
-        flags = updateFlagsForResolve(flags, userId, intent);
+        flags = updateFlagsForResolve(flags, userId, intent, false);
         ComponentName comp = intent.getComponent();
         if (comp == null) {
             if (intent.getSelector() != null) {
@@ -7006,7 +7042,7 @@
     private @NonNull List<ResolveInfo> queryIntentContentProvidersInternal(
             Intent intent, String resolvedType, int flags, int userId) {
         if (!sUserManager.exists(userId)) return Collections.emptyList();
-        flags = updateFlagsForResolve(flags, userId, intent);
+        flags = updateFlagsForResolve(flags, userId, intent, false);
         ComponentName comp = intent.getComponent();
         if (comp == null) {
             if (intent.getSelector() != null) {
@@ -23003,13 +23039,18 @@
             return targetPackages;
         }
 
-
         @Override
         public boolean setEnabledOverlayPackages(int userId, String targetPackageName,
                 List<String> overlayPackageNames) {
             // TODO: implement when we integrate OMS properly
             return false;
         }
+
+        public ResolveInfo resolveIntent(Intent intent, String resolvedType,
+                int flags, int userId) {
+            return resolveIntentInternal(
+                    intent, resolvedType, flags, userId, true /*includeInstantApp*/);
+        }
     }
 
     @Override
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index a8a5ff0..a057e9b 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -3370,7 +3370,7 @@
     private void applyDefaultPreferredActivityLPw(PackageManagerService service,
             Intent intent, int flags, ComponentName cn, String scheme, PatternMatcher ssp,
             IntentFilter.AuthorityEntry auth, PatternMatcher path, int userId) {
-        flags = service.updateFlagsForResolve(flags, userId, intent);
+        flags = service.updateFlagsForResolve(flags, userId, intent, false);
         List<ResolveInfo> ri = service.mActivities.queryIntent(intent,
                 intent.getType(), flags, 0);
         if (PackageManagerService.DEBUG_PREFERRED) Log.d(TAG, "Queried " + intent