Implement new ephemeral resolver design
am: fea1b776e9
Change-Id: Ied8a583de6247a5d826805dfbb5e8edbecdcdb27
This commit is contained in:
@@ -4313,6 +4313,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
|
||||
|
||||
@@ -67,12 +67,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.
|
||||
*/
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
return new ArrayList<ResolveInfo>();
|
||||
}
|
||||
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);
|
||||
}
|
||||
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);
|
||||
|
||||
Reference in New Issue
Block a user