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