Merge "Load splits on-demand"
diff --git a/core/java/android/content/pm/AuxiliaryResolveInfo.java b/core/java/android/content/pm/AuxiliaryResolveInfo.java
new file mode 100644
index 0000000..7d7784a
--- /dev/null
+++ b/core/java/android/content/pm/AuxiliaryResolveInfo.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Intent;
+import android.content.IntentFilter;
+
+/**
+ * Auxiliary application resolution response.
+ * <p>
+ * Used when resolution occurs, but, the target is not actually on the device.
+ * This happens resolving instant apps that haven't been installed yet or if
+ * the application consists of multiple feature splits and the needed split
+ * hasn't been installed.
+ * @hide
+ */
+public final class AuxiliaryResolveInfo extends IntentFilter {
+    /** Resolved information returned from the external ephemeral resolver */
+    public final EphemeralResolveInfo resolveInfo;
+    /** The resolved package. Copied from {@link #resolveInfo}. */
+    public final String packageName;
+    /** The resolve split. Copied from the matched filter in {@link #resolveInfo}. */
+    public final String splitName;
+    /** Whether or not ephemeral resolution needs the second phase */
+    public final boolean needsPhaseTwo;
+    /** Opaque token to track the ephemeral application resolution */
+    public final String token;
+    /** The version code of the package */
+    public final int versionCode;
+
+    /** Create a response for installing an instant application. */
+    public AuxiliaryResolveInfo(@NonNull EphemeralResolveInfo resolveInfo,
+            @NonNull IntentFilter orig,
+            @Nullable String splitName,
+            @NonNull String token,
+            boolean needsPhase2) {
+        super(orig);
+        this.resolveInfo = resolveInfo;
+        this.packageName = resolveInfo.getPackageName();
+        this.splitName = splitName;
+        this.token = token;
+        this.needsPhaseTwo = needsPhase2;
+        this.versionCode = resolveInfo.getVersionCode();
+    }
+
+    /** Create a response for installing a split on demand. */
+    public AuxiliaryResolveInfo(@NonNull String packageName,
+            @Nullable String splitName,
+            int versionCode) {
+        super();
+        this.packageName = packageName;
+        this.splitName = splitName;
+        this.versionCode = versionCode;
+        this.resolveInfo = null;
+        this.token = null;
+        this.needsPhaseTwo = false;
+    }
+}
\ No newline at end of file
diff --git a/core/java/android/content/pm/EphemeralRequest.java b/core/java/android/content/pm/EphemeralRequest.java
index 7f2b3ee1..58099c2b 100644
--- a/core/java/android/content/pm/EphemeralRequest.java
+++ b/core/java/android/content/pm/EphemeralRequest.java
@@ -24,24 +24,21 @@
  */
 public final class EphemeralRequest {
     /** Response from the first phase of ephemeral application resolution */
-    public final EphemeralResponse responseObj;
+    public final AuxiliaryResolveInfo responseObj;
     /** The original intent that triggered ephemeral application resolution */
     public final Intent origIntent;
     /** Resolved type of the intent */
     public final String resolvedType;
-    /** The intent that would launch if there were no ephemeral applications */
-    public final Intent launchIntent;
     /** The name of the package requesting the ephemeral application */
     public final String callingPackage;
     /** ID of the user requesting the ephemeral application */
     public final int userId;
 
-    public EphemeralRequest(EphemeralResponse responseObj, Intent origIntent,
-            String resolvedType, Intent launchIntent, String callingPackage, int userId) {
+    public EphemeralRequest(AuxiliaryResolveInfo responseObj, Intent origIntent,
+            String resolvedType, String callingPackage, int userId) {
         this.responseObj = responseObj;
         this.origIntent = origIntent;
         this.resolvedType = resolvedType;
-        this.launchIntent = launchIntent;
         this.callingPackage = callingPackage;
         this.userId = userId;
     }
diff --git a/core/java/android/content/pm/EphemeralResponse.java b/core/java/android/content/pm/EphemeralResponse.java
deleted file mode 100644
index 6e569f7..0000000
--- a/core/java/android/content/pm/EphemeralResponse.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.content.pm;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.IntentFilter;
-
-/**
- * Ephemeral application resolution response.
- * @hide
- */
-public final class EphemeralResponse extends IntentFilter {
-    /** Resolved information returned from the external ephemeral resolver */
-    public final EphemeralResolveInfo resolveInfo;
-    /** The resolved package. Copied from {@link #resolveInfo}. */
-    public final String packageName;
-    /** The resolve split. Copied from the matched filter in {@link #resolveInfo}. */
-    public final String splitName;
-    /** Whether or not ephemeral resolution needs the second phase */
-    public final boolean needsPhase2;
-    /** Opaque token to track the ephemeral application resolution */
-    public final String token;
-
-    public EphemeralResponse(@NonNull EphemeralResolveInfo resolveInfo,
-            @NonNull IntentFilter orig,
-            @Nullable String splitName,
-            @NonNull String token,
-            boolean needsPhase2) {
-        super(orig);
-        this.resolveInfo = resolveInfo;
-        this.packageName = resolveInfo.getPackageName();
-        this.splitName = splitName;
-        this.token = token;
-        this.needsPhase2 = needsPhase2;
-    }
-}
\ No newline at end of file
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index 7d59bd6..94fe572 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -213,12 +213,11 @@
      * @param responseObj The response of the first phase of ephemeral resolution
      * @param origIntent The original intent that triggered ephemeral resolution
      * @param resolvedType The resolved type of the intent
-     * @param launchIntent The intent that would launch if there was no ephemeral application
      * @param callingPackage The name of the package requesting the ephemeral application
      * @param userId The ID of the user that triggered ephemeral resolution
      */
-    public abstract void requestEphemeralResolutionPhaseTwo(EphemeralResponse responseObj,
-            Intent origIntent, String resolvedType, Intent launchIntent, String callingPackage,
+    public abstract void requestInstantAppResolutionPhaseTwo(AuxiliaryResolveInfo responseObj,
+            Intent origIntent, String resolvedType, String callingPackage,
             int userId);
 
     /**
diff --git a/core/java/android/content/pm/ResolveInfo.java b/core/java/android/content/pm/ResolveInfo.java
index f8b4570..50f2d53 100644
--- a/core/java/android/content/pm/ResolveInfo.java
+++ b/core/java/android/content/pm/ResolveInfo.java
@@ -61,11 +61,12 @@
     public ProviderInfo providerInfo;
 
     /**
-     * The ephemeral application that corresponds to this resolution match. This will
-     * only be set in specific circumstances.
+     * An auxiliary response that may modify the resolved information. This is
+     * only set under certain circumstances; such as when resolving instant apps
+     * or components defined in un-installed splits.
      * @hide
      */
-    public EphemeralResponse ephemeralResponse;
+    public AuxiliaryResolveInfo auxiliaryInfo;
 
     /**
      * The IntentFilter that was matched for this ResolveInfo.
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 7605a1e..83d43db 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -82,6 +82,7 @@
 import static com.android.server.am.ActivityStackSupervisor.TAG_TASKS;
 import static com.android.server.am.EventLogTags.AM_NEW_INTENT;
 
+import android.annotation.NonNull;
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
 import android.app.AppGlobals;
@@ -98,7 +99,9 @@
 import android.content.IntentSender;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.AuxiliaryResolveInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
 import android.content.pm.ResolveInfo;
 import android.content.pm.UserInfo;
 import android.content.res.Configuration;
@@ -456,22 +459,9 @@
         // Instead, launch the ephemeral installer. Once the installer is finished, it
         // starts either the intent we resolved here [on install error] or the ephemeral
         // app [on install success].
-        if (rInfo != null && rInfo.ephemeralResponse != null) {
-            final String packageName =
-                    rInfo.ephemeralResponse.resolveInfo.getPackageName();
-            final String splitName = rInfo.ephemeralResponse.splitName;
-            final boolean needsPhaseTwo = rInfo.ephemeralResponse.needsPhase2;
-            final String token = rInfo.ephemeralResponse.token;
-            final int versionCode = rInfo.ephemeralResponse.resolveInfo.getVersionCode();
-            if (needsPhaseTwo) {
-                // request phase two resolution
-                mService.getPackageManagerInternalLocked().requestEphemeralResolutionPhaseTwo(
-                        rInfo.ephemeralResponse, ephemeralIntent, resolvedType, intent,
-                        callingPackage, userId);
-            }
-            intent = EphemeralResolver.buildEphemeralInstallerIntent(intent, ephemeralIntent,
-                    callingPackage, resolvedType, userId, packageName, splitName, versionCode,
-                    token, needsPhaseTwo);
+        if (rInfo != null && rInfo.auxiliaryInfo != null) {
+            intent = createLaunchIntent(rInfo.auxiliaryInfo, ephemeralIntent,
+                    callingPackage, resolvedType, userId);
             resolvedType = null;
             callingUid = realCallingUid;
             callingPid = realCallingPid;
@@ -530,6 +520,21 @@
         return err;
     }
 
+    /** Creates a launch intent for the given auxiliary resolution data. */
+    private @NonNull Intent createLaunchIntent(@NonNull AuxiliaryResolveInfo auxiliaryResponse,
+            Intent originalIntent, String callingPackage,
+            String resolvedType, int userId) {
+        if (auxiliaryResponse.needsPhaseTwo) {
+            // request phase two resolution
+            mService.getPackageManagerInternalLocked().requestInstantAppResolutionPhaseTwo(
+                    auxiliaryResponse, originalIntent, resolvedType, callingPackage, userId);
+        }
+        return EphemeralResolver.buildEphemeralInstallerIntent(originalIntent,
+                callingPackage, resolvedType, userId, auxiliaryResponse.packageName,
+                auxiliaryResponse.splitName, auxiliaryResponse.versionCode,
+                auxiliaryResponse.token, auxiliaryResponse.needsPhaseTwo);
+    }
+
     void postStartActivityUncheckedProcessing(
             ActivityRecord r, int result, int prevFocusedStackId, ActivityRecord sourceRecord,
             ActivityStack targetStack) {
diff --git a/services/core/java/com/android/server/pm/EphemeralResolver.java b/services/core/java/com/android/server/pm/EphemeralResolver.java
index d99a1b6..7bc65f9 100644
--- a/services/core/java/com/android/server/pm/EphemeralResolver.java
+++ b/services/core/java/com/android/server/pm/EphemeralResolver.java
@@ -16,8 +16,9 @@
 
 package com.android.server.pm;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.ActivityManager;
-import android.app.ActivityManagerNative;
 import android.app.PendingIntent;
 import android.content.ComponentName;
 import android.content.Context;
@@ -29,7 +30,7 @@
 import android.content.pm.EphemeralIntentFilter;
 import android.content.pm.EphemeralRequest;
 import android.content.pm.EphemeralResolveInfo;
-import android.content.pm.EphemeralResponse;
+import android.content.pm.AuxiliaryResolveInfo;
 import android.content.pm.EphemeralResolveInfo.EphemeralDigest;
 import android.os.Binder;
 import android.os.Handler;
@@ -46,7 +47,7 @@
 
 /** @hide */
 public abstract class EphemeralResolver {
-    public static EphemeralResponse doEphemeralResolutionPhaseOne(Context context,
+    public static AuxiliaryResolveInfo doEphemeralResolutionPhaseOne(Context context,
             EphemeralResolverConnection connection, EphemeralRequest requestObj) {
         final Intent intent = requestObj.origIntent;
         final EphemeralDigest digest =
@@ -83,7 +84,7 @@
                     final ArrayList<EphemeralResolveInfo> ephemeralResolveInfoList =
                             new ArrayList<EphemeralResolveInfo>(1);
                     ephemeralResolveInfoList.add(ephemeralResolveInfo);
-                    final EphemeralResponse ephemeralIntentInfo =
+                    final AuxiliaryResolveInfo ephemeralIntentInfo =
                             EphemeralResolver.filterEphemeralIntent(
                                     ephemeralResolveInfoList, intent, null /*resolvedType*/,
                                     0 /*userId*/, intent.getPackage(), digest,
@@ -104,7 +105,6 @@
                     versionCode = -1;
                 }
                 final Intent installerIntent = buildEphemeralInstallerIntent(
-                        requestObj.launchIntent,
                         requestObj.origIntent,
                         requestObj.callingPackage,
                         requestObj.resolvedType,
@@ -126,35 +126,41 @@
     /**
      * Builds and returns an intent to launch the ephemeral installer.
      */
-    public static Intent buildEphemeralInstallerIntent(Intent launchIntent, Intent origIntent,
-            String callingPackage, String resolvedType, int userId, String ephemeralPackageName,
-            String ephemeralSplitName, int versionCode, String token, boolean needsPhaseTwo) {
+    public static Intent buildEphemeralInstallerIntent(@NonNull Intent origIntent,
+            @NonNull String callingPackage,
+            @NonNull String resolvedType,
+            int userId,
+            @NonNull String ephemeralPackageName,
+            @Nullable String ephemeralSplitName,
+            int versionCode,
+            @Nullable String token,
+            boolean needsPhaseTwo) {
         // Construct the intent that launches the ephemeral installer
-        int flags = launchIntent.getFlags();
+        int flags = origIntent.getFlags();
         final Intent intent = new Intent();
         intent.setFlags(flags
                 | Intent.FLAG_ACTIVITY_NEW_TASK
                 | Intent.FLAG_ACTIVITY_CLEAR_TASK
                 | Intent.FLAG_ACTIVITY_NO_HISTORY
                 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
-        // TODO: Remove when the platform has fully implemented ephemeral apps
-        intent.setData(origIntent.getData().buildUpon().clearQuery().build());
-        intent.putExtra(Intent.EXTRA_EPHEMERAL_TOKEN, token);
-        intent.putExtra(Intent.EXTRA_EPHEMERAL_HOSTNAME, origIntent.getData().getHost());
+        if (token != null) {
+            intent.putExtra(Intent.EXTRA_EPHEMERAL_TOKEN, token);
+        }
+        if (origIntent.getData() != null) {
+            intent.putExtra(Intent.EXTRA_EPHEMERAL_HOSTNAME, origIntent.getData().getHost());
+        }
 
+        // We have all of the data we need; just start the installer without a second phase
         if (!needsPhaseTwo) {
-            // We have all of the data we need; just start the installer without a second phase
-            final Intent nonEphemeralIntent = new Intent(origIntent);
-            nonEphemeralIntent.setFlags(
-                    nonEphemeralIntent.getFlags() | Intent.FLAG_IGNORE_EPHEMERAL);
-            // Intent that is launched if the ephemeral package couldn't be installed
-            // for any reason.
+            // Intent that is launched if the package couldn't be installed for any reason.
+            final Intent failureIntent = new Intent(origIntent);
+            failureIntent.setFlags(failureIntent.getFlags() | Intent.FLAG_IGNORE_EPHEMERAL);
             try {
-                final IIntentSender failureIntentTarget = ActivityManagerNative.getDefault()
+                final IIntentSender failureIntentTarget = ActivityManager.getService()
                         .getIntentSender(
                                 ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage,
                                 null /*token*/, null /*resultWho*/, 1 /*requestCode*/,
-                                new Intent[] { nonEphemeralIntent },
+                                new Intent[] { failureIntent },
                                 new String[] { resolvedType },
                                 PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT
                                         | PendingIntent.FLAG_IMMUTABLE,
@@ -163,19 +169,14 @@
                         new IntentSender(failureIntentTarget));
             } catch (RemoteException ignore) { /* ignore; same process */ }
 
-            // Success intent goes back to the installer
-            final Intent ephemeralIntent = new Intent(launchIntent)
-                    .setComponent(null)
-                    .setPackage(ephemeralPackageName);
-            // Intent that is eventually launched if the ephemeral package was
-            // installed successfully. This will actually be launched by a platform
-            // broadcast receiver.
+            // Intent that is launched if the package was installed successfully.
+            final Intent successIntent = new Intent(origIntent);
             try {
-                final IIntentSender successIntentTarget = ActivityManagerNative.getDefault()
+                final IIntentSender successIntentTarget = ActivityManager.getService()
                         .getIntentSender(
                                 ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage,
                                 null /*token*/, null /*resultWho*/, 0 /*requestCode*/,
-                                new Intent[] { ephemeralIntent },
+                                new Intent[] { successIntent },
                                 new String[] { resolvedType },
                                 PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT
                                         | PendingIntent.FLAG_IMMUTABLE,
@@ -192,7 +193,7 @@
         return intent;
     }
 
-    private static EphemeralResponse filterEphemeralIntent(
+    private static AuxiliaryResolveInfo filterEphemeralIntent(
             List<EphemeralResolveInfo> ephemeralResolveInfoList,
             Intent intent, String resolvedType, int userId, String packageName,
             EphemeralDigest digest, String token) {
@@ -212,7 +213,7 @@
                         ephemeralInfo.getIntentFilters();
                 // No filters; we need to start phase two
                 if (ephemeralFilters == null || ephemeralFilters.isEmpty()) {
-                    return new EphemeralResponse(ephemeralInfo,
+                    return new AuxiliaryResolveInfo(ephemeralInfo,
                             new IntentFilter(Intent.ACTION_VIEW) /*intentFilter*/,
                             null /*splitName*/, token, true /*needsPhase2*/);
                 }
@@ -226,14 +227,14 @@
                         continue;
                     }
                     for (int k = splitFilters.size() - 1; k >= 0; --k) {
-                        final EphemeralResponse intentInfo =
-                                new EphemeralResponse(ephemeralInfo,
+                        final AuxiliaryResolveInfo intentInfo =
+                                new AuxiliaryResolveInfo(ephemeralInfo,
                                         splitFilters.get(k), ephemeralFilter.getSplitName(),
                                         token, false /*needsPhase2*/);
                         ephemeralResolver.addFilter(intentInfo);
                     }
                 }
-                List<EphemeralResponse> matchedResolveInfoList = ephemeralResolver.queryIntent(
+                List<AuxiliaryResolveInfo> matchedResolveInfoList = ephemeralResolver.queryIntent(
                         intent, resolvedType, false /*defaultOnly*/, userId);
                 if (!matchedResolveInfoList.isEmpty()) {
                     return matchedResolveInfoList.get(0);
diff --git a/services/core/java/com/android/server/pm/EphemeralResolverConnection.java b/services/core/java/com/android/server/pm/EphemeralResolverConnection.java
index 2b6ce10..7f5973e 100644
--- a/services/core/java/com/android/server/pm/EphemeralResolverConnection.java
+++ b/services/core/java/com/android/server/pm/EphemeralResolverConnection.java
@@ -23,7 +23,6 @@
 import android.content.Intent;
 import android.content.ServiceConnection;
 import android.content.pm.EphemeralResolveInfo;
-import android.content.pm.EphemeralResponse;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 975ae06..fe2fb66 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -131,7 +131,7 @@
 import android.content.pm.InstantAppInfo;
 import android.content.pm.EphemeralRequest;
 import android.content.pm.EphemeralResolveInfo;
-import android.content.pm.EphemeralResponse;
+import android.content.pm.AuxiliaryResolveInfo;
 import android.content.pm.FallbackCategoryProvider;
 import android.content.pm.FeatureInfo;
 import android.content.pm.IOnPermissionsChangeListener;
@@ -837,12 +837,12 @@
     private int mIntentFilterVerificationToken = 0;
 
     /** The service connection to the ephemeral resolver */
-    final EphemeralResolverConnection mEphemeralResolverConnection;
+    final EphemeralResolverConnection mInstantAppResolverConnection;
 
     /** Component used to install ephemeral applications */
-    ComponentName mEphemeralInstallerComponent;
-    final ActivityInfo mEphemeralInstallerActivity = new ActivityInfo();
-    final ResolveInfo mEphemeralInstallerInfo = new ResolveInfo();
+    ComponentName mInstantAppInstallerComponent;
+    final ActivityInfo mInstantAppInstallerActivity = new ActivityInfo();
+    final ResolveInfo mInstantAppInstallerInfo = new ResolveInfo();
 
     final SparseArray<IntentFilterVerificationState> mIntentFilterVerificationStates
             = new SparseArray<IntentFilterVerificationState>();
@@ -1164,7 +1164,7 @@
     static final int START_INTENT_FILTER_VERIFICATIONS = 17;
     static final int INTENT_FILTER_VERIFIED = 18;
     static final int WRITE_PACKAGE_LIST = 19;
-    static final int EPHEMERAL_RESOLUTION_PHASE_TWO = 20;
+    static final int INSTANT_APP_RESOLUTION_PHASE_TWO = 20;
 
     static final int WRITE_SETTINGS_DELAY = 10*1000;  // 10 seconds
 
@@ -1735,11 +1735,11 @@
 
                     break;
                 }
-                case EPHEMERAL_RESOLUTION_PHASE_TWO: {
+                case INSTANT_APP_RESOLUTION_PHASE_TWO: {
                     EphemeralResolver.doEphemeralResolutionPhaseTwo(mContext,
-                            mEphemeralResolverConnection,
+                            mInstantAppResolverConnection,
                             (EphemeralRequest) msg.obj,
-                            mEphemeralInstallerActivity,
+                            mInstantAppInstallerActivity,
                             mHandler);
                 }
             }
@@ -2890,17 +2890,17 @@
                 if (DEBUG_EPHEMERAL) {
                     Slog.i(TAG, "Ephemeral resolver: " + ephemeralResolverComponent);
                 }
-                mEphemeralResolverConnection =
+                mInstantAppResolverConnection =
                         new EphemeralResolverConnection(mContext, ephemeralResolverComponent);
             } else {
-                mEphemeralResolverConnection = null;
+                mInstantAppResolverConnection = null;
             }
-            mEphemeralInstallerComponent = getEphemeralInstallerLPr();
-            if (mEphemeralInstallerComponent != null) {
+            mInstantAppInstallerComponent = getEphemeralInstallerLPr();
+            if (mInstantAppInstallerComponent != null) {
                 if (DEBUG_EPHEMERAL) {
-                    Slog.i(TAG, "Ephemeral installer: " + mEphemeralInstallerComponent);
+                    Slog.i(TAG, "Ephemeral installer: " + mInstantAppInstallerComponent);
                 }
-                setUpEphemeralInstallerActivityLP(mEphemeralInstallerComponent);
+                setUpInstantAppInstallerActivityLP(mInstantAppInstallerComponent);
             }
 
             // Read and update the usage of dex files.
@@ -4026,7 +4026,9 @@
         } else {
             // Otherwise, prevent leaking ephemeral components
             flags &= ~PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY;
-            if (callingUid != Process.SYSTEM_UID && callingUid != 0) {
+            if (callingUid != Process.SYSTEM_UID
+                    && callingUid != Process.SHELL_UID
+                    && callingUid != 0) {
                 // Unless called from the system process
                 flags &= ~PackageManager.MATCH_INSTANT;
             }
@@ -5659,10 +5661,10 @@
         if (callingUser != UserHandle.USER_SYSTEM) {
             return false;
         }
-        if (mEphemeralResolverConnection == null) {
+        if (mInstantAppResolverConnection == null) {
             return false;
         }
-        if (mEphemeralInstallerComponent == null) {
+        if (mInstantAppInstallerComponent == null) {
             return false;
         }
         if (intent.getComponent() != null) {
@@ -5679,6 +5681,7 @@
             return false;
         }
         // Deny ephemeral apps if the user chose _ALWAYS or _ALWAYS_ASK for intent resolution.
+        // Or if there's already an ephemeral app installed that handles the action
         synchronized (mPackages) {
             final int count = (resolvedActivities == null ? 0 : resolvedActivities.size());
             for (int n = 0; n < count; n++) {
@@ -5697,6 +5700,9 @@
                         }
                         return false;
                     }
+                    if (ps.getInstantApp(userId)) {
+                        return false;
+                    }
                 }
             }
         }
@@ -5704,11 +5710,11 @@
         return true;
     }
 
-    private void requestEphemeralResolutionPhaseTwo(EphemeralResponse responseObj,
-            Intent origIntent, String resolvedType, Intent launchIntent, String callingPackage,
+    private void requestInstantAppResolutionPhaseTwo(AuxiliaryResolveInfo responseObj,
+            Intent origIntent, String resolvedType, String callingPackage,
             int userId) {
-        final Message msg = mHandler.obtainMessage(EPHEMERAL_RESOLUTION_PHASE_TWO,
-                new EphemeralRequest(responseObj, origIntent, resolvedType, launchIntent,
+        final Message msg = mHandler.obtainMessage(INSTANT_APP_RESOLUTION_PHASE_TWO,
+                new EphemeralRequest(responseObj, origIntent, resolvedType,
                         callingPackage, userId));
         mHandler.sendMessage(msg);
     }
@@ -6134,7 +6140,7 @@
                     list.add(ri);
                 }
             }
-            return list;
+            return applyPostResolutionFilter(list, instantAppPkgName);
         }
 
         // reader
@@ -6152,7 +6158,7 @@
                 if (xpResolveInfo != null) {
                     List<ResolveInfo> xpResult = new ArrayList<ResolveInfo>(1);
                     xpResult.add(xpResolveInfo);
-                    return filterForEphemeral(
+                    return applyPostResolutionFilter(
                             filterIfNotSystemUser(xpResult, userId), instantAppPkgName);
                 }
 
@@ -6193,13 +6199,13 @@
                             // And we are not going to add emphemeral app, so we can return the
                             // result straight away.
                             result.add(xpDomainInfo.resolveInfo);
-                            return filterForEphemeral(result, instantAppPkgName);
+                            return applyPostResolutionFilter(result, instantAppPkgName);
                         }
                     } else if (result.size() <= 1 && !addEphemeral) {
                         // No result in parent user and <= 1 result in current profile, and we
                         // are not going to add emphemeral app, so we can return the result without
                         // further processing.
-                        return filterForEphemeral(result, instantAppPkgName);
+                        return applyPostResolutionFilter(result, instantAppPkgName);
                     }
                     // We have more than one candidate (combining results from current and parent
                     // profile), so we need filtering and sorting.
@@ -6210,7 +6216,7 @@
             } else {
                 final PackageParser.Package pkg = mPackages.get(pkgName);
                 if (pkg != null) {
-                    result = filterForEphemeral(filterIfNotSystemUser(
+                    result = applyPostResolutionFilter(filterIfNotSystemUser(
                             mActivities.queryIntentForPackage(
                                     intent, resolvedType, flags, pkg.activities, userId),
                             userId), instantAppPkgName);
@@ -6227,15 +6233,16 @@
             Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveEphemeral");
             final EphemeralRequest requestObject = new EphemeralRequest(
                     null /*responseObj*/, intent /*origIntent*/, resolvedType,
-                    null /*launchIntent*/, null /*callingPackage*/, userId);
-            final EphemeralResponse intentInfo = EphemeralResolver.doEphemeralResolutionPhaseOne(
-                    mContext, mEphemeralResolverConnection, requestObject);
-            if (intentInfo != null) {
+                    null /*callingPackage*/, userId);
+            final AuxiliaryResolveInfo auxiliaryResponse =
+                    EphemeralResolver.doEphemeralResolutionPhaseOne(
+                            mContext, mInstantAppResolverConnection, requestObject);
+            if (auxiliaryResponse != null) {
                 if (DEBUG_EPHEMERAL) {
                     Slog.v(TAG, "Adding ephemeral installer to the ResolveInfo list");
                 }
-                final ResolveInfo ephemeralInstaller = new ResolveInfo(mEphemeralInstallerInfo);
-                ephemeralInstaller.ephemeralResponse = intentInfo;
+                final ResolveInfo ephemeralInstaller = new ResolveInfo(mInstantAppInstallerInfo);
+                ephemeralInstaller.auxiliaryInfo = auxiliaryResponse;
                 // make sure this resolver is the default
                 ephemeralInstaller.isDefault = true;
                 ephemeralInstaller.match = IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART
@@ -6251,7 +6258,7 @@
         if (sortResult) {
             Collections.sort(result, mResolvePrioritySorter);
         }
-        return filterForEphemeral(result, instantAppPkgName);
+        return applyPostResolutionFilter(result, instantAppPkgName);
     }
 
     private static class CrossProfileDomainInfo {
@@ -6359,16 +6366,40 @@
      *          is performed.
      * @return A filtered list of resolved activities.
      */
-    private List<ResolveInfo> filterForEphemeral(List<ResolveInfo> resolveInfos,
+    private List<ResolveInfo> applyPostResolutionFilter(List<ResolveInfo> resolveInfos,
             String ephemeralPkgName) {
+        // TODO: When adding on-demand split support for non-instant apps, remove this check
+        // and always apply post filtering
         if (ephemeralPkgName == null) {
             return resolveInfos;
         }
         for (int i = resolveInfos.size() - 1; i >= 0; i--) {
-            ResolveInfo info = resolveInfos.get(i);
+            final ResolveInfo info = resolveInfos.get(i);
             final boolean isEphemeralApp = info.activityInfo.applicationInfo.isInstantApp();
             // allow activities that are defined in the provided package
             if (isEphemeralApp && ephemeralPkgName.equals(info.activityInfo.packageName)) {
+                if (info.activityInfo.splitName != null
+                        && !ArrayUtils.contains(info.activityInfo.applicationInfo.splitNames,
+                                info.activityInfo.splitName)) {
+                    // requested activity is defined in a split that hasn't been installed yet.
+                    // add the installer to the resolve list
+                    if (DEBUG_EPHEMERAL) {
+                        Slog.v(TAG, "Adding ephemeral installer to the ResolveInfo list");
+                    }
+                    final ResolveInfo installerInfo = new ResolveInfo(mInstantAppInstallerInfo);
+                    installerInfo.auxiliaryInfo = new AuxiliaryResolveInfo(
+                            info.activityInfo.packageName, info.activityInfo.splitName,
+                            info.activityInfo.applicationInfo.versionCode);
+                    // make sure this resolver is the default
+                    installerInfo.isDefault = true;
+                    installerInfo.match = IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART
+                            | IntentFilter.MATCH_ADJUSTMENT_NORMAL;
+                    // add a non-generic filter
+                    installerInfo.filter = new IntentFilter();
+                    // load resources from the correct package
+                    installerInfo.resolvePackageName = info.getComponentInfo().packageName;
+                    resolveInfos.set(i, installerInfo);
+                }
                 continue;
             }
             // allow activities that have been explicitly exposed to ephemeral apps
@@ -10699,12 +10730,12 @@
         }
     }
 
-    private void setUpEphemeralInstallerActivityLP(ComponentName installerComponent) {
+    private void setUpInstantAppInstallerActivityLP(ComponentName installerComponent) {
         if (installerComponent == null) {
             if (DEBUG_EPHEMERAL) {
                 Slog.d(TAG, "Clear ephemeral installer activity");
             }
-            mEphemeralInstallerActivity.applicationInfo = null;
+            mInstantAppInstallerActivity.applicationInfo = null;
             return;
         }
 
@@ -10713,21 +10744,21 @@
         }
         final PackageParser.Package pkg = mPackages.get(installerComponent.getPackageName());
         // Set up information for ephemeral installer activity
-        mEphemeralInstallerActivity.applicationInfo = pkg.applicationInfo;
-        mEphemeralInstallerActivity.name = installerComponent.getClassName();
-        mEphemeralInstallerActivity.packageName = pkg.applicationInfo.packageName;
-        mEphemeralInstallerActivity.processName = pkg.applicationInfo.packageName;
-        mEphemeralInstallerActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
-        mEphemeralInstallerActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS
+        mInstantAppInstallerActivity.applicationInfo = pkg.applicationInfo;
+        mInstantAppInstallerActivity.name = installerComponent.getClassName();
+        mInstantAppInstallerActivity.packageName = pkg.applicationInfo.packageName;
+        mInstantAppInstallerActivity.processName = pkg.applicationInfo.packageName;
+        mInstantAppInstallerActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
+        mInstantAppInstallerActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS
                 | ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS;
-        mEphemeralInstallerActivity.theme = 0;
-        mEphemeralInstallerActivity.exported = true;
-        mEphemeralInstallerActivity.enabled = true;
-        mEphemeralInstallerInfo.activityInfo = mEphemeralInstallerActivity;
-        mEphemeralInstallerInfo.priority = 0;
-        mEphemeralInstallerInfo.preferredOrder = 1;
-        mEphemeralInstallerInfo.isDefault = true;
-        mEphemeralInstallerInfo.match = IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART
+        mInstantAppInstallerActivity.theme = 0;
+        mInstantAppInstallerActivity.exported = true;
+        mInstantAppInstallerActivity.enabled = true;
+        mInstantAppInstallerInfo.activityInfo = mInstantAppInstallerActivity;
+        mInstantAppInstallerInfo.priority = 0;
+        mInstantAppInstallerInfo.preferredOrder = 1;
+        mInstantAppInstallerInfo.isDefault = true;
+        mInstantAppInstallerInfo.match = IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART
                 | IntentFilter.MATCH_ADJUSTMENT_NORMAL;
     }
 
@@ -12769,7 +12800,7 @@
     }
 
     static final class EphemeralIntentResolver
-            extends IntentResolver<EphemeralResponse, EphemeralResponse> {
+            extends IntentResolver<AuxiliaryResolveInfo, AuxiliaryResolveInfo> {
         /**
          * The result that has the highest defined order. Ordering applies on a
          * per-package basis. Mapping is from package name to Pair of order and
@@ -12784,17 +12815,17 @@
         final ArrayMap<String, Pair<Integer, EphemeralResolveInfo>> mOrderResult = new ArrayMap<>();
 
         @Override
-        protected EphemeralResponse[] newArray(int size) {
-            return new EphemeralResponse[size];
+        protected AuxiliaryResolveInfo[] newArray(int size) {
+            return new AuxiliaryResolveInfo[size];
         }
 
         @Override
-        protected boolean isPackageForFilter(String packageName, EphemeralResponse responseObj) {
+        protected boolean isPackageForFilter(String packageName, AuxiliaryResolveInfo responseObj) {
             return true;
         }
 
         @Override
-        protected EphemeralResponse newResult(EphemeralResponse responseObj, int match,
+        protected AuxiliaryResolveInfo newResult(AuxiliaryResolveInfo responseObj, int match,
                 int userId) {
             if (!sUserManager.exists(userId)) {
                 return null;
@@ -12816,7 +12847,7 @@
         }
 
         @Override
-        protected void filterResults(List<EphemeralResponse> results) {
+        protected void filterResults(List<AuxiliaryResolveInfo> results) {
             // only do work if ordering is enabled [most of the time it won't be]
             if (mOrderResult.size() == 0) {
                 return;
@@ -22898,11 +22929,10 @@
         }
 
         @Override
-        public void requestEphemeralResolutionPhaseTwo(EphemeralResponse responseObj,
-                Intent origIntent, String resolvedType, Intent launchIntent,
-                String callingPackage, int userId) {
-            PackageManagerService.this.requestEphemeralResolutionPhaseTwo(
-                    responseObj, origIntent, resolvedType, launchIntent, callingPackage, userId);
+        public void requestInstantAppResolutionPhaseTwo(AuxiliaryResolveInfo responseObj,
+                Intent origIntent, String resolvedType, String callingPackage, int userId) {
+            PackageManagerService.this.requestInstantAppResolutionPhaseTwo(
+                    responseObj, origIntent, resolvedType, callingPackage, userId);
         }
 
         @Override