diff options
4 files changed, 155 insertions, 87 deletions
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 4d9db98587ce..1cf23ae8d040 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -4314,6 +4314,14 @@ public class Intent implements Parcelable, Cloneable { public static final int FLAG_DEBUG_TRIAGED_MISSING = 0x00000100; /** + * Internal flag used to indicate ephemeral applications should not be + * considered when resolving the intent. + * + * @hide + */ + public static final int FLAG_IGNORE_EPHEMERAL = 0x00000200; + + /** * If set, the new activity is not kept in the history stack. As soon as * the user navigates away from it, the activity is finished. This may also * be set with the {@link android.R.styleable#AndroidManifestActivity_noHistory diff --git a/core/java/android/content/pm/ResolveInfo.java b/core/java/android/content/pm/ResolveInfo.java index c9be6edab424..b5df4d75a238 100644 --- a/core/java/android/content/pm/ResolveInfo.java +++ b/core/java/android/content/pm/ResolveInfo.java @@ -68,12 +68,6 @@ public class ResolveInfo implements Parcelable { public EphemeralResolveInfo ephemeralResolveInfo; /** - * A ResolveInfo that points at the ephemeral installer. - * @hide - */ - public ResolveInfo ephemeralInstaller; - - /** * The IntentFilter that was matched for this ResolveInfo. */ public IntentFilter filter; diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java index 525244699082..6c612268331e 100644 --- a/services/core/java/com/android/server/am/ActivityStarter.java +++ b/services/core/java/com/android/server/am/ActivityStarter.java @@ -103,6 +103,7 @@ import android.os.Build; import android.os.Bundle; import android.os.IBinder; import android.os.PowerManagerInternal; +import android.os.Process; import android.os.RemoteException; import android.os.SystemClock; import android.os.UserHandle; @@ -132,6 +133,9 @@ class ActivityStarter { private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION; private static final String TAG_USER_LEAVING = TAG + POSTFIX_USER_LEAVING; + // TODO b/30204367 remove when the platform fully supports ephemeral applications + private static final boolean USE_DEFAULT_EPHEMERAL_LAUNCHER = false; + private final ActivityManagerService mService; private final ActivityStackSupervisor mSupervisor; private ActivityStartInterceptor mInterceptor; @@ -456,39 +460,13 @@ class ActivityStarter { // starts either the intent we resolved here [on install error] or the ephemeral // app [on install success]. if (rInfo != null && rInfo.ephemeralResolveInfo != null) { - // Create a pending intent to start the intent resolved here. - final IIntentSender failureTarget = mService.getIntentSenderLocked( - ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage, - Binder.getCallingUid(), userId, null, null, 0, new Intent[]{ intent }, - new String[]{ resolvedType }, - PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT - | PendingIntent.FLAG_IMMUTABLE, null); - - // Create a pending intent to start the ephemeral application; force it to be - // directed to the ephemeral package. - ephemeralIntent.setPackage(rInfo.ephemeralResolveInfo.getPackageName()); - final IIntentSender ephemeralTarget = mService.getIntentSenderLocked( - ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage, - Binder.getCallingUid(), userId, null, null, 0, new Intent[]{ ephemeralIntent }, - new String[]{ resolvedType }, - PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT - | PendingIntent.FLAG_IMMUTABLE, null); - - int flags = intent.getFlags(); - intent = new Intent(); - intent.setFlags(flags - | Intent.FLAG_ACTIVITY_NEW_TASK - | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); - intent.putExtra(Intent.EXTRA_PACKAGE_NAME, - rInfo.ephemeralResolveInfo.getPackageName()); - intent.putExtra(Intent.EXTRA_EPHEMERAL_FAILURE, new IntentSender(failureTarget)); - intent.putExtra(Intent.EXTRA_EPHEMERAL_SUCCESS, new IntentSender(ephemeralTarget)); - + intent = buildEphemeralInstallerIntent(intent, ephemeralIntent, + rInfo.ephemeralResolveInfo.getPackageName(), callingPackage, resolvedType, + userId); resolvedType = null; callingUid = realCallingUid; callingPid = realCallingPid; - rInfo = rInfo.ephemeralInstaller; aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, null /*profilerInfo*/); } @@ -543,6 +521,60 @@ class ActivityStarter { return err; } + /** + * Builds and returns an intent to launch the ephemeral installer. + */ + private Intent buildEphemeralInstallerIntent(Intent launchIntent, Intent origIntent, + String ephemeralPackage, String callingPackage, String resolvedType, int userId) { + 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. + final IIntentSender failureIntentTarget = mService.getIntentSenderLocked( + ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage, + Binder.getCallingUid(), userId, null /*token*/, null /*resultWho*/, 1, + new Intent[]{ nonEphemeralIntent }, new String[]{ resolvedType }, + PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT + | PendingIntent.FLAG_IMMUTABLE, null /*bOptions*/); + + final Intent ephemeralIntent; + if (USE_DEFAULT_EPHEMERAL_LAUNCHER) { + // Force the intent to be directed to the ephemeral package + ephemeralIntent = new Intent(origIntent); + ephemeralIntent.setPackage(ephemeralPackage); + } else { + // Success intent goes back to the installer + // TODO; do we need any extras for the installer? + ephemeralIntent = new Intent(launchIntent); + ephemeralIntent.setData(null); + } + + // Intent that is eventually launched if the ephemeral package was + // installed successfully. This will actually be launched by a platform + // broadcast receiver. + final IIntentSender successIntentTarget = mService.getIntentSenderLocked( + ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage, + Binder.getCallingUid(), userId, null /*token*/, null /*resultWho*/, 0, + new Intent[]{ ephemeralIntent }, new String[]{ resolvedType }, + PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT + | PendingIntent.FLAG_IMMUTABLE, null /*bOptions*/); + + // Finally build the actual intent to launch the ephemeral installer + int flags = launchIntent.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); + intent.putExtra(Intent.EXTRA_PACKAGE_NAME, ephemeralPackage); + intent.putExtra(Intent.EXTRA_EPHEMERAL_FAILURE, new IntentSender(failureIntentTarget)); + intent.putExtra(Intent.EXTRA_EPHEMERAL_SUCCESS, new IntentSender(successIntentTarget)); + // TODO: Remove when the platform has fully implemented ephemeral apps + intent.setData(origIntent.getData()); + return intent; + } + void postStartActivityUncheckedProcessing( ActivityRecord r, int result, int prevFocusedStackId, ActivityRecord sourceRecord, ActivityStack targetStack) { diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 38b5b149f412..29cbdbb990de 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -177,6 +177,7 @@ import android.os.Looper; import android.os.Message; import android.os.Parcel; import android.os.ParcelFileDescriptor; +import android.os.PatternMatcher; import android.os.Process; import android.os.RemoteCallbackList; import android.os.RemoteException; @@ -4725,20 +4726,6 @@ public class PackageManagerService extends IPackageManager.Stub { final ResolveInfo bestChoice = chooseBestActivity(intent, resolvedType, flags, query, userId); - - if (isEphemeralAllowed(intent, query, userId)) { - Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveEphemeral"); - final EphemeralResolveInfo ai = - getEphemeralResolveInfo(intent, resolvedType, userId); - if (ai != null) { - if (DEBUG_EPHEMERAL) { - Slog.v(TAG, "Returning an EphemeralResolveInfo"); - } - bestChoice.ephemeralInstaller = mEphemeralInstallerInfo; - bestChoice.ephemeralResolveInfo = ai; - } - Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); - } return bestChoice; } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); @@ -4779,9 +4766,9 @@ public class PackageManagerService extends IPackageManager.Stub { false, false, false, userId); } - private boolean isEphemeralAllowed( - Intent intent, List<ResolveInfo> resolvedActivites, int userId) { + Intent intent, List<ResolveInfo> resolvedActivities, int userId, + boolean skipPackageCheck) { // Short circuit and return early if possible. if (DISABLE_EPHEMERAL_APPS) { return false; @@ -4796,18 +4783,21 @@ public class PackageManagerService extends IPackageManager.Stub { if (intent.getComponent() != null) { return false; } - if (intent.getPackage() != null) { + if ((intent.getFlags() & Intent.FLAG_IGNORE_EPHEMERAL) != 0) { + return false; + } + if (!skipPackageCheck && intent.getPackage() != null) { return false; } final boolean isWebUri = hasWebURI(intent); - if (!isWebUri) { + if (!isWebUri || intent.getData().getHost() == null) { return false; } // Deny ephemeral apps if the user chose _ALWAYS or _ALWAYS_ASK for intent resolution. synchronized (mPackages) { - final int count = resolvedActivites.size(); + final int count = (resolvedActivities == null ? 0 : resolvedActivities.size()); for (int n = 0; n < count; n++) { - ResolveInfo info = resolvedActivites.get(n); + ResolveInfo info = resolvedActivities.get(n); String packageName = info.activityInfo.packageName; PackageSetting ps = mSettings.mPackages.get(packageName); if (ps != null) { @@ -4829,19 +4819,19 @@ public class PackageManagerService extends IPackageManager.Stub { return true; } - private EphemeralResolveInfo getEphemeralResolveInfo(Intent intent, String resolvedType, - int userId) { - final int ephemeralPrefixMask = Global.getInt(mContext.getContentResolver(), + private static EphemeralResolveInfo getEphemeralResolveInfo( + Context context, EphemeralResolverConnection resolverConnection, Intent intent, + String resolvedType, int userId, String packageName) { + final int ephemeralPrefixMask = Global.getInt(context.getContentResolver(), Global.EPHEMERAL_HASH_PREFIX_MASK, DEFAULT_EPHEMERAL_HASH_PREFIX_MASK); - final int ephemeralPrefixCount = Global.getInt(mContext.getContentResolver(), + final int ephemeralPrefixCount = Global.getInt(context.getContentResolver(), Global.EPHEMERAL_HASH_PREFIX_COUNT, DEFAULT_EPHEMERAL_HASH_PREFIX_COUNT); final EphemeralDigest digest = new EphemeralDigest(intent.getData(), ephemeralPrefixMask, ephemeralPrefixCount); final int[] shaPrefix = digest.getDigestPrefix(); final byte[][] digestBytes = digest.getDigestBytes(); final List<EphemeralResolveInfo> ephemeralResolveInfoList = - mEphemeralResolverConnection.getEphemeralResolveInfoList( - shaPrefix, ephemeralPrefixMask); + resolverConnection.getEphemeralResolveInfoList(shaPrefix, ephemeralPrefixMask); if (ephemeralResolveInfoList == null || ephemeralResolveInfoList.size() == 0) { // No hash prefix match; there are no ephemeral apps for this domain. return null; @@ -4858,6 +4848,10 @@ public class PackageManagerService extends IPackageManager.Stub { if (filters.isEmpty()) { continue; } + if (packageName != null + && !packageName.equals(ephemeralApplication.getPackageName())) { + continue; + } // We have a domain match; resolve the filters to see if anything matches. final EphemeralIntentResolver ephemeralResolver = new EphemeralIntentResolver(); for (int j = filters.size() - 1; j >= 0; --j) { @@ -5261,8 +5255,12 @@ public class PackageManagerService extends IPackageManager.Stub { } // reader + boolean sortResult = false; + boolean addEphemeral = false; + boolean matchEphemeralPackage = false; + List<ResolveInfo> result; + final String pkgName = intent.getPackage(); synchronized (mPackages) { - final String pkgName = intent.getPackage(); if (pkgName == null) { List<CrossProfileIntentFilter> matchingFilters = getMatchingCrossProfileIntentFilters(intent, resolvedType, userId); @@ -5270,15 +5268,16 @@ public class PackageManagerService extends IPackageManager.Stub { ResolveInfo xpResolveInfo = querySkipCurrentProfileIntents(matchingFilters, intent, resolvedType, flags, userId); if (xpResolveInfo != null) { - List<ResolveInfo> result = new ArrayList<ResolveInfo>(1); - result.add(xpResolveInfo); - return filterIfNotSystemUser(result, userId); + List<ResolveInfo> xpResult = new ArrayList<ResolveInfo>(1); + xpResult.add(xpResolveInfo); + return filterIfNotSystemUser(xpResult, userId); } // Check for results in the current profile. - List<ResolveInfo> result = mActivities.queryIntent( - intent, resolvedType, flags, userId); - result = filterIfNotSystemUser(result, userId); + result = filterIfNotSystemUser(mActivities.queryIntent( + intent, resolvedType, flags, userId), userId); + addEphemeral = + isEphemeralAllowed(intent, result, userId, false /*skipPackageCheck*/); // Check for cross profile results. boolean hasNonNegativePriorityResult = hasNonNegativePriority(result); @@ -5290,7 +5289,7 @@ public class PackageManagerService extends IPackageManager.Stub { Collections.singletonList(xpResolveInfo), userId).size() > 0; if (isVisibleToUser) { result.add(xpResolveInfo); - Collections.sort(result, mResolvePrioritySorter); + sortResult = true; } } if (hasWebURI(intent)) { @@ -5306,28 +5305,61 @@ public class PackageManagerService extends IPackageManager.Stub { // in the result. result.remove(xpResolveInfo); } - if (result.size() == 0) { + if (result.size() == 0 && !addEphemeral) { result.add(xpDomainInfo.resolveInfo); return result; } - } else if (result.size() <= 1) { - return result; } - result = filterCandidatesWithDomainPreferredActivitiesLPr(intent, flags, result, - xpDomainInfo, userId); - Collections.sort(result, mResolvePrioritySorter); + if (result.size() > 1 || addEphemeral) { + result = filterCandidatesWithDomainPreferredActivitiesLPr( + intent, flags, result, xpDomainInfo, userId); + sortResult = true; + } + } + } else { + final PackageParser.Package pkg = mPackages.get(pkgName); + if (pkg != null) { + result = filterIfNotSystemUser( + mActivities.queryIntentForPackage( + intent, resolvedType, flags, pkg.activities, userId), + userId); + } else { + // the caller wants to resolve for a particular package; however, there + // were no installed results, so, try to find an ephemeral result + addEphemeral = isEphemeralAllowed( + intent, null /*result*/, userId, true /*skipPackageCheck*/); + matchEphemeralPackage = true; + result = new ArrayList<ResolveInfo>(); } - return result; } - final PackageParser.Package pkg = mPackages.get(pkgName); - if (pkg != null) { - return filterIfNotSystemUser( - mActivities.queryIntentForPackage( - intent, resolvedType, flags, pkg.activities, userId), - userId); + } + if (addEphemeral) { + Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveEphemeral"); + final EphemeralResolveInfo ai = getEphemeralResolveInfo( + mContext, mEphemeralResolverConnection, intent, resolvedType, userId, + matchEphemeralPackage ? pkgName : null); + if (ai != null) { + if (DEBUG_EPHEMERAL) { + Slog.v(TAG, "Adding ephemeral installer to the ResolveInfo list"); + } + final ResolveInfo ephemeralInstaller = new ResolveInfo(mEphemeralInstallerInfo); + ephemeralInstaller.ephemeralResolveInfo = ai; + // make sure this resolver is the default + ephemeralInstaller.isDefault = true; + ephemeralInstaller.match = IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART + | IntentFilter.MATCH_ADJUSTMENT_NORMAL; + // add a non-generic filter + ephemeralInstaller.filter = new IntentFilter(intent.getAction()); + ephemeralInstaller.filter.addDataPath( + intent.getData().getPath(), PatternMatcher.PATTERN_LITERAL); + result.add(ephemeralInstaller); } - return new ArrayList<ResolveInfo>(); + Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); + } + if (sortResult) { + Collections.sort(result, mResolvePrioritySorter); } + return result; } private static class CrossProfileDomainInfo { @@ -9205,15 +9237,17 @@ public class PackageManagerService extends IPackageManager.Stub { mEphemeralInstallerActivity.packageName = pkg.applicationInfo.packageName; mEphemeralInstallerActivity.processName = pkg.applicationInfo.packageName; mEphemeralInstallerActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE; - mEphemeralInstallerActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS | - ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS; + mEphemeralInstallerActivity.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 = 0; - mEphemeralInstallerInfo.match = 0; + mEphemeralInstallerInfo.preferredOrder = 1; + mEphemeralInstallerInfo.isDefault = true; + mEphemeralInstallerInfo.match = IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART + | IntentFilter.MATCH_ADJUSTMENT_NORMAL; if (DEBUG_EPHEMERAL) { Slog.d(TAG, "Set ephemeral installer activity: " + mEphemeralInstallerComponent); |