Load splits on-demand

A split may be declared in an application's base manifest, but,
defined in a feature split. When resolving such a component,
invoke the installer to download and install the necessary split(s)

At the moment, this only works for instant apps. However, the
implementation is generic and could be applied to any application.

Bug: 25119046
Test: cts-tradefed run commandAndExit cts-dev -m CtsAppSecurityHostTestCases -t android.appsecurity.cts.EphemeralTest
Change-Id: I6598abb34becfd049fc03199813226736e5057b1
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.