Revert "Revert "Adds generic intent Instant App resolution""

This reverts commit 860b8ba719.

The original change that was reverted contained a bug that allowed an
http view/browsable intent used to query for browsers to be considered
as a candidate for instant apps. This was resulting in an attempt to
bind to the instant app resolver while holding a lock on mPackages.

This change ensures that PMS doesn't bind while checking for the browser
status of a package in both the instant app filtering code and by adding
the FLAG_IGNORE_EPHEMERAL to the canonical browser intent.

Reason for revert: Applying fix

Change-Id: I4896b3a15416a11fdc3f6c191e552c4ce8963623
Fixes: 63117034
Fixes: 71916178
Test: Manual using test app at google_experimental/users/patb/InstantAppsInP
Test: atest android.appsecurity.cts.EphemeralTest passes after modification
This commit is contained in:
Patrick Baumann
2018-01-31 16:55:10 +00:00
parent 64dd7468f3
commit 577d402d0d
14 changed files with 647 additions and 325 deletions

View File

@@ -10050,6 +10050,7 @@ package android.content {
field public static final int FLAG_ACTIVITY_FORWARD_RESULT = 33554432; // 0x2000000
field public static final int FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY = 1048576; // 0x100000
field public static final int FLAG_ACTIVITY_LAUNCH_ADJACENT = 4096; // 0x1000
field public static final int FLAG_ACTIVITY_MATCH_EXTERNAL = 2048; // 0x800
field public static final int FLAG_ACTIVITY_MULTIPLE_TASK = 134217728; // 0x8000000
field public static final int FLAG_ACTIVITY_NEW_DOCUMENT = 524288; // 0x80000
field public static final int FLAG_ACTIVITY_NEW_TASK = 268435456; // 0x10000000

View File

@@ -311,8 +311,10 @@ package android.app {
ctor public InstantAppResolverService();
method public final void attachBaseContext(android.content.Context);
method public final android.os.IBinder onBind(android.content.Intent);
method public void onGetInstantAppIntentFilter(int[], java.lang.String, android.app.InstantAppResolverService.InstantAppResolutionCallback);
method public void onGetInstantAppResolveInfo(int[], java.lang.String, android.app.InstantAppResolverService.InstantAppResolutionCallback);
method public deprecated void onGetInstantAppIntentFilter(int[], java.lang.String, android.app.InstantAppResolverService.InstantAppResolutionCallback);
method public void onGetInstantAppIntentFilter(android.content.Intent, int[], java.lang.String, android.app.InstantAppResolverService.InstantAppResolutionCallback);
method public deprecated void onGetInstantAppResolveInfo(int[], java.lang.String, android.app.InstantAppResolverService.InstantAppResolutionCallback);
method public void onGetInstantAppResolveInfo(android.content.Intent, int[], java.lang.String, android.app.InstantAppResolverService.InstantAppResolutionCallback);
}
public static final class InstantAppResolverService.InstantAppResolutionCallback {
@@ -821,12 +823,14 @@ package android.content {
field public static final java.lang.String ACTION_VOICE_ASSIST = "android.intent.action.VOICE_ASSIST";
field public static final java.lang.String CATEGORY_LEANBACK_SETTINGS = "android.intent.category.LEANBACK_SETTINGS";
field public static final java.lang.String EXTRA_FORCE_FACTORY_RESET = "android.intent.extra.FORCE_FACTORY_RESET";
field public static final java.lang.String EXTRA_INSTANT_APP_BUNDLES = "android.intent.extra.INSTANT_APP_BUNDLES";
field public static final java.lang.String EXTRA_ORIGINATING_UID = "android.intent.extra.ORIGINATING_UID";
field public static final java.lang.String EXTRA_PACKAGES = "android.intent.extra.PACKAGES";
field public static final java.lang.String EXTRA_PERMISSION_NAME = "android.intent.extra.PERMISSION_NAME";
field public static final java.lang.String EXTRA_REASON = "android.intent.extra.REASON";
field public static final java.lang.String EXTRA_REMOTE_CALLBACK = "android.intent.extra.REMOTE_CALLBACK";
field public static final java.lang.String EXTRA_RESULT_NEEDED = "android.intent.extra.RESULT_NEEDED";
field public static final java.lang.String EXTRA_UNKNOWN_INSTANT_APP = "android.intent.extra.UNKNOWN_INSTANT_APP";
}
public class IntentFilter implements android.os.Parcelable {
@@ -869,6 +873,7 @@ package android.content.pm {
ctor public InstantAppResolveInfo(android.content.pm.InstantAppResolveInfo.InstantAppDigest, java.lang.String, java.util.List<android.content.pm.InstantAppIntentFilter>, int);
ctor public InstantAppResolveInfo(android.content.pm.InstantAppResolveInfo.InstantAppDigest, java.lang.String, java.util.List<android.content.pm.InstantAppIntentFilter>, long, android.os.Bundle);
ctor public InstantAppResolveInfo(java.lang.String, java.lang.String, java.util.List<android.content.pm.InstantAppIntentFilter>);
ctor public InstantAppResolveInfo(android.os.Bundle);
method public int describeContents();
method public byte[] getDigestBytes();
method public int getDigestPrefix();
@@ -877,6 +882,7 @@ package android.content.pm {
method public long getLongVersionCode();
method public java.lang.String getPackageName();
method public deprecated int getVersionCode();
method public boolean shouldLetInstallerDecide();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.content.pm.InstantAppResolveInfo> CREATOR;
}
@@ -888,6 +894,7 @@ package android.content.pm {
method public int[] getDigestPrefix();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.content.pm.InstantAppResolveInfo.InstantAppDigest> CREATOR;
field public static final android.content.pm.InstantAppResolveInfo.InstantAppDigest UNDEFINED;
}
public final class IntentFilterVerificationInfo implements android.os.Parcelable {

View File

@@ -17,20 +17,10 @@
package android.app;
import android.annotation.SystemApi;
import android.app.Service;
import android.app.InstantAppResolverService.InstantAppResolutionCallback;
import android.content.Context;
import android.content.Intent;
import android.content.pm.EphemeralResolveInfo;
import android.content.pm.InstantAppResolveInfo;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.IRemoteCallback;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.util.Log;
import java.util.ArrayList;
@@ -85,7 +75,6 @@ public abstract class EphemeralResolverService extends InstantAppResolverService
return super.getLooper();
}
@Override
void _onGetInstantAppResolveInfo(int[] digestPrefix, String token,
InstantAppResolutionCallback callback) {
if (DEBUG_EPHEMERAL) {
@@ -101,7 +90,6 @@ public abstract class EphemeralResolverService extends InstantAppResolverService
callback.onInstantAppResolveInfo(resultList);
}
@Override
void _onGetInstantAppIntentFilter(int[] digestPrefix, String token,
String hostName, InstantAppResolutionCallback callback) {
if (DEBUG_EPHEMERAL) {

View File

@@ -16,13 +16,15 @@
package android.app;
import android.content.Intent;
import android.os.IRemoteCallback;
/** @hide */
oneway interface IInstantAppResolver {
void getInstantAppResolveInfoList(in int[] digestPrefix,
void getInstantAppResolveInfoList(in Intent sanitizedIntent, in int[] hostDigestPrefix,
String token, int sequence, IRemoteCallback callback);
void getInstantAppIntentFilterList(in int[] digestPrefix,
String token, String hostName, IRemoteCallback callback);
void getInstantAppIntentFilterList(in Intent sanitizedIntent, in int[] hostDigestPrefix,
String token, IRemoteCallback callback);
}

View File

@@ -17,7 +17,6 @@
package android.app;
import android.annotation.SystemApi;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.pm.InstantAppResolveInfo;
@@ -35,6 +34,7 @@ import android.util.Slog;
import com.android.internal.os.SomeArgs;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
@@ -53,23 +53,65 @@ public abstract class InstantAppResolverService extends Service {
Handler mHandler;
/**
* Called to retrieve resolve info for instant applications.
* Called to retrieve resolve info for instant applications immediately.
*
* @param digestPrefix The hash prefix of the instant app's domain.
* @deprecated should implement {@link #onGetInstantAppResolveInfo(Intent, int[], String,
* InstantAppResolutionCallback)}
*/
@Deprecated
public void onGetInstantAppResolveInfo(
int digestPrefix[], String token, InstantAppResolutionCallback callback) {
throw new IllegalStateException("Must define");
}
/**
* Called to retrieve intent filters for instant applications.
* Called to retrieve intent filters for instant applications from potentially expensive
* sources.
*
* @param digestPrefix The hash prefix of the instant app's domain.
* @deprecated should implement {@link #onGetInstantAppIntentFilter(Intent, int[], String,
* InstantAppResolutionCallback)}
*/
@Deprecated
public void onGetInstantAppIntentFilter(
int digestPrefix[], String token, InstantAppResolutionCallback callback) {
throw new IllegalStateException("Must define");
throw new IllegalStateException("Must define onGetInstantAppIntentFilter");
}
/**
* Called to retrieve resolve info for instant applications immediately.
*
* @param sanitizedIntent The sanitized {@link Intent} used for resolution.
* @param hostDigestPrefix The hash prefix of the instant app's domain.
*/
public void onGetInstantAppResolveInfo(Intent sanitizedIntent, int[] hostDigestPrefix,
String token, InstantAppResolutionCallback callback) {
// if not overridden, forward to old methods and filter out non-web intents
if (sanitizedIntent.isBrowsableWebIntent()) {
onGetInstantAppResolveInfo(hostDigestPrefix, token, callback);
} else {
callback.onInstantAppResolveInfo(Collections.emptyList());
}
}
/**
* Called to retrieve intent filters for instant applications from potentially expensive
* sources.
*
* @param sanitizedIntent The sanitized {@link Intent} used for resolution.
* @param hostDigestPrefix The hash prefix of the instant app's domain or null if no host is
* defined.
*/
public void onGetInstantAppIntentFilter(Intent sanitizedIntent, int[] hostDigestPrefix,
String token, InstantAppResolutionCallback callback) {
Log.e(TAG, "New onGetInstantAppIntentFilter is not overridden");
// if not overridden, forward to old methods and filter out non-web intents
if (sanitizedIntent.isBrowsableWebIntent()) {
onGetInstantAppIntentFilter(hostDigestPrefix, token, callback);
} else {
callback.onInstantAppResolveInfo(Collections.emptyList());
}
}
/**
@@ -89,8 +131,8 @@ public abstract class InstantAppResolverService extends Service {
public final IBinder onBind(Intent intent) {
return new IInstantAppResolver.Stub() {
@Override
public void getInstantAppResolveInfoList(
int digestPrefix[], String token, int sequence, IRemoteCallback callback) {
public void getInstantAppResolveInfoList(Intent sanitizedIntent, int[] digestPrefix,
String token, int sequence, IRemoteCallback callback) {
if (DEBUG_EPHEMERAL) {
Slog.v(TAG, "[" + token + "] Phase1 called; posting");
}
@@ -98,14 +140,14 @@ public abstract class InstantAppResolverService extends Service {
args.arg1 = callback;
args.arg2 = digestPrefix;
args.arg3 = token;
mHandler.obtainMessage(
ServiceHandler.MSG_GET_INSTANT_APP_RESOLVE_INFO, sequence, 0, args)
.sendToTarget();
args.arg4 = sanitizedIntent;
mHandler.obtainMessage(ServiceHandler.MSG_GET_INSTANT_APP_RESOLVE_INFO,
sequence, 0, args).sendToTarget();
}
@Override
public void getInstantAppIntentFilterList(
int digestPrefix[], String token, String hostName, IRemoteCallback callback) {
public void getInstantAppIntentFilterList(Intent sanitizedIntent,
int[] digestPrefix, String token, IRemoteCallback callback) {
if (DEBUG_EPHEMERAL) {
Slog.v(TAG, "[" + token + "] Phase2 called; posting");
}
@@ -113,9 +155,9 @@ public abstract class InstantAppResolverService extends Service {
args.arg1 = callback;
args.arg2 = digestPrefix;
args.arg3 = token;
args.arg4 = hostName;
mHandler.obtainMessage(
ServiceHandler.MSG_GET_INSTANT_APP_INTENT_FILTER, callback).sendToTarget();
args.arg4 = sanitizedIntent;
mHandler.obtainMessage(ServiceHandler.MSG_GET_INSTANT_APP_INTENT_FILTER,
callback).sendToTarget();
}
};
}
@@ -142,29 +184,9 @@ public abstract class InstantAppResolverService extends Service {
}
}
@Deprecated
void _onGetInstantAppResolveInfo(int[] digestPrefix, String token,
InstantAppResolutionCallback callback) {
if (DEBUG_EPHEMERAL) {
Slog.d(TAG, "[" + token + "] Phase1 request;"
+ " prefix: " + Arrays.toString(digestPrefix));
}
onGetInstantAppResolveInfo(digestPrefix, token, callback);
}
@Deprecated
void _onGetInstantAppIntentFilter(int digestPrefix[], String token, String hostName,
InstantAppResolutionCallback callback) {
if (DEBUG_EPHEMERAL) {
Slog.d(TAG, "[" + token + "] Phase2 request;"
+ " prefix: " + Arrays.toString(digestPrefix));
}
onGetInstantAppIntentFilter(digestPrefix, token, callback);
}
private final class ServiceHandler extends Handler {
public static final int MSG_GET_INSTANT_APP_RESOLVE_INFO = 1;
public static final int MSG_GET_INSTANT_APP_INTENT_FILTER = 2;
public ServiceHandler(Looper looper) {
super(looper, null /*callback*/, true /*async*/);
}
@@ -179,9 +201,13 @@ public abstract class InstantAppResolverService extends Service {
final IRemoteCallback callback = (IRemoteCallback) args.arg1;
final int[] digestPrefix = (int[]) args.arg2;
final String token = (String) args.arg3;
final Intent intent = (Intent) args.arg4;
final int sequence = message.arg1;
_onGetInstantAppResolveInfo(
digestPrefix, token,
if (DEBUG_EPHEMERAL) {
Slog.d(TAG, "[" + token + "] Phase1 request;"
+ " prefix: " + Arrays.toString(digestPrefix));
}
onGetInstantAppResolveInfo(intent, digestPrefix, token,
new InstantAppResolutionCallback(sequence, callback));
} break;
@@ -190,9 +216,12 @@ public abstract class InstantAppResolverService extends Service {
final IRemoteCallback callback = (IRemoteCallback) args.arg1;
final int[] digestPrefix = (int[]) args.arg2;
final String token = (String) args.arg3;
final String hostName = (String) args.arg4;
_onGetInstantAppIntentFilter(
digestPrefix, token, hostName,
final Intent intent = (Intent) args.arg4;
if (DEBUG_EPHEMERAL) {
Slog.d(TAG, "[" + token + "] Phase2 request;"
+ " prefix: " + Arrays.toString(digestPrefix));
}
onGetInstantAppIntentFilter(intent, digestPrefix, token,
new InstantAppResolutionCallback(-1 /*sequence*/, callback));
} break;

View File

@@ -50,6 +50,7 @@ import android.provider.DocumentsContract;
import android.provider.DocumentsProvider;
import android.provider.MediaStore;
import android.provider.OpenableColumns;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.AttributeSet;
import android.util.Log;
@@ -4472,7 +4473,15 @@ public class Intent implements Parcelable, Cloneable {
public static final String EXTRA_INSTANT_APP_ACTION = "android.intent.extra.INSTANT_APP_ACTION";
/**
* A {@link Bundle} of metadata that describes the instanta application that needs to be
* An array of {@link Bundle}s containing details about resolved instant apps..
* @hide
*/
@SystemApi
public static final String EXTRA_INSTANT_APP_BUNDLES =
"android.intent.extra.INSTANT_APP_BUNDLES";
/**
* A {@link Bundle} of metadata that describes the instant application that needs to be
* installed. This data is populated from the response to
* {@link android.content.pm.InstantAppResolveInfo#getExtras()} as provided by the registered
* instant application resolver.
@@ -4481,6 +4490,16 @@ public class Intent implements Parcelable, Cloneable {
public static final String EXTRA_INSTANT_APP_EXTRAS =
"android.intent.extra.INSTANT_APP_EXTRAS";
/**
* A boolean value indicating that the instant app resolver was unable to state with certainty
* that it did or did not have an app for the sanitized {@link Intent} defined at
* {@link #EXTRA_INTENT}.
* @hide
*/
@SystemApi
public static final String EXTRA_UNKNOWN_INSTANT_APP =
"android.intent.extra.UNKNOWN_INSTANT_APP";
/**
* The version code of the app to install components from.
* @deprecated Use {@link #EXTRA_LONG_VERSION_CODE).
@@ -5029,6 +5048,7 @@ public class Intent implements Parcelable, Cloneable {
FLAG_GRANT_PREFIX_URI_PERMISSION,
FLAG_DEBUG_TRIAGED_MISSING,
FLAG_IGNORE_EPHEMERAL,
FLAG_ACTIVITY_MATCH_EXTERNAL,
FLAG_ACTIVITY_NO_HISTORY,
FLAG_ACTIVITY_SINGLE_TOP,
FLAG_ACTIVITY_NEW_TASK,
@@ -5072,6 +5092,7 @@ public class Intent implements Parcelable, Cloneable {
FLAG_INCLUDE_STOPPED_PACKAGES,
FLAG_DEBUG_TRIAGED_MISSING,
FLAG_IGNORE_EPHEMERAL,
FLAG_ACTIVITY_MATCH_EXTERNAL,
FLAG_ACTIVITY_NO_HISTORY,
FLAG_ACTIVITY_SINGLE_TOP,
FLAG_ACTIVITY_NEW_TASK,
@@ -5475,6 +5496,14 @@ public class Intent implements Parcelable, Cloneable {
*/
public static final int FLAG_ACTIVITY_LAUNCH_ADJACENT = 0x00001000;
/**
* If set, resolution of this intent may take place via an instant app not
* yet on the device if there does not yet exist an app on device to
* resolve it.
*/
public static final int FLAG_ACTIVITY_MATCH_EXTERNAL = 0x00000800;
/**
* If set, when sending a broadcast only registered receivers will be
* called -- no BroadcastReceiver components will be launched.
@@ -10028,6 +10057,25 @@ public class Intent implements Parcelable, Cloneable {
}
}
/** @hide */
public boolean hasWebURI() {
if (getData() == null) {
return false;
}
final String scheme = getScheme();
if (TextUtils.isEmpty(scheme)) {
return false;
}
return scheme.equals(IntentFilter.SCHEME_HTTP) || scheme.equals(IntentFilter.SCHEME_HTTPS);
}
/** @hide */
public boolean isBrowsableWebIntent() {
return ACTION_VIEW.equals(mAction)
&& hasCategory(CATEGORY_BROWSABLE)
&& hasWebURI();
}
/**
* @hide
*/

View File

@@ -21,6 +21,10 @@ import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import java.util.Collections;
import java.util.List;
/**
* Auxiliary application resolution response.
@@ -31,56 +35,95 @@ import android.content.IntentFilter;
* hasn't been installed.
* @hide
*/
public final class AuxiliaryResolveInfo extends IntentFilter {
/** Resolved information returned from the external instant resolver */
public final InstantAppResolveInfo resolveInfo;
/** The resolved package. Copied from {@link #resolveInfo}. */
public final String packageName;
public final class AuxiliaryResolveInfo {
/** The activity to launch if there's an installation failure. */
public final ComponentName installFailureActivity;
/** The resolve split. Copied from the matched filter in {@link #resolveInfo}. */
public final String splitName;
/** Whether or not instant resolution needs the second phase */
public final boolean needsPhaseTwo;
/** Opaque token to track the instant application resolution */
public final String token;
/** The version code of the package */
public final long versionCode;
/** An intent to start upon failure to install */
public final Intent failureIntent;
/** The matching filters for this resolve info. */
public final List<AuxiliaryFilter> filters;
/** Create a response for installing an instant application. */
public AuxiliaryResolveInfo(@NonNull InstantAppResolveInfo resolveInfo,
@NonNull IntentFilter orig,
@Nullable String splitName,
@NonNull String token,
public AuxiliaryResolveInfo(@NonNull String token,
boolean needsPhase2,
@Nullable Intent failureIntent) {
super(orig);
this.resolveInfo = resolveInfo;
this.packageName = resolveInfo.getPackageName();
this.splitName = splitName;
@Nullable Intent failureIntent,
@Nullable List<AuxiliaryFilter> filters) {
this.token = token;
this.needsPhaseTwo = needsPhase2;
this.versionCode = resolveInfo.getVersionCode();
this.failureIntent = failureIntent;
this.filters = filters;
this.installFailureActivity = null;
}
/** Create a response for installing a split on demand. */
public AuxiliaryResolveInfo(@NonNull String packageName,
@Nullable String splitName,
@Nullable ComponentName failureActivity,
long versionCode,
@Nullable Intent failureIntent) {
public AuxiliaryResolveInfo(@Nullable ComponentName failureActivity,
@Nullable Intent failureIntent,
@Nullable List<AuxiliaryFilter> filters) {
super();
this.packageName = packageName;
this.installFailureActivity = failureActivity;
this.splitName = splitName;
this.versionCode = versionCode;
this.resolveInfo = null;
this.filters = filters;
this.token = null;
this.needsPhaseTwo = false;
this.failureIntent = failureIntent;
}
/** Create a response for installing a split on demand. */
public AuxiliaryResolveInfo(@Nullable ComponentName failureActivity,
String packageName, long versionCode, String splitName) {
this(failureActivity, null, Collections.singletonList(
new AuxiliaryResolveInfo.AuxiliaryFilter(packageName, versionCode, splitName)));
}
/** @hide */
public static final class AuxiliaryFilter extends IntentFilter {
/** Resolved information returned from the external instant resolver */
public final InstantAppResolveInfo resolveInfo;
/** The resolved package. Copied from {@link #resolveInfo}. */
public final String packageName;
/** The version code of the package */
public final long versionCode;
/** The resolve split. Copied from the matched filter in {@link #resolveInfo}. */
public final String splitName;
/** The extras to pass on to the installer for this filter. */
public final Bundle extras;
public AuxiliaryFilter(IntentFilter orig, InstantAppResolveInfo resolveInfo,
String splitName, Bundle extras) {
super(orig);
this.resolveInfo = resolveInfo;
this.packageName = resolveInfo.getPackageName();
this.versionCode = resolveInfo.getLongVersionCode();
this.splitName = splitName;
this.extras = extras;
}
public AuxiliaryFilter(InstantAppResolveInfo resolveInfo,
String splitName, Bundle extras) {
this.resolveInfo = resolveInfo;
this.packageName = resolveInfo.getPackageName();
this.versionCode = resolveInfo.getLongVersionCode();
this.splitName = splitName;
this.extras = extras;
}
public AuxiliaryFilter(String packageName, long versionCode, String splitName) {
this.resolveInfo = null;
this.packageName = packageName;
this.versionCode = versionCode;
this.splitName = splitName;
this.extras = null;
}
@Override
public String toString() {
return "AuxiliaryFilter{"
+ "packageName='" + packageName + '\''
+ ", versionCode=" + versionCode
+ ", splitName='" + splitName + '\'' + '}';
}
}
}

View File

@@ -19,6 +19,7 @@ package android.content.pm;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.content.Intent;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -26,11 +27,35 @@ import android.os.Parcelable;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
/**
* Information about an instant application.
* Describes an externally resolvable instant application. There are three states that this class
* can represent: <p/>
* <ul>
* <li>
* The first, usable only for non http/s intents, implies that the resolver cannot
* immediately resolve this intent and would prefer that resolution be deferred to the
* instant app installer. Represent this state with {@link #InstantAppResolveInfo(Bundle)}.
* If the {@link android.content.Intent} has the scheme set to http/s and a set of digest
* prefixes were passed into one of the resolve methods in
* {@link android.app.InstantAppResolverService}, this state cannot be used.
* </li>
* <li>
* The second represents a partial match and is constructed with any of the other
* constructors. By setting one or more of the {@link Nullable}arguments to null, you
* communicate to the resolver in response to
* {@link android.app.InstantAppResolverService#onGetInstantAppResolveInfo(Intent, int[],
* String, InstantAppResolverService.InstantAppResolutionCallback)}
* that you need a 2nd round of resolution to complete the request.
* </li>
* <li>
* The third represents a complete match and is constructed with all @Nullable parameters
* populated.
* </li>
* </ul>
* @hide
*/
@SystemApi
@@ -38,6 +63,8 @@ public final class InstantAppResolveInfo implements Parcelable {
/** Algorithm that will be used to generate the domain digest */
private static final String SHA_ALGORITHM = "SHA-256";
private static final byte[] EMPTY_DIGEST = new byte[0];
private final InstantAppDigest mDigest;
private final String mPackageName;
/** The filters used to match domain */
@@ -46,15 +73,30 @@ public final class InstantAppResolveInfo implements Parcelable {
private final long mVersionCode;
/** Data about the app that should be passed along to the Instant App installer on resolve */
private final Bundle mExtras;
/**
* A flag that indicates that the resolver is aware that an app may match, but would prefer
* that the installer get the sanitized intent to decide. This should not be used for
* resolutions that include a host and will be ignored in such cases.
*/
private final boolean mShouldLetInstallerDecide;
/** Constructor for intent-based InstantApp resolution results. */
public InstantAppResolveInfo(@NonNull InstantAppDigest digest, @Nullable String packageName,
@Nullable List<InstantAppIntentFilter> filters, int versionCode) {
this(digest, packageName, filters, (long) versionCode, null /* extras */);
}
/** Constructor for intent-based InstantApp resolution results with extras. */
public InstantAppResolveInfo(@NonNull InstantAppDigest digest, @Nullable String packageName,
@Nullable List<InstantAppIntentFilter> filters, long versionCode,
@Nullable Bundle extras) {
this(digest, packageName, filters, versionCode, extras, false);
}
/** Constructor for intent-based InstantApp resolution results with extras. */
private InstantAppResolveInfo(@NonNull InstantAppDigest digest, @Nullable String packageName,
@Nullable List<InstantAppIntentFilter> filters, long versionCode,
@Nullable Bundle extras, boolean shouldLetInstallerDecide) {
// validate arguments
if ((packageName == null && (filters != null && filters.size() != 0))
|| (packageName != null && (filters == null || filters.size() == 0))) {
@@ -62,7 +104,7 @@ public final class InstantAppResolveInfo implements Parcelable {
}
mDigest = digest;
if (filters != null) {
mFilters = new ArrayList<InstantAppIntentFilter>(filters.size());
mFilters = new ArrayList<>(filters.size());
mFilters.addAll(filters);
} else {
mFilters = null;
@@ -70,25 +112,48 @@ public final class InstantAppResolveInfo implements Parcelable {
mPackageName = packageName;
mVersionCode = versionCode;
mExtras = extras;
mShouldLetInstallerDecide = shouldLetInstallerDecide;
}
/** Constructor for intent-based InstantApp resolution results by hostname. */
public InstantAppResolveInfo(@NonNull String hostName, @Nullable String packageName,
@Nullable List<InstantAppIntentFilter> filters) {
this(new InstantAppDigest(hostName), packageName, filters, -1 /*versionCode*/,
null /* extras */);
}
/**
* Constructor that creates a "let the installer decide" response with optional included
* extras.
*/
public InstantAppResolveInfo(@Nullable Bundle extras) {
this(InstantAppDigest.UNDEFINED, null, null, -1, extras, true);
}
InstantAppResolveInfo(Parcel in) {
mDigest = in.readParcelable(null /*loader*/);
mPackageName = in.readString();
mFilters = new ArrayList<InstantAppIntentFilter>();
in.readList(mFilters, null /*loader*/);
mVersionCode = in.readLong();
mShouldLetInstallerDecide = in.readBoolean();
mExtras = in.readBundle();
if (mShouldLetInstallerDecide) {
mDigest = InstantAppDigest.UNDEFINED;
mPackageName = null;
mFilters = Collections.emptyList();
mVersionCode = -1;
} else {
mDigest = in.readParcelable(null /*loader*/);
mPackageName = in.readString();
mFilters = new ArrayList<>();
in.readList(mFilters, null /*loader*/);
mVersionCode = in.readLong();
}
}
/** Returns true if the installer should be notified that it should query for packages. */
public boolean shouldLetInstallerDecide() {
return mShouldLetInstallerDecide;
}
public byte[] getDigestBytes() {
return mDigest.getDigestBytes()[0];
return mDigest.mDigestBytes.length > 0 ? mDigest.getDigestBytes()[0] : EMPTY_DIGEST;
}
public int getDigestPrefix() {
@@ -127,11 +192,15 @@ public final class InstantAppResolveInfo implements Parcelable {
@Override
public void writeToParcel(Parcel out, int flags) {
out.writeBoolean(mShouldLetInstallerDecide);
out.writeBundle(mExtras);
if (mShouldLetInstallerDecide) {
return;
}
out.writeParcelable(mDigest, flags);
out.writeString(mPackageName);
out.writeList(mFilters);
out.writeLong(mVersionCode);
out.writeBundle(mExtras);
}
public static final Parcelable.Creator<InstantAppResolveInfo> CREATOR
@@ -159,7 +228,9 @@ public final class InstantAppResolveInfo implements Parcelable {
@SystemApi
public static final class InstantAppDigest implements Parcelable {
private static final int DIGEST_MASK = 0xfffff000;
private static final int DIGEST_PREFIX_COUNT = 5;
public static final InstantAppDigest UNDEFINED =
new InstantAppDigest(new byte[][]{}, new int[]{});
/** Full digest of the domain hashes */
private final byte[][] mDigestBytes;
/** The first 4 bytes of the domain hashes */
@@ -186,6 +257,11 @@ public final class InstantAppResolveInfo implements Parcelable {
}
}
private InstantAppDigest(byte[][] digestBytes, int[] prefix) {
this.mDigestPrefix = prefix;
this.mDigestBytes = digestBytes;
}
private static byte[][] generateDigest(String hostName, int maxDigests) {
ArrayList<byte[]> digests = new ArrayList<>();
try {

View File

@@ -103,11 +103,14 @@ public class ResolverListController {
List<ResolverActivity.ResolvedComponentInfo> resolvedComponents = null;
for (int i = 0, N = intents.size(); i < N; i++) {
final Intent intent = intents.get(i);
final List<ResolveInfo> infos = mpm.queryIntentActivities(intent,
PackageManager.MATCH_DEFAULT_ONLY
| (shouldGetResolvedFilter ? PackageManager.GET_RESOLVED_FILTER : 0)
| (shouldGetActivityMetadata ? PackageManager.GET_META_DATA : 0)
| PackageManager.MATCH_INSTANT);
int flags = PackageManager.MATCH_DEFAULT_ONLY
| (shouldGetResolvedFilter ? PackageManager.GET_RESOLVED_FILTER : 0)
| (shouldGetActivityMetadata ? PackageManager.GET_META_DATA : 0);
if (intent.isBrowsableWebIntent()
|| (intent.getFlags() & Intent.FLAG_ACTIVITY_MATCH_EXTERNAL) != 0) {
flags |= PackageManager.MATCH_INSTANT;
}
final List<ResolveInfo> infos = mpm.queryIntentActivities(intent, flags);
// Remove any activities that are not exported.
int totalSize = infos.size();
for (int j = totalSize - 1; j >= 0 ; j--) {

View File

@@ -1251,10 +1251,14 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
synchronized (mService) {
try {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "resolveIntent");
int modifiedFlags = flags
| PackageManager.MATCH_DEFAULT_ONLY | ActivityManagerService.STOCK_PM_FLAGS;
if (intent.isBrowsableWebIntent()
|| (intent.getFlags() & Intent.FLAG_ACTIVITY_MATCH_EXTERNAL) != 0) {
modifiedFlags |= PackageManager.MATCH_INSTANT;
}
return mService.getPackageManagerInternalLocked().resolveIntent(
intent, resolvedType, PackageManager.MATCH_INSTANT
| PackageManager.MATCH_DEFAULT_ONLY | flags
| ActivityManagerService.STOCK_PM_FLAGS, userId, true);
intent, resolvedType, modifiedFlags, userId, true);
} finally {
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);

View File

@@ -31,6 +31,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.Intent.ACTION_INSTALL_INSTANT_APP_PACKAGE;
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
import static android.content.Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT;
@@ -789,7 +790,7 @@ class ActivityStarter {
// 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.auxiliaryInfo != null) {
if (rInfo != null && rInfo.isInstantAppAvailable) {
intent = createLaunchIntent(rInfo.auxiliaryInfo, ephemeralIntent,
callingPackage, verificationBundle, resolvedType, userId);
resolvedType = null;
@@ -849,22 +850,27 @@ class ActivityStarter {
/**
* Creates a launch intent for the given auxiliary resolution data.
*/
private @NonNull Intent createLaunchIntent(@NonNull AuxiliaryResolveInfo auxiliaryResponse,
private @NonNull Intent createLaunchIntent(@Nullable AuxiliaryResolveInfo auxiliaryResponse,
Intent originalIntent, String callingPackage, Bundle verificationBundle,
String resolvedType, int userId) {
if (auxiliaryResponse.needsPhaseTwo) {
if (auxiliaryResponse != null && auxiliaryResponse.needsPhaseTwo) {
// request phase two resolution
mService.getPackageManagerInternalLocked().requestInstantAppResolutionPhaseTwo(
auxiliaryResponse, originalIntent, resolvedType, callingPackage,
verificationBundle, userId);
}
return InstantAppResolver.buildEphemeralInstallerIntent(
Intent.ACTION_INSTALL_INSTANT_APP_PACKAGE, originalIntent,
auxiliaryResponse.failureIntent, callingPackage, verificationBundle,
resolvedType, userId, auxiliaryResponse.packageName, auxiliaryResponse.splitName,
auxiliaryResponse.installFailureActivity, auxiliaryResponse.versionCode,
auxiliaryResponse.token, auxiliaryResponse.resolveInfo.getExtras(),
auxiliaryResponse.needsPhaseTwo);
originalIntent,
InstantAppResolver.sanitizeIntent(originalIntent),
auxiliaryResponse == null ? null : auxiliaryResponse.failureIntent,
callingPackage,
verificationBundle,
resolvedType,
userId,
auxiliaryResponse == null ? null : auxiliaryResponse.installFailureActivity,
auxiliaryResponse == null ? null : auxiliaryResponse.token,
auxiliaryResponse != null && auxiliaryResponse.needsPhaseTwo,
auxiliaryResponse == null ? null : auxiliaryResponse.filters);
}
void postStartActivityProcessing(ActivityRecord r, int result, ActivityStack targetStack) {
@@ -924,12 +930,12 @@ class ActivityStarter {
// Don't modify the client's object!
intent = new Intent(intent);
if (componentSpecified
&& intent.getData() != null
&& Intent.ACTION_VIEW.equals(intent.getAction())
&& !Intent.ACTION_INSTALL_INSTANT_APP_PACKAGE.equals(intent.getAction())
&& !Intent.ACTION_RESOLVE_INSTANT_APP_PACKAGE.equals(intent.getAction())
&& mService.getPackageManagerInternalLocked()
.isInstantAppInstallerComponent(intent.getComponent())) {
// intercept intents targeted directly to the ephemeral installer the
// ephemeral installer should never be started with a raw URL; instead
// ephemeral installer should never be started with a raw Intent; instead
// adjust the intent so it looks like a "normal" instant app launch
intent.setComponent(null /*component*/);
componentSpecified = false;

View File

@@ -43,6 +43,7 @@ import java.io.FileDescriptor;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.concurrent.TimeoutException;
@@ -84,8 +85,8 @@ final class EphemeralResolverConnection implements DeathRecipient {
mIntent = new Intent(action).setComponent(componentName);
}
public final List<InstantAppResolveInfo> getInstantAppResolveInfoList(int hashPrefix[],
String token) throws ConnectionException {
public final List<InstantAppResolveInfo> getInstantAppResolveInfoList(Intent sanitizedIntent,
int hashPrefix[], String token) throws ConnectionException {
throwIfCalledOnMainThread();
IInstantAppResolver target = null;
try {
@@ -98,7 +99,7 @@ final class EphemeralResolverConnection implements DeathRecipient {
}
try {
return mGetEphemeralResolveInfoCaller
.getEphemeralResolveInfoList(target, hashPrefix, token);
.getEphemeralResolveInfoList(target, sanitizedIntent, hashPrefix, token);
} catch (TimeoutException e) {
throw new ConnectionException(ConnectionException.FAILURE_CALL);
} catch (RemoteException ignore) {
@@ -111,26 +112,22 @@ final class EphemeralResolverConnection implements DeathRecipient {
return null;
}
public final void getInstantAppIntentFilterList(int hashPrefix[], String token,
String hostName, PhaseTwoCallback callback, Handler callbackHandler,
final long startTime) throws ConnectionException {
public final void getInstantAppIntentFilterList(Intent sanitizedIntent, int hashPrefix[],
String token, PhaseTwoCallback callback, Handler callbackHandler, final long startTime)
throws ConnectionException {
final IRemoteCallback remoteCallback = new IRemoteCallback.Stub() {
@Override
public void sendResult(Bundle data) throws RemoteException {
final ArrayList<InstantAppResolveInfo> resolveList =
data.getParcelableArrayList(
InstantAppResolverService.EXTRA_RESOLVE_INFO);
callbackHandler.post(new Runnable() {
@Override
public void run() {
callback.onPhaseTwoResolved(resolveList, startTime);
}
});
callbackHandler.post(() -> callback.onPhaseTwoResolved(resolveList, startTime));
}
};
try {
getRemoteInstanceLazy(token)
.getInstantAppIntentFilterList(hashPrefix, token, hostName, remoteCallback);
.getInstantAppIntentFilterList(sanitizedIntent, hashPrefix, token,
remoteCallback);
} catch (TimeoutException e) {
throw new ConnectionException(ConnectionException.FAILURE_BIND);
} catch (InterruptedException e) {
@@ -337,10 +334,11 @@ final class EphemeralResolverConnection implements DeathRecipient {
}
public List<InstantAppResolveInfo> getEphemeralResolveInfoList(
IInstantAppResolver target, int hashPrefix[], String token)
IInstantAppResolver target, Intent sanitizedIntent, int hashPrefix[], String token)
throws RemoteException, TimeoutException {
final int sequence = onBeforeRemoteCall();
target.getInstantAppResolveInfoList(hashPrefix, token, sequence, mCallback);
target.getInstantAppResolveInfoList(sanitizedIntent, hashPrefix, token, sequence,
mCallback);
return getResultTimed(sequence);
}
}

View File

@@ -40,11 +40,14 @@ import android.content.pm.InstantAppIntentFilter;
import android.content.pm.InstantAppResolveInfo;
import android.content.pm.InstantAppResolveInfo.InstantAppDigest;
import android.metrics.LogMaker;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.RemoteException;
import android.text.TextUtils;
import android.util.Log;
import android.util.Slog;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
@@ -53,8 +56,12 @@ import com.android.server.pm.EphemeralResolverConnection.PhaseTwoCallback;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.UUID;
/** @hide */
@@ -79,6 +86,7 @@ public abstract class InstantAppResolver {
public @interface ResolutionStatus {}
private static MetricsLogger sMetricsLogger;
private static MetricsLogger getLogger() {
if (sMetricsLogger == null) {
sMetricsLogger = new MetricsLogger();
@@ -86,26 +94,49 @@ public abstract class InstantAppResolver {
return sMetricsLogger;
}
public static AuxiliaryResolveInfo doInstantAppResolutionPhaseOne(Context context,
/**
* Returns an intent with potential PII removed from the original intent. Fields removed
* include extras and the host + path of the data, if defined.
*/
public static Intent sanitizeIntent(Intent origIntent) {
final Intent sanitizedIntent;
sanitizedIntent = new Intent(origIntent.getAction());
Set<String> categories = origIntent.getCategories();
if (categories != null) {
for (String category : categories) {
sanitizedIntent.addCategory(category);
}
}
Uri sanitizedUri = origIntent.getData() == null
? null
: Uri.fromParts(origIntent.getScheme(), "", "");
sanitizedIntent.setDataAndType(sanitizedUri, origIntent.getType());
sanitizedIntent.addFlags(origIntent.getFlags());
sanitizedIntent.setPackage(origIntent.getPackage());
return sanitizedIntent;
}
public static AuxiliaryResolveInfo doInstantAppResolutionPhaseOne(
EphemeralResolverConnection connection, InstantAppRequest requestObj) {
final long startTime = System.currentTimeMillis();
final String token = UUID.randomUUID().toString();
if (DEBUG_EPHEMERAL) {
Log.d(TAG, "[" + token + "] Phase1; resolving");
}
final Intent intent = requestObj.origIntent;
final InstantAppDigest digest =
new InstantAppDigest(intent.getData().getHost(), 5 /*maxDigests*/);
final Intent origIntent = requestObj.origIntent;
final Intent sanitizedIntent = sanitizeIntent(origIntent);
final InstantAppDigest digest = getInstantAppDigest(origIntent);
final int[] shaPrefix = digest.getDigestPrefix();
AuxiliaryResolveInfo resolveInfo = null;
@ResolutionStatus int resolutionStatus = RESOLUTION_SUCCESS;
try {
final List<InstantAppResolveInfo> instantAppResolveInfoList =
connection.getInstantAppResolveInfoList(shaPrefix, token);
connection.getInstantAppResolveInfoList(sanitizedIntent, shaPrefix, token);
if (instantAppResolveInfoList != null && instantAppResolveInfoList.size() > 0) {
resolveInfo = InstantAppResolver.filterInstantAppIntent(
instantAppResolveInfoList, intent, requestObj.resolvedType,
requestObj.userId, intent.getPackage(), digest, token);
instantAppResolveInfoList, origIntent, requestObj.resolvedType,
requestObj.userId, origIntent.getPackage(), digest, token);
}
} catch (ConnectionException e) {
if (e.failure == ConnectionException.FAILURE_BIND) {
@@ -135,6 +166,12 @@ public abstract class InstantAppResolver {
return resolveInfo;
}
private static InstantAppDigest getInstantAppDigest(Intent origIntent) {
return origIntent.getData() != null && !TextUtils.isEmpty(origIntent.getData().getHost())
? new InstantAppDigest(origIntent.getData().getHost(), 5 /*maxDigests*/)
: InstantAppDigest.UNDEFINED;
}
public static void doInstantAppResolutionPhaseTwo(Context context,
EphemeralResolverConnection connection, InstantAppRequest requestObj,
ActivityInfo instantAppInstaller, Handler callbackHandler) {
@@ -143,73 +180,53 @@ public abstract class InstantAppResolver {
if (DEBUG_EPHEMERAL) {
Log.d(TAG, "[" + token + "] Phase2; resolving");
}
final Intent intent = requestObj.origIntent;
final String hostName = intent.getData().getHost();
final InstantAppDigest digest = new InstantAppDigest(hostName, 5 /*maxDigests*/);
final Intent origIntent = requestObj.origIntent;
final Intent sanitizedIntent = sanitizeIntent(origIntent);
final InstantAppDigest digest = getInstantAppDigest(origIntent);
final int[] shaPrefix = digest.getDigestPrefix();
final PhaseTwoCallback callback = new PhaseTwoCallback() {
@Override
void onPhaseTwoResolved(List<InstantAppResolveInfo> instantAppResolveInfoList,
long startTime) {
final String packageName;
final String splitName;
final long versionCode;
final Intent failureIntent;
final Bundle extras;
if (instantAppResolveInfoList != null && instantAppResolveInfoList.size() > 0) {
final AuxiliaryResolveInfo instantAppIntentInfo =
InstantAppResolver.filterInstantAppIntent(
instantAppResolveInfoList, intent, null /*resolvedType*/,
0 /*userId*/, intent.getPackage(), digest, token);
if (instantAppIntentInfo != null
&& instantAppIntentInfo.resolveInfo != null) {
packageName = instantAppIntentInfo.resolveInfo.getPackageName();
splitName = instantAppIntentInfo.splitName;
versionCode = instantAppIntentInfo.resolveInfo.getVersionCode();
instantAppResolveInfoList, origIntent, null /*resolvedType*/,
0 /*userId*/, origIntent.getPackage(), digest, token);
if (instantAppIntentInfo != null) {
failureIntent = instantAppIntentInfo.failureIntent;
extras = instantAppIntentInfo.resolveInfo.getExtras();
} else {
packageName = null;
splitName = null;
versionCode = -1;
failureIntent = null;
extras = null;
}
} else {
packageName = null;
splitName = null;
versionCode = -1;
failureIntent = null;
extras = null;
}
final Intent installerIntent = buildEphemeralInstallerIntent(
Intent.ACTION_RESOLVE_INSTANT_APP_PACKAGE,
requestObj.origIntent,
sanitizedIntent,
failureIntent,
requestObj.callingPackage,
requestObj.verificationBundle,
requestObj.resolvedType,
requestObj.userId,
packageName,
splitName,
requestObj.responseObj.installFailureActivity,
versionCode,
token,
extras,
false /*needsPhaseTwo*/);
false /*needsPhaseTwo*/,
requestObj.responseObj.filters);
installerIntent.setComponent(new ComponentName(
instantAppInstaller.packageName, instantAppInstaller.name));
logMetrics(ACTION_INSTANT_APP_RESOLUTION_PHASE_TWO, startTime, token,
packageName != null ? RESOLUTION_SUCCESS : RESOLUTION_FAILURE);
requestObj.responseObj.filters != null ? RESOLUTION_SUCCESS : RESOLUTION_FAILURE);
context.startActivity(installerIntent);
}
};
try {
connection.getInstantAppIntentFilterList(
shaPrefix, token, hostName, callback, callbackHandler, startTime);
connection.getInstantAppIntentFilterList(sanitizedIntent, shaPrefix, token, callback,
callbackHandler, startTime);
} catch (ConnectionException e) {
@ResolutionStatus int resolutionStatus = RESOLUTION_FAILURE;
if (e.failure == ConnectionException.FAILURE_BIND) {
@@ -231,23 +248,20 @@ public abstract class InstantAppResolver {
* Builds and returns an intent to launch the instant installer.
*/
public static Intent buildEphemeralInstallerIntent(
@NonNull String action,
@NonNull Intent origIntent,
@NonNull Intent failureIntent,
@NonNull Intent sanitizedIntent,
@Nullable Intent failureIntent,
@NonNull String callingPackage,
@Nullable Bundle verificationBundle,
@NonNull String resolvedType,
int userId,
@NonNull String instantAppPackageName,
@Nullable String instantAppSplitName,
@Nullable ComponentName installFailureActivity,
long versionCode,
@Nullable String token,
@Nullable Bundle extras,
boolean needsPhaseTwo) {
boolean needsPhaseTwo,
List<AuxiliaryResolveInfo.AuxiliaryFilter> filters) {
// Construct the intent that launches the instant installer
int flags = origIntent.getFlags();
final Intent intent = new Intent(action);
final Intent intent = new Intent();
intent.setFlags(flags
| Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_CLEAR_TASK
@@ -260,20 +274,23 @@ public abstract class InstantAppResolver {
intent.putExtra(Intent.EXTRA_EPHEMERAL_HOSTNAME, origIntent.getData().getHost());
}
intent.putExtra(Intent.EXTRA_INSTANT_APP_ACTION, origIntent.getAction());
if (extras != null) {
intent.putExtra(Intent.EXTRA_INSTANT_APP_EXTRAS, extras);
}
intent.putExtra(Intent.EXTRA_INTENT, sanitizedIntent);
// We have all of the data we need; just start the installer without a second phase
if (!needsPhaseTwo) {
// Intent that is launched if the package couldn't be installed for any reason.
if (needsPhaseTwo) {
intent.setAction(Intent.ACTION_RESOLVE_INSTANT_APP_PACKAGE);
} else {
// We have all of the data we need; just start the installer without a second phase
if (failureIntent != null || installFailureActivity != null) {
// Intent that is launched if the package couldn't be installed for any reason.
try {
final Intent onFailureIntent;
if (installFailureActivity != null) {
onFailureIntent = new Intent();
onFailureIntent.setComponent(installFailureActivity);
onFailureIntent.putExtra(Intent.EXTRA_SPLIT_NAME, instantAppSplitName);
if (filters != null && filters.size() == 1) {
onFailureIntent.putExtra(Intent.EXTRA_SPLIT_NAME,
filters.get(0).splitName);
}
onFailureIntent.putExtra(Intent.EXTRA_INTENT, origIntent);
} else {
onFailureIntent = failureIntent;
@@ -309,17 +326,35 @@ public abstract class InstantAppResolver {
intent.putExtra(Intent.EXTRA_EPHEMERAL_SUCCESS,
new IntentSender(successIntentTarget));
} catch (RemoteException ignore) { /* ignore; same process */ }
intent.putExtra(Intent.EXTRA_PACKAGE_NAME, instantAppPackageName);
intent.putExtra(Intent.EXTRA_SPLIT_NAME, instantAppSplitName);
intent.putExtra(Intent.EXTRA_VERSION_CODE, (int) (versionCode & 0x7fffffff));
intent.putExtra(Intent.EXTRA_LONG_VERSION_CODE, versionCode);
intent.putExtra(Intent.EXTRA_CALLING_PACKAGE, callingPackage);
if (verificationBundle != null) {
intent.putExtra(Intent.EXTRA_VERIFICATION_BUNDLE, verificationBundle);
}
}
intent.putExtra(Intent.EXTRA_CALLING_PACKAGE, callingPackage);
if (filters != null) {
Bundle resolvableFilters[] = new Bundle[filters.size()];
for (int i = 0, max = filters.size(); i < max; i++) {
Bundle resolvableFilter = new Bundle();
AuxiliaryResolveInfo.AuxiliaryFilter filter = filters.get(i);
resolvableFilter.putBoolean(Intent.EXTRA_UNKNOWN_INSTANT_APP,
filter.resolveInfo != null
&& filter.resolveInfo.shouldLetInstallerDecide());
resolvableFilter.putString(Intent.EXTRA_PACKAGE_NAME, filter.packageName);
resolvableFilter.putString(Intent.EXTRA_SPLIT_NAME, filter.splitName);
resolvableFilter.putLong(Intent.EXTRA_LONG_VERSION_CODE, filter.versionCode);
resolvableFilter.putBundle(Intent.EXTRA_INSTANT_APP_EXTRAS, filter.extras);
resolvableFilters[i] = resolvableFilter;
if (i == 0) {
// for backwards compat, always set the first result on the intent and add
// the int version code
intent.putExtras(resolvableFilter);
intent.putExtra(Intent.EXTRA_VERSION_CODE, (int) filter.versionCode);
}
}
intent.putExtra(Intent.EXTRA_INSTANT_APP_BUNDLES, resolvableFilters);
}
intent.setAction(Intent.ACTION_INSTALL_INSTANT_APP_PACKAGE);
}
return intent;
}
@@ -330,69 +365,134 @@ public abstract class InstantAppResolver {
final int[] shaPrefix = digest.getDigestPrefix();
final byte[][] digestBytes = digest.getDigestBytes();
final Intent failureIntent = new Intent(origIntent);
boolean requiresSecondPhase = false;
failureIntent.setFlags(failureIntent.getFlags() | Intent.FLAG_IGNORE_EPHEMERAL);
failureIntent.setLaunchToken(token);
// Go in reverse order so we match the narrowest scope first.
for (int i = shaPrefix.length - 1; i >= 0 ; --i) {
for (InstantAppResolveInfo instantAppInfo : instantAppResolveInfoList) {
if (!Arrays.equals(digestBytes[i], instantAppInfo.getDigestBytes())) {
ArrayList<AuxiliaryResolveInfo.AuxiliaryFilter> filters = null;
boolean isWebIntent = origIntent.isBrowsableWebIntent();
for (InstantAppResolveInfo instantAppResolveInfo : instantAppResolveInfoList) {
if (shaPrefix.length > 0 && instantAppResolveInfo.shouldLetInstallerDecide()) {
Slog.e(TAG, "InstantAppResolveInfo with mShouldLetInstallerDecide=true when digest"
+ " provided; ignoring");
continue;
}
byte[] filterDigestBytes = instantAppResolveInfo.getDigestBytes();
// Only include matching digests if we have a prefix and we're either dealing with a
// web intent or the resolveInfo specifies digest details.
if (shaPrefix.length > 0 && (isWebIntent || filterDigestBytes.length > 0)) {
boolean matchFound = false;
// Go in reverse order so we match the narrowest scope first.
for (int i = shaPrefix.length - 1; i >= 0; --i) {
if (Arrays.equals(digestBytes[i], filterDigestBytes)) {
matchFound = true;
break;
}
}
if (!matchFound) {
continue;
}
if (packageName != null
&& !packageName.equals(instantAppInfo.getPackageName())) {
continue;
}
// We matched a resolve info; resolve the filters to see if anything matches completely.
List<AuxiliaryResolveInfo.AuxiliaryFilter> matchFilters = computeResolveFilters(
origIntent, resolvedType, userId, packageName, token, instantAppResolveInfo);
if (matchFilters != null) {
if (matchFilters.isEmpty()) {
requiresSecondPhase = true;
}
final List<InstantAppIntentFilter> instantAppFilters =
instantAppInfo.getIntentFilters();
// No filters; we need to start phase two
if (instantAppFilters == null || instantAppFilters.isEmpty()) {
if (DEBUG_EPHEMERAL) {
Log.d(TAG, "No app filters; go to phase 2");
}
return new AuxiliaryResolveInfo(instantAppInfo,
new IntentFilter(Intent.ACTION_VIEW) /*intentFilter*/,
null /*splitName*/, token, true /*needsPhase2*/,
null /*failureIntent*/);
}
// We have a domain match; resolve the filters to see if anything matches.
final PackageManagerService.EphemeralIntentResolver instantAppResolver =
new PackageManagerService.EphemeralIntentResolver();
for (int j = instantAppFilters.size() - 1; j >= 0; --j) {
final InstantAppIntentFilter instantAppFilter = instantAppFilters.get(j);
final List<IntentFilter> splitFilters = instantAppFilter.getFilters();
if (splitFilters == null || splitFilters.isEmpty()) {
continue;
}
for (int k = splitFilters.size() - 1; k >= 0; --k) {
final AuxiliaryResolveInfo intentInfo =
new AuxiliaryResolveInfo(instantAppInfo,
splitFilters.get(k), instantAppFilter.getSplitName(),
token, false /*needsPhase2*/, failureIntent);
instantAppResolver.addFilter(intentInfo);
}
}
List<AuxiliaryResolveInfo> matchedResolveInfoList = instantAppResolver.queryIntent(
origIntent, resolvedType, false /*defaultOnly*/, userId);
if (!matchedResolveInfoList.isEmpty()) {
if (DEBUG_EPHEMERAL) {
final AuxiliaryResolveInfo info = matchedResolveInfoList.get(0);
Log.d(TAG, "[" + token + "] Found match;"
+ " package: " + info.packageName
+ ", split: " + info.splitName
+ ", versionCode: " + info.versionCode);
}
return matchedResolveInfoList.get(0);
} else if (DEBUG_EPHEMERAL) {
Log.d(TAG, "[" + token + "] No matches found"
+ " package: " + instantAppInfo.getPackageName()
+ ", versionCode: " + instantAppInfo.getVersionCode());
if (filters == null) {
filters = new ArrayList<>(matchFilters);
} else {
filters.addAll(matchFilters);
}
}
}
if (filters != null && !filters.isEmpty()) {
return new AuxiliaryResolveInfo(token, requiresSecondPhase, failureIntent, filters);
}
// Hash or filter mis-match; no instant apps for this domain.
return null;
}
/**
* Returns one of three states: <p/>
* <ul>
* <li>{@code null} if there are no matches will not be; resolution is unnecessary.</li>
* <li>An empty list signifying that a 2nd phase of resolution is required.</li>
* <li>A populated list meaning that matches were found and should be sent directly to the
* installer</li>
* </ul>
*
*/
private static List<AuxiliaryResolveInfo.AuxiliaryFilter> computeResolveFilters(
Intent origIntent, String resolvedType, int userId, String packageName, String token,
InstantAppResolveInfo instantAppInfo) {
if (instantAppInfo.shouldLetInstallerDecide()) {
return Collections.singletonList(
new AuxiliaryResolveInfo.AuxiliaryFilter(
instantAppInfo, null /* splitName */,
instantAppInfo.getExtras()));
}
if (packageName != null
&& !packageName.equals(instantAppInfo.getPackageName())) {
return null;
}
final List<InstantAppIntentFilter> instantAppFilters =
instantAppInfo.getIntentFilters();
if (instantAppFilters == null || instantAppFilters.isEmpty()) {
// No filters on web intent; no matches, 2nd phase unnecessary.
if (origIntent.isBrowsableWebIntent()) {
return null;
}
// No filters; we need to start phase two
if (DEBUG_EPHEMERAL) {
Log.d(TAG, "No app filters; go to phase 2");
}
return Collections.emptyList();
}
final PackageManagerService.EphemeralIntentResolver instantAppResolver =
new PackageManagerService.EphemeralIntentResolver();
for (int j = instantAppFilters.size() - 1; j >= 0; --j) {
final InstantAppIntentFilter instantAppFilter = instantAppFilters.get(j);
final List<IntentFilter> splitFilters = instantAppFilter.getFilters();
if (splitFilters == null || splitFilters.isEmpty()) {
continue;
}
for (int k = splitFilters.size() - 1; k >= 0; --k) {
IntentFilter filter = splitFilters.get(k);
Iterator<IntentFilter.AuthorityEntry> authorities =
filter.authoritiesIterator();
// ignore http/s-only filters.
if ((authorities == null || !authorities.hasNext())
&& (filter.hasDataScheme("http") || filter.hasDataScheme("https"))
&& filter.hasAction(Intent.ACTION_VIEW)
&& filter.hasCategory(Intent.CATEGORY_BROWSABLE)) {
continue;
}
instantAppResolver.addFilter(
new AuxiliaryResolveInfo.AuxiliaryFilter(
filter,
instantAppInfo,
instantAppFilter.getSplitName(),
instantAppInfo.getExtras()
));
}
}
List<AuxiliaryResolveInfo.AuxiliaryFilter> matchedResolveInfoList =
instantAppResolver.queryIntent(
origIntent, resolvedType, false /*defaultOnly*/, userId);
if (!matchedResolveInfoList.isEmpty()) {
if (DEBUG_EPHEMERAL) {
Log.d(TAG, "[" + token + "] Found match(es); " + matchedResolveInfoList);
}
return matchedResolveInfoList;
} else if (DEBUG_EPHEMERAL) {
Log.d(TAG, "[" + token + "] No matches found"
+ " package: " + instantAppInfo.getPackageName()
+ ", versionCode: " + instantAppInfo.getVersionCode());
}
return null;
}
private static void logMetrics(int action, long startTime, String token,
@ResolutionStatus int status) {
final LogMaker logMaker = new LogMaker(action)

View File

@@ -582,6 +582,7 @@ public class PackageManagerService extends IPackageManager.Stub
sBrowserIntent.setAction(Intent.ACTION_VIEW);
sBrowserIntent.addCategory(Intent.CATEGORY_BROWSABLE);
sBrowserIntent.setData(Uri.parse("http:"));
sBrowserIntent.addFlags(Intent.FLAG_IGNORE_EPHEMERAL);
}
/**
@@ -3594,24 +3595,35 @@ Slog.e("TODD",
}
private @Nullable ActivityInfo getInstantAppInstallerLPr() {
final Intent intent = new Intent(Intent.ACTION_INSTALL_INSTANT_APP_PACKAGE);
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.setDataAndType(Uri.fromFile(new File("foo.apk")), PACKAGE_MIME_TYPE);
String[] orderedActions = Build.IS_ENG
? new String[]{
Intent.ACTION_INSTALL_INSTANT_APP_PACKAGE + "_TEST",
Intent.ACTION_INSTALL_INSTANT_APP_PACKAGE,
Intent.ACTION_INSTALL_EPHEMERAL_PACKAGE}
: new String[]{
Intent.ACTION_INSTALL_INSTANT_APP_PACKAGE,
Intent.ACTION_INSTALL_EPHEMERAL_PACKAGE};
final int resolveFlags =
MATCH_DIRECT_BOOT_AWARE
| MATCH_DIRECT_BOOT_UNAWARE
| (!Build.IS_DEBUGGABLE ? MATCH_SYSTEM_ONLY : 0);
List<ResolveInfo> matches = queryIntentActivitiesInternal(intent, PACKAGE_MIME_TYPE,
resolveFlags, UserHandle.USER_SYSTEM);
// temporarily look for the old action
if (matches.isEmpty()) {
if (DEBUG_EPHEMERAL) {
Slog.d(TAG, "Ephemeral installer not found with new action; try old one");
}
intent.setAction(Intent.ACTION_INSTALL_EPHEMERAL_PACKAGE);
| MATCH_DIRECT_BOOT_UNAWARE
| Intent.FLAG_IGNORE_EPHEMERAL
| (!Build.IS_ENG ? MATCH_SYSTEM_ONLY : 0);
final Intent intent = new Intent();
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.setDataAndType(Uri.fromFile(new File("foo.apk")), PACKAGE_MIME_TYPE);
List<ResolveInfo> matches = null;
for (String action : orderedActions) {
intent.setAction(action);
matches = queryIntentActivitiesInternal(intent, PACKAGE_MIME_TYPE,
resolveFlags, UserHandle.USER_SYSTEM);
if (matches.isEmpty()) {
if (DEBUG_EPHEMERAL) {
Slog.d(TAG, "Instant App installer not found with " + action);
}
} else {
break;
}
}
Iterator<ResolveInfo> iter = matches.iterator();
while (iter.hasNext()) {
@@ -3619,7 +3631,8 @@ Slog.e("TODD",
final PackageSetting ps = mSettings.mPackages.get(rInfo.activityInfo.packageName);
if (ps != null) {
final PermissionsState permissionsState = ps.getPermissionsState();
if (permissionsState.hasPermission(Manifest.permission.INSTALL_PACKAGES, 0)) {
if (permissionsState.hasPermission(Manifest.permission.INSTALL_PACKAGES, 0)
|| Build.IS_ENG) {
continue;
}
}
@@ -4778,10 +4791,7 @@ Slog.e("TODD",
flags |= PackageManager.MATCH_INSTANT;
} else {
final boolean wantMatchInstant = (flags & PackageManager.MATCH_INSTANT) != 0;
final boolean allowMatchInstant =
(wantInstantApps
&& Intent.ACTION_VIEW.equals(intent.getAction())
&& hasWebURI(intent))
final boolean allowMatchInstant = wantInstantApps
|| (wantMatchInstant && canViewInstantApps(callingUid, userId));
flags &= ~(PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY
| PackageManager.MATCH_EXPLICITLY_VISIBLE_ONLY);
@@ -5971,8 +5981,14 @@ Slog.e("TODD",
if (!skipPackageCheck && intent.getPackage() != null) {
return false;
}
final boolean isWebUri = hasWebURI(intent);
if (!isWebUri || intent.getData().getHost() == null) {
if (!intent.isBrowsableWebIntent()) {
// for non web intents, we should not resolve externally if an app already exists to
// handle it or if the caller didn't explicitly request it.
if ((resolvedActivities != null && resolvedActivities.size() != 0)
|| (intent.getFlags() & Intent.FLAG_ACTIVITY_MATCH_EXTERNAL) == 0) {
return false;
}
} else if (intent.getData() == null || TextUtils.isEmpty(intent.getData().getHost())) {
return false;
}
// Deny ephemeral apps if the user chose _ALWAYS or _ALWAYS_ASK for intent resolution.
@@ -6370,7 +6386,7 @@ Slog.e("TODD",
if (matches.get(i).getTargetUserId() == targetUserId) return true;
}
}
if (hasWebURI(intent)) {
if (intent.hasWebURI()) {
// cross-profile app linking works only towards the parent.
final int callingUid = Binder.getCallingUid();
final UserInfo parent = getProfileParent(sourceUserId);
@@ -6545,7 +6561,7 @@ Slog.e("TODD",
sortResult = true;
}
}
if (hasWebURI(intent)) {
if (intent.hasWebURI()) {
CrossProfileDomainInfo xpDomainInfo = null;
final UserInfo parent = getProfileParent(userId);
if (parent != null) {
@@ -6631,7 +6647,6 @@ Slog.e("TODD",
if (ps.getInstantApp(userId)) {
final long packedStatus = getDomainVerificationStatusLPr(ps, userId);
final int status = (int)(packedStatus >> 32);
final int linkGeneration = (int)(packedStatus & 0xFFFFFFFF);
if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER) {
// there's a local instant application installed, but, the user has
// chosen to never use it; skip resolution and don't acknowledge
@@ -6663,9 +6678,8 @@ Slog.e("TODD",
null /*responseObj*/, intent /*origIntent*/, resolvedType,
null /*callingPackage*/, userId, null /*verificationBundle*/,
resolveForStart);
auxiliaryResponse =
InstantAppResolver.doInstantAppResolutionPhaseOne(
mContext, mInstantAppResolverConnection, requestObject);
auxiliaryResponse = InstantAppResolver.doInstantAppResolutionPhaseOne(
mInstantAppResolverConnection, requestObject);
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
} else {
// we have an instant application locally, but, we can't admit that since
@@ -6674,35 +6688,40 @@ Slog.e("TODD",
// instant application available externally. when it comes time to start
// the instant application, we'll do the right thing.
final ApplicationInfo ai = localInstantApp.activityInfo.applicationInfo;
auxiliaryResponse = new AuxiliaryResolveInfo(
ai.packageName, null /*splitName*/, null /*failureActivity*/,
ai.versionCode, null /*failureIntent*/);
auxiliaryResponse = new AuxiliaryResolveInfo(null /* failureActivity */,
ai.packageName, ai.versionCode, null /* splitName */);
}
}
if (auxiliaryResponse != null) {
if (DEBUG_EPHEMERAL) {
Slog.v(TAG, "Adding ephemeral installer to the ResolveInfo list");
}
final ResolveInfo ephemeralInstaller = new ResolveInfo(mInstantAppInstallerInfo);
final PackageSetting ps =
mSettings.mPackages.get(mInstantAppInstallerActivity.packageName);
if (ps != null) {
ephemeralInstaller.activityInfo = PackageParser.generateActivityInfo(
mInstantAppInstallerActivity, 0, ps.readUserState(userId), userId);
ephemeralInstaller.activityInfo.launchToken = auxiliaryResponse.token;
ephemeralInstaller.auxiliaryInfo = auxiliaryResponse;
// 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);
ephemeralInstaller.isInstantAppAvailable = true;
result.add(ephemeralInstaller);
}
if (intent.isBrowsableWebIntent() && auxiliaryResponse == null) {
return result;
}
final PackageSetting ps = mSettings.mPackages.get(mInstantAppInstallerActivity.packageName);
if (ps == null) {
return result;
}
final ResolveInfo ephemeralInstaller = new ResolveInfo(mInstantAppInstallerInfo);
ephemeralInstaller.activityInfo = PackageParser.generateActivityInfo(
mInstantAppInstallerActivity, 0, ps.readUserState(userId), userId);
ephemeralInstaller.match = IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART
| IntentFilter.MATCH_ADJUSTMENT_NORMAL;
// add a non-generic filter
ephemeralInstaller.filter = new IntentFilter();
if (intent.getAction() != null) {
ephemeralInstaller.filter.addAction(intent.getAction());
}
if (intent.getData() != null && intent.getData().getPath() != null) {
ephemeralInstaller.filter.addDataPath(
intent.getData().getPath(), PatternMatcher.PATTERN_LITERAL);
}
ephemeralInstaller.isInstantAppAvailable = true;
// make sure this resolver is the default
ephemeralInstaller.isDefault = true;
ephemeralInstaller.auxiliaryInfo = auxiliaryResponse;
if (DEBUG_EPHEMERAL) {
Slog.v(TAG, "Adding ephemeral installer to the ResolveInfo list");
}
result.add(ephemeralInstaller);
return result;
}
@@ -6817,10 +6836,11 @@ Slog.e("TODD",
final ResolveInfo info = resolveInfos.get(i);
// allow activities that are defined in the provided package
if (allowDynamicSplits
&& info.activityInfo != null
&& info.activityInfo.splitName != null
&& !ArrayUtils.contains(info.activityInfo.applicationInfo.splitNames,
info.activityInfo.splitName)) {
if (mInstantAppInstallerInfo == null) {
if (mInstantAppInstallerActivity == null) {
if (DEBUG_INSTALL) {
Slog.v(TAG, "No installer - not adding it to the ResolveInfo list");
}
@@ -6832,14 +6852,15 @@ Slog.e("TODD",
if (DEBUG_INSTALL) {
Slog.v(TAG, "Adding installer to the ResolveInfo list");
}
final ResolveInfo installerInfo = new ResolveInfo(mInstantAppInstallerInfo);
final ResolveInfo installerInfo = new ResolveInfo(
mInstantAppInstallerInfo);
final ComponentName installFailureActivity = findInstallFailureActivity(
info.activityInfo.packageName, filterCallingUid, userId);
installerInfo.auxiliaryInfo = new AuxiliaryResolveInfo(
info.activityInfo.packageName, info.activityInfo.splitName,
installFailureActivity,
info.activityInfo.packageName,
info.activityInfo.applicationInfo.versionCode,
null /*failureIntent*/);
info.activityInfo.splitName);
installerInfo.match = IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART
| IntentFilter.MATCH_ADJUSTMENT_NORMAL;
// add a non-generic filter
@@ -6856,6 +6877,7 @@ Slog.e("TODD",
installerInfo.priority = info.priority;
installerInfo.preferredOrder = info.preferredOrder;
installerInfo.isDefault = info.isDefault;
installerInfo.isInstantAppAvailable = true;
resolveInfos.set(i, installerInfo);
continue;
}
@@ -6913,17 +6935,6 @@ Slog.e("TODD",
return resolveInfos.size() > 0 && resolveInfos.get(0).priority >= 0;
}
private static boolean hasWebURI(Intent intent) {
if (intent.getData() == null) {
return false;
}
final String scheme = intent.getScheme();
if (TextUtils.isEmpty(scheme)) {
return false;
}
return scheme.equals(IntentFilter.SCHEME_HTTP) || scheme.equals(IntentFilter.SCHEME_HTTPS);
}
private List<ResolveInfo> filterCandidatesWithDomainPreferredActivitiesLPr(Intent intent,
int matchFlags, List<ResolveInfo> candidates, CrossProfileDomainInfo xpDomainInfo,
int userId) {
@@ -7596,11 +7607,13 @@ Slog.e("TODD",
if (DEBUG_EPHEMERAL) {
Slog.v(TAG, "Adding ephemeral installer to the ResolveInfo list");
}
final ResolveInfo installerInfo = new ResolveInfo(mInstantAppInstallerInfo);
final ResolveInfo installerInfo = new ResolveInfo(
mInstantAppInstallerInfo);
installerInfo.auxiliaryInfo = new AuxiliaryResolveInfo(
info.serviceInfo.packageName, info.serviceInfo.splitName,
null /*failureActivity*/, info.serviceInfo.applicationInfo.versionCode,
null /*failureIntent*/);
null /* installFailureActivity */,
info.serviceInfo.packageName,
info.serviceInfo.applicationInfo.versionCode,
info.serviceInfo.splitName);
// make sure this resolver is the default
installerInfo.isDefault = true;
installerInfo.match = IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART
@@ -7716,11 +7729,13 @@ Slog.e("TODD",
if (DEBUG_EPHEMERAL) {
Slog.v(TAG, "Adding ephemeral installer to the ResolveInfo list");
}
final ResolveInfo installerInfo = new ResolveInfo(mInstantAppInstallerInfo);
final ResolveInfo installerInfo = new ResolveInfo(
mInstantAppInstallerInfo);
installerInfo.auxiliaryInfo = new AuxiliaryResolveInfo(
info.providerInfo.packageName, info.providerInfo.splitName,
null /*failureActivity*/, info.providerInfo.applicationInfo.versionCode,
null /*failureIntent*/);
null /*failureActivity*/,
info.providerInfo.packageName,
info.providerInfo.applicationInfo.versionCode,
info.providerInfo.splitName);
// make sure this resolver is the default
installerInfo.isDefault = true;
installerInfo.match = IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART
@@ -11794,7 +11809,7 @@ Slog.e("TODD",
mInstantAppInstallerActivity.exported = true;
mInstantAppInstallerActivity.enabled = true;
mInstantAppInstallerInfo.activityInfo = mInstantAppInstallerActivity;
mInstantAppInstallerInfo.priority = 0;
mInstantAppInstallerInfo.priority = 1;
mInstantAppInstallerInfo.preferredOrder = 1;
mInstantAppInstallerInfo.isDefault = true;
mInstantAppInstallerInfo.match = IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART
@@ -13244,7 +13259,8 @@ Slog.e("TODD",
}
static final class EphemeralIntentResolver
extends IntentResolver<AuxiliaryResolveInfo, AuxiliaryResolveInfo> {
extends IntentResolver<AuxiliaryResolveInfo.AuxiliaryFilter,
AuxiliaryResolveInfo.AuxiliaryFilter> {
/**
* 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
@@ -13259,18 +13275,19 @@ Slog.e("TODD",
final ArrayMap<String, Pair<Integer, InstantAppResolveInfo>> mOrderResult = new ArrayMap<>();
@Override
protected AuxiliaryResolveInfo[] newArray(int size) {
return new AuxiliaryResolveInfo[size];
protected AuxiliaryResolveInfo.AuxiliaryFilter[] newArray(int size) {
return new AuxiliaryResolveInfo.AuxiliaryFilter[size];
}
@Override
protected boolean isPackageForFilter(String packageName, AuxiliaryResolveInfo responseObj) {
protected boolean isPackageForFilter(String packageName,
AuxiliaryResolveInfo.AuxiliaryFilter responseObj) {
return true;
}
@Override
protected AuxiliaryResolveInfo newResult(AuxiliaryResolveInfo responseObj, int match,
int userId) {
protected AuxiliaryResolveInfo.AuxiliaryFilter newResult(
AuxiliaryResolveInfo.AuxiliaryFilter responseObj, int match, int userId) {
if (!sUserManager.exists(userId)) {
return null;
}
@@ -13291,7 +13308,7 @@ Slog.e("TODD",
}
@Override
protected void filterResults(List<AuxiliaryResolveInfo> results) {
protected void filterResults(List<AuxiliaryResolveInfo.AuxiliaryFilter> results) {
// only do work if ordering is enabled [most of the time it won't be]
if (mOrderResult.size() == 0) {
return;