diff options
12 files changed, 425 insertions, 116 deletions
diff --git a/api/system-current.txt b/api/system-current.txt index f74b74318180..dad0ac2c7e1a 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -542,10 +542,12 @@ package android.app { method public final android.os.IBinder onBind(android.content.Intent); method @Deprecated public void onGetInstantAppIntentFilter(@Nullable int[], @NonNull String, @NonNull android.app.InstantAppResolverService.InstantAppResolutionCallback); method @Deprecated public void onGetInstantAppIntentFilter(@NonNull android.content.Intent, @Nullable int[], @NonNull String, @NonNull android.app.InstantAppResolverService.InstantAppResolutionCallback); - method public void onGetInstantAppIntentFilter(@NonNull android.content.Intent, @Nullable int[], @NonNull android.os.UserHandle, @NonNull String, @NonNull android.app.InstantAppResolverService.InstantAppResolutionCallback); + method @Deprecated public void onGetInstantAppIntentFilter(@NonNull android.content.Intent, @Nullable int[], @NonNull android.os.UserHandle, @NonNull String, @NonNull android.app.InstantAppResolverService.InstantAppResolutionCallback); + method public void onGetInstantAppIntentFilter(@NonNull android.content.pm.InstantAppRequestInfo, @NonNull android.app.InstantAppResolverService.InstantAppResolutionCallback); method @Deprecated public void onGetInstantAppResolveInfo(@Nullable int[], @NonNull String, @NonNull android.app.InstantAppResolverService.InstantAppResolutionCallback); method @Deprecated public void onGetInstantAppResolveInfo(@NonNull android.content.Intent, @Nullable int[], @NonNull String, @NonNull android.app.InstantAppResolverService.InstantAppResolutionCallback); - method public void onGetInstantAppResolveInfo(@NonNull android.content.Intent, @Nullable int[], @NonNull android.os.UserHandle, @NonNull String, @NonNull android.app.InstantAppResolverService.InstantAppResolutionCallback); + method @Deprecated public void onGetInstantAppResolveInfo(@NonNull android.content.Intent, @Nullable int[], @NonNull android.os.UserHandle, @NonNull String, @NonNull android.app.InstantAppResolverService.InstantAppResolutionCallback); + method public void onGetInstantAppResolveInfo(@NonNull android.content.pm.InstantAppRequestInfo, @NonNull android.app.InstantAppResolverService.InstantAppResolutionCallback); } public static final class InstantAppResolverService.InstantAppResolutionCallback { @@ -1591,6 +1593,18 @@ package android.content.pm { field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.InstantAppIntentFilter> CREATOR; } + public final class InstantAppRequestInfo implements android.os.Parcelable { + ctor public InstantAppRequestInfo(@NonNull android.content.Intent, @Nullable int[], @NonNull android.os.UserHandle, boolean, @NonNull String); + method public int describeContents(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.InstantAppRequestInfo> CREATOR; + field @Nullable public final int[] hostDigestPrefix; + field @NonNull public final android.content.Intent intent; + field public final boolean isRequesterInstantApp; + field @NonNull public final String token; + field @NonNull public final android.os.UserHandle userHandle; + } + public final class InstantAppResolveInfo implements android.os.Parcelable { ctor public InstantAppResolveInfo(@NonNull android.content.pm.InstantAppResolveInfo.InstantAppDigest, @Nullable String, @Nullable java.util.List<android.content.pm.InstantAppIntentFilter>, int); ctor public InstantAppResolveInfo(@NonNull android.content.pm.InstantAppResolveInfo.InstantAppDigest, @Nullable String, @Nullable java.util.List<android.content.pm.InstantAppIntentFilter>, long, @Nullable android.os.Bundle); diff --git a/core/java/android/app/IInstantAppResolver.aidl b/core/java/android/app/IInstantAppResolver.aidl index 7318762cfc63..8618fbb3bada 100644 --- a/core/java/android/app/IInstantAppResolver.aidl +++ b/core/java/android/app/IInstantAppResolver.aidl @@ -16,15 +16,13 @@ package android.app; -import android.content.Intent; +import android.content.pm.InstantAppRequestInfo; import android.os.IRemoteCallback; /** @hide */ oneway interface IInstantAppResolver { - void getInstantAppResolveInfoList(in Intent sanitizedIntent, in int[] hostDigestPrefix, - int userId, String token, int sequence, IRemoteCallback callback); - - void getInstantAppIntentFilterList(in Intent sanitizedIntent, in int[] hostDigestPrefix, - int userId, String token, IRemoteCallback callback); + void getInstantAppResolveInfoList(in InstantAppRequestInfo request, int sequence, + IRemoteCallback callback); + void getInstantAppIntentFilterList(in InstantAppRequestInfo request, IRemoteCallback callback); } diff --git a/core/java/android/app/InstantAppResolverService.java b/core/java/android/app/InstantAppResolverService.java index a7be5421adb2..a413c606b76f 100644 --- a/core/java/android/app/InstantAppResolverService.java +++ b/core/java/android/app/InstantAppResolverService.java @@ -21,6 +21,7 @@ import android.annotation.Nullable; import android.annotation.SystemApi; import android.content.Context; import android.content.Intent; +import android.content.pm.InstantAppRequestInfo; import android.content.pm.InstantAppResolveInfo; import android.os.Build; import android.os.Bundle; @@ -59,8 +60,9 @@ public abstract class InstantAppResolverService extends Service { * 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[], UserHandle, - * String, InstantAppResolutionCallback)}. + * + * @deprecated Should implement {@link #onGetInstantAppResolveInfo(InstantAppRequestInfo, + * InstantAppResolutionCallback)} */ @Deprecated public void onGetInstantAppResolveInfo(@Nullable int[] digestPrefix, @NonNull String token, @@ -73,8 +75,9 @@ public abstract class InstantAppResolverService extends Service { * sources. * * @param digestPrefix The hash prefix of the instant app's domain. - * @deprecated Should implement {@link #onGetInstantAppIntentFilter(Intent, int[], UserHandle, - * String, InstantAppResolutionCallback)}. + * + * @deprecated Should implement {@link #onGetInstantAppIntentFilter(InstantAppRequestInfo, + * InstantAppResolutionCallback)} */ @Deprecated public void onGetInstantAppIntentFilter(@Nullable int[] digestPrefix, @NonNull String token, @@ -103,8 +106,8 @@ public abstract class InstantAppResolverService extends Service { * * @see InstantAppResolveInfo * - * @deprecated Should implement {@link #onGetInstantAppResolveInfo(Intent, int[], UserHandle, - * String, InstantAppResolutionCallback)}. + * @deprecated Should implement {@link #onGetInstantAppResolveInfo(InstantAppRequestInfo, + * InstantAppResolutionCallback)} */ @Deprecated public void onGetInstantAppResolveInfo(@NonNull Intent sanitizedIntent, @@ -134,8 +137,8 @@ public abstract class InstantAppResolverService extends Service { * {@link Intent#EXTRA_INSTANT_APP_TOKEN}. * @param callback The {@link InstantAppResolutionCallback} to provide results to. * - * @deprecated Should implement {@link #onGetInstantAppIntentFilter(Intent, int[], UserHandle, - * String, InstantAppResolutionCallback)}. + * @deprecated Should implement {@link #onGetInstantAppIntentFilter(InstantAppRequestInfo, + * InstantAppResolutionCallback)} */ @Deprecated public void onGetInstantAppIntentFilter(@NonNull Intent sanitizedIntent, @@ -170,7 +173,11 @@ public abstract class InstantAppResolverService extends Service { * @param callback The {@link InstantAppResolutionCallback} to provide results to. * * @see InstantAppResolveInfo + * + * @deprecated Should implement {@link #onGetInstantAppResolveInfo(InstantAppRequestInfo, + * InstantAppResolutionCallback */ + @Deprecated public void onGetInstantAppResolveInfo(@NonNull Intent sanitizedIntent, @Nullable int[] hostDigestPrefix, @NonNull UserHandle userHandle, @NonNull String token, @NonNull InstantAppResolutionCallback callback) { @@ -193,7 +200,11 @@ public abstract class InstantAppResolverService extends Service { * Intent, int[], UserHandle, String, InstantAppResolutionCallback)} and provided * to the currently visible installer via {@link Intent#EXTRA_INSTANT_APP_TOKEN}. * @param callback The {@link InstantAppResolutionCallback} to provide results to. + * + * @deprecated Should implement {@link #onGetInstantAppIntentFilter(InstantAppRequestInfo, + * InstantAppResolutionCallback)} */ + @Deprecated public void onGetInstantAppIntentFilter(@NonNull Intent sanitizedIntent, @Nullable int[] hostDigestPrefix, @NonNull UserHandle userHandle, @NonNull String token, @NonNull InstantAppResolutionCallback callback) { @@ -202,6 +213,41 @@ public abstract class InstantAppResolverService extends Service { } /** + * Called to retrieve resolve info for instant applications immediately. The response will be + * ignored if not provided within a reasonable time. {@link InstantAppResolveInfo}s provided + * in response to this method may be partial to request a second phase of resolution which will + * result in a subsequent call to {@link #onGetInstantAppIntentFilter(InstantAppRequestInfo, + * InstantAppResolutionCallback)} + * + * @param request The parameters for this resolution request + * @param callback The {@link InstantAppResolutionCallback} to provide results to. + * + * @see InstantAppResolveInfo + */ + public void onGetInstantAppResolveInfo(@NonNull InstantAppRequestInfo request, + @NonNull InstantAppResolutionCallback callback) { + // If not overridden, forward to the old method. + onGetInstantAppResolveInfo(request.intent, request.hostDigestPrefix, request.userHandle, + request.token, callback); + } + + /** + * Called to retrieve intent filters for potentially matching instant applications. Unlike + * {@link #onGetInstantAppResolveInfo(InstantAppRequestInfo, InstantAppResolutionCallback)}, + * the response may take as long as necessary to respond. All {@link InstantAppResolveInfo}s + * provided in response to this method must be completely populated. + * + * @param request The parameters for this resolution request + * @param callback The {@link InstantAppResolutionCallback} to provide results to. + */ + public void onGetInstantAppIntentFilter(@NonNull InstantAppRequestInfo request, + @NonNull InstantAppResolutionCallback callback) { + // If not overridden, forward to the old method. + onGetInstantAppIntentFilter(request.intent, request.hostDigestPrefix, request.userHandle, + request.token, callback); + } + + /** * Returns a {@link Looper} to perform service operations on. */ Looper getLooper() { @@ -218,35 +264,29 @@ public abstract class InstantAppResolverService extends Service { public final IBinder onBind(Intent intent) { return new IInstantAppResolver.Stub() { @Override - public void getInstantAppResolveInfoList(Intent sanitizedIntent, int[] digestPrefix, - int userId, String token, int sequence, IRemoteCallback callback) { + public void getInstantAppResolveInfoList(InstantAppRequestInfo request, int sequence, + IRemoteCallback callback) { if (DEBUG_INSTANT) { - Slog.v(TAG, "[" + token + "] Phase1 called; posting"); + Slog.v(TAG, "[" + request.token + "] Phase1 called; posting"); } final SomeArgs args = SomeArgs.obtain(); - args.arg1 = callback; - args.arg2 = digestPrefix; - args.arg3 = userId; - args.arg4 = token; - args.arg5 = sanitizedIntent; - mHandler.obtainMessage(ServiceHandler.MSG_GET_INSTANT_APP_RESOLVE_INFO, - sequence, 0, args).sendToTarget(); + args.arg1 = request; + args.arg2 = callback; + mHandler.obtainMessage(ServiceHandler.MSG_GET_INSTANT_APP_RESOLVE_INFO, sequence, + 0, args).sendToTarget(); } @Override - public void getInstantAppIntentFilterList(Intent sanitizedIntent, - int[] digestPrefix, int userId, String token, IRemoteCallback callback) { + public void getInstantAppIntentFilterList(InstantAppRequestInfo request, + IRemoteCallback callback) { if (DEBUG_INSTANT) { - Slog.v(TAG, "[" + token + "] Phase2 called; posting"); + Slog.v(TAG, "[" + request.token + "] Phase2 called; posting"); } final SomeArgs args = SomeArgs.obtain(); - args.arg1 = callback; - args.arg2 = digestPrefix; - args.arg3 = userId; - args.arg4 = token; - args.arg5 = sanitizedIntent; - mHandler.obtainMessage(ServiceHandler.MSG_GET_INSTANT_APP_INTENT_FILTER, - args).sendToTarget(); + args.arg1 = request; + args.arg2 = callback; + mHandler.obtainMessage(ServiceHandler.MSG_GET_INSTANT_APP_INTENT_FILTER, args) + .sendToTarget(); } }; } @@ -287,36 +327,33 @@ public abstract class InstantAppResolverService extends Service { switch (action) { case MSG_GET_INSTANT_APP_RESOLVE_INFO: { final SomeArgs args = (SomeArgs) message.obj; - final IRemoteCallback callback = (IRemoteCallback) args.arg1; - final int[] digestPrefix = (int[]) args.arg2; - final int userId = (int) args.arg3; - final String token = (String) args.arg4; - final Intent intent = (Intent) args.arg5; + final InstantAppRequestInfo request = (InstantAppRequestInfo) args.arg1; + final IRemoteCallback callback = (IRemoteCallback) args.arg2; + args.recycle(); final int sequence = message.arg1; if (DEBUG_INSTANT) { - Slog.d(TAG, "[" + token + "] Phase1 request;" - + " prefix: " + Arrays.toString(digestPrefix) - + ", userId: " + userId); + Slog.d(TAG, "[" + request.token + "] Phase1 request;" + + " prefix: " + Arrays.toString(request.hostDigestPrefix) + + ", userId: " + request.userHandle.getIdentifier()); } - onGetInstantAppResolveInfo(intent, digestPrefix, UserHandle.of(userId), token, + onGetInstantAppResolveInfo(request, new InstantAppResolutionCallback(sequence, callback)); } break; case MSG_GET_INSTANT_APP_INTENT_FILTER: { final SomeArgs args = (SomeArgs) message.obj; - final IRemoteCallback callback = (IRemoteCallback) args.arg1; - final int[] digestPrefix = (int[]) args.arg2; - final int userId = (int) args.arg3; - final String token = (String) args.arg4; - final Intent intent = (Intent) args.arg5; + final InstantAppRequestInfo request = (InstantAppRequestInfo) args.arg1; + final IRemoteCallback callback = (IRemoteCallback) args.arg2; + args.recycle(); if (DEBUG_INSTANT) { - Slog.d(TAG, "[" + token + "] Phase2 request;" - + " prefix: " + Arrays.toString(digestPrefix) - + ", userId: " + userId); + Slog.d(TAG, "[" + request.token + "] Phase2 request;" + + " prefix: " + Arrays.toString(request.hostDigestPrefix) + + ", userId: " + request.userHandle.getIdentifier()); } - onGetInstantAppIntentFilter(intent, digestPrefix, UserHandle.of(userId), token, + onGetInstantAppIntentFilter(request, new InstantAppResolutionCallback(-1 /*sequence*/, callback)); - } break; + } + break; default: { throw new IllegalArgumentException("Unknown message: " + action); diff --git a/core/java/android/content/pm/AuxiliaryResolveInfo.java b/core/java/android/content/pm/AuxiliaryResolveInfo.java index 202df50dda6f..7d07e1dc6361 100644 --- a/core/java/android/content/pm/AuxiliaryResolveInfo.java +++ b/core/java/android/content/pm/AuxiliaryResolveInfo.java @@ -46,17 +46,21 @@ public final class AuxiliaryResolveInfo { public final Intent failureIntent; /** The matching filters for this resolve info. */ public final List<AuxiliaryFilter> filters; + /** Stored {@link InstantAppRequest#hostDigestPrefixSecure} to prevent re-generation */ + public final int[] hostDigestPrefixSecure; /** Create a response for installing an instant application. */ public AuxiliaryResolveInfo(@NonNull String token, boolean needsPhase2, @Nullable Intent failureIntent, - @Nullable List<AuxiliaryFilter> filters) { + @Nullable List<AuxiliaryFilter> filters, + @Nullable int[] hostDigestPrefix) { this.token = token; this.needsPhaseTwo = needsPhase2; this.failureIntent = failureIntent; this.filters = filters; this.installFailureActivity = null; + this.hostDigestPrefixSecure = hostDigestPrefix; } /** Create a response for installing a split on demand. */ @@ -69,6 +73,7 @@ public final class AuxiliaryResolveInfo { this.token = null; this.needsPhaseTwo = false; this.failureIntent = failureIntent; + this.hostDigestPrefixSecure = null; } /** Create a response for installing a split on demand. */ @@ -126,4 +131,4 @@ public final class AuxiliaryResolveInfo { + ", splitName='" + splitName + '\'' + '}'; } } -}
\ No newline at end of file +} diff --git a/core/java/android/content/pm/InstantAppRequest.java b/core/java/android/content/pm/InstantAppRequest.java index 361d4e4acb3b..f692db1f0443 100644 --- a/core/java/android/content/pm/InstantAppRequest.java +++ b/core/java/android/content/pm/InstantAppRequest.java @@ -16,9 +16,10 @@ package android.content.pm; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.content.Intent; import android.os.Bundle; -import android.text.TextUtils; /** * Information needed to make an instant application resolution request. @@ -34,32 +35,40 @@ public final class InstantAppRequest { public final String resolvedType; /** The name of the package requesting the instant application */ public final String callingPackage; + /** Whether or not the requesting package was an instant app */ + public final boolean isRequesterInstantApp; /** ID of the user requesting the instant application */ public final int userId; /** * Optional extra bundle provided by the source application to the installer for additional - * verification. */ + * verification. + */ public final Bundle verificationBundle; /** Whether resolution occurs because an application is starting */ public final boolean resolveForStart; - /** The instant app digest for this request */ - public final InstantAppResolveInfo.InstantAppDigest digest; + /** + * The hash prefix of an instant app's domain or null if no host is defined. + * Secure version that should be carried through for external use. + */ + @Nullable + public final int[] hostDigestPrefixSecure; + /** A unique identifier */ + @NonNull + public final String token; public InstantAppRequest(AuxiliaryResolveInfo responseObj, Intent origIntent, - String resolvedType, String callingPackage, int userId, Bundle verificationBundle, - boolean resolveForStart) { + String resolvedType, String callingPackage, boolean isRequesterInstantApp, + int userId, Bundle verificationBundle, boolean resolveForStart, + @Nullable int[] hostDigestPrefixSecure, @NonNull String token) { this.responseObj = responseObj; this.origIntent = origIntent; this.resolvedType = resolvedType; this.callingPackage = callingPackage; + this.isRequesterInstantApp = isRequesterInstantApp; this.userId = userId; this.verificationBundle = verificationBundle; this.resolveForStart = resolveForStart; - if (origIntent.getData() != null && !TextUtils.isEmpty(origIntent.getData().getHost())) { - digest = new InstantAppResolveInfo.InstantAppDigest( - origIntent.getData().getHost(), 5 /*maxDigests*/); - } else { - digest = InstantAppResolveInfo.InstantAppDigest.UNDEFINED; - } + this.hostDigestPrefixSecure = hostDigestPrefixSecure; + this.token = token; } } diff --git a/core/java/android/content/pm/InstantAppRequestInfo.aidl b/core/java/android/content/pm/InstantAppRequestInfo.aidl new file mode 100644 index 000000000000..0f94220bc5da --- /dev/null +++ b/core/java/android/content/pm/InstantAppRequestInfo.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.pm; + +parcelable InstantAppRequestInfo; diff --git a/core/java/android/content/pm/InstantAppRequestInfo.java b/core/java/android/content/pm/InstantAppRequestInfo.java new file mode 100644 index 000000000000..83d55361ff2a --- /dev/null +++ b/core/java/android/content/pm/InstantAppRequestInfo.java @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.pm; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.content.Intent; +import android.os.Parcelable; +import android.os.UserHandle; + +import com.android.internal.util.DataClass; + +/** + * Information exposed to {@link android.app.InstantAppResolverService} to complete + * an instant application resolution request. + * @hide + */ +@SystemApi +@DataClass(genParcelable = true, genConstructor = true, genAidl = true) +public final class InstantAppRequestInfo implements Parcelable { + + /** + * The sanitized {@link Intent} used for resolution. A sanitized Intent is an intent with + * potential PII removed from the original intent. Fields removed include extras and the + * host + path of the data, if defined. + */ + @NonNull + public final Intent intent; + + /** The hash prefix of the instant app's domain or null if no host is defined. */ + @Nullable + public final int[] hostDigestPrefix; + + /** The user requesting the instant application */ + @NonNull + public final UserHandle userHandle; + + /** Whether or not the requesting package was an instant app itself */ + public final boolean isRequesterInstantApp; + + /** A unique identifier */ + @NonNull + public final String token; + + + + // Code below generated by codegen v1.0.13. + // + // DO NOT MODIFY! + // CHECKSTYLE:OFF Generated code + // + // To regenerate run: + // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/InstantAppRequestInfo.java + // + // To exclude the generated code from IntelliJ auto-formatting enable (one-time): + // Settings > Editor > Code Style > Formatter Control + //@formatter:off + + + /** + * Creates a new InstantAppRequestInfo. + * + * @param intent + * The sanitized {@link Intent} used for resolution. A sanitized Intent is an intent with + * potential PII removed from the original intent. Fields removed include extras and the + * host + path of the data, if defined. + * @param hostDigestPrefix + * The hash prefix of the instant app's domain or null if no host is defined. + * @param userHandle + * The user requesting the instant application + * @param isRequesterInstantApp + * Whether or not the requesting package was an instant app itself + * @param token + * A unique identifier + */ + @DataClass.Generated.Member + public InstantAppRequestInfo( + @NonNull Intent intent, + @Nullable int[] hostDigestPrefix, + @NonNull UserHandle userHandle, + boolean isRequesterInstantApp, + @NonNull String token) { + this.intent = intent; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, intent); + this.hostDigestPrefix = hostDigestPrefix; + this.userHandle = userHandle; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, userHandle); + this.isRequesterInstantApp = isRequesterInstantApp; + this.token = token; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, token); + + // onConstructed(); // You can define this method to get a callback + } + + @Override + @DataClass.Generated.Member + public void writeToParcel(@NonNull android.os.Parcel dest, int flags) { + // You can override field parcelling by defining methods like: + // void parcelFieldName(Parcel dest, int flags) { ... } + + byte flg = 0; + if (isRequesterInstantApp) flg |= 0x8; + if (hostDigestPrefix != null) flg |= 0x2; + dest.writeByte(flg); + dest.writeTypedObject(intent, flags); + if (hostDigestPrefix != null) dest.writeIntArray(hostDigestPrefix); + dest.writeTypedObject(userHandle, flags); + dest.writeString(token); + } + + @Override + @DataClass.Generated.Member + public int describeContents() { return 0; } + + /** @hide */ + @SuppressWarnings({"unchecked", "RedundantCast"}) + @DataClass.Generated.Member + /* package-private */ InstantAppRequestInfo(@NonNull android.os.Parcel in) { + // You can override field unparcelling by defining methods like: + // static FieldType unparcelFieldName(Parcel in) { ... } + + byte flg = in.readByte(); + boolean _isRequesterInstantApp = (flg & 0x8) != 0; + Intent _intent = (Intent) in.readTypedObject(Intent.CREATOR); + int[] _hostDigestPrefix = (flg & 0x2) == 0 ? null : in.createIntArray(); + UserHandle _userHandle = (UserHandle) in.readTypedObject(UserHandle.CREATOR); + String _token = in.readString(); + + this.intent = _intent; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, intent); + this.hostDigestPrefix = _hostDigestPrefix; + this.userHandle = _userHandle; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, userHandle); + this.isRequesterInstantApp = _isRequesterInstantApp; + this.token = _token; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, token); + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public static final @NonNull Parcelable.Creator<InstantAppRequestInfo> CREATOR + = new Parcelable.Creator<InstantAppRequestInfo>() { + @Override + public InstantAppRequestInfo[] newArray(int size) { + return new InstantAppRequestInfo[size]; + } + + @Override + public InstantAppRequestInfo createFromParcel(@NonNull android.os.Parcel in) { + return new InstantAppRequestInfo(in); + } + }; + + @DataClass.Generated( + time = 1574373347443L, + codegenVersion = "1.0.13", + sourceFile = "frameworks/base/core/java/android/content/pm/InstantAppRequestInfo.java", + inputSignatures = "public final @android.annotation.NonNull android.content.Intent intent\npublic final @android.annotation.Nullable int[] hostDigestPrefix\npublic final @android.annotation.NonNull android.os.UserHandle userHandle\npublic final boolean isRequesterInstantApp\npublic final @android.annotation.NonNull java.lang.String token\nclass InstantAppRequestInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genParcelable=true, genConstructor=true, genAidl=true)") + @Deprecated + private void __metadata() {} + + + //@formatter:on + // End of generated code + +} diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java index dc24cffa54a4..5ec0fe76b5a2 100644 --- a/services/core/java/android/content/pm/PackageManagerInternal.java +++ b/services/core/java/android/content/pm/PackageManagerInternal.java @@ -331,14 +331,16 @@ public abstract class PackageManagerInternal { * @param responseObj The response of the first phase of ephemeral resolution * @param origIntent The original intent that triggered ephemeral resolution * @param resolvedType The resolved type of the intent - * @param callingPackage The name of the package requesting the ephemeral application + * @param callingPkg The app requesting the ephemeral application + * @param isRequesterInstantApp Whether or not the app requesting the ephemeral application + * is an instant app * @param verificationBundle Optional bundle to pass to the installer for additional * verification * @param userId The ID of the user that triggered ephemeral resolution */ public abstract void requestInstantAppResolutionPhaseTwo(AuxiliaryResolveInfo responseObj, - Intent origIntent, String resolvedType, String callingPackage, - Bundle verificationBundle, int userId); + Intent origIntent, String resolvedType, String callingPkg, + boolean isRequesterInstantApp, Bundle verificationBundle, int userId); /** * Grants implicit access based on an interaction between two apps. This grants the target app diff --git a/services/core/java/com/android/server/pm/InstantAppResolver.java b/services/core/java/com/android/server/pm/InstantAppResolver.java index 30b2c9d21a6a..8333ae5cbbad 100644 --- a/services/core/java/com/android/server/pm/InstantAppResolver.java +++ b/services/core/java/com/android/server/pm/InstantAppResolver.java @@ -39,6 +39,7 @@ import android.content.pm.ActivityInfo; import android.content.pm.AuxiliaryResolveInfo; import android.content.pm.InstantAppIntentFilter; import android.content.pm.InstantAppRequest; +import android.content.pm.InstantAppRequestInfo; import android.content.pm.InstantAppResolveInfo; import android.content.pm.InstantAppResolveInfo.InstantAppDigest; import android.metrics.LogMaker; @@ -47,6 +48,8 @@ import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.RemoteException; +import android.os.UserHandle; +import android.text.TextUtils; import android.util.Log; import android.util.Slog; @@ -63,7 +66,6 @@ import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Set; -import java.util.UUID; /** @hide */ public abstract class InstantAppResolver { @@ -117,26 +119,40 @@ public abstract class InstantAppResolver { return sanitizedIntent; } + /** + * Generate an {@link InstantAppDigest} from an {@link Intent} which contains hashes of the + * host. The object contains both secure and insecure hash array variants, and the secure + * version must be passed along to ensure the random data is consistent. + */ + @NonNull + public static InstantAppDigest parseDigest(@NonNull Intent origIntent) { + if (origIntent.getData() != null && !TextUtils.isEmpty(origIntent.getData().getHost())) { + return new InstantAppResolveInfo.InstantAppDigest(origIntent.getData().getHost(), + 5 /*maxDigests*/); + } else { + return InstantAppResolveInfo.InstantAppDigest.UNDEFINED; + } + } + public static AuxiliaryResolveInfo doInstantAppResolutionPhaseOne( InstantAppResolverConnection connection, InstantAppRequest requestObj) { final long startTime = System.currentTimeMillis(); - final String token = UUID.randomUUID().toString(); + final String token = requestObj.token; if (DEBUG_INSTANT) { Log.d(TAG, "[" + token + "] Phase1; resolving"); } - final Intent origIntent = requestObj.origIntent; - final Intent sanitizedIntent = sanitizeIntent(origIntent); AuxiliaryResolveInfo resolveInfo = null; @ResolutionStatus int resolutionStatus = RESOLUTION_SUCCESS; + Intent origIntent = requestObj.origIntent; try { final List<InstantAppResolveInfo> instantAppResolveInfoList = - connection.getInstantAppResolveInfoList(sanitizedIntent, - requestObj.digest.getDigestPrefixSecure(), requestObj.userId, token); + connection.getInstantAppResolveInfoList(buildRequestInfo(requestObj)); if (instantAppResolveInfoList != null && instantAppResolveInfoList.size() > 0) { resolveInfo = InstantAppResolver.filterInstantAppIntent( instantAppResolveInfoList, origIntent, requestObj.resolvedType, - requestObj.userId, origIntent.getPackage(), requestObj.digest, token); + requestObj.userId, origIntent.getPackage(), token, + requestObj.hostDigestPrefixSecure); } } catch (ConnectionException e) { if (e.failure == ConnectionException.FAILURE_BIND) { @@ -166,7 +182,7 @@ public abstract class InstantAppResolver { // if the match external flag is set, return an empty resolve info instead of a null result. if (resolveInfo == null && (origIntent.getFlags() & FLAG_ACTIVITY_MATCH_EXTERNAL) != 0) { return new AuxiliaryResolveInfo(token, false, createFailureIntent(origIntent, token), - null /* filters */); + null /* filters */, requestObj.hostDigestPrefixSecure); } return resolveInfo; } @@ -175,7 +191,7 @@ public abstract class InstantAppResolver { InstantAppResolverConnection connection, InstantAppRequest requestObj, ActivityInfo instantAppInstaller, Handler callbackHandler) { final long startTime = System.currentTimeMillis(); - final String token = requestObj.responseObj.token; + final String token = requestObj.token; if (DEBUG_INSTANT) { Log.d(TAG, "[" + token + "] Phase2; resolving"); } @@ -191,8 +207,8 @@ public abstract class InstantAppResolver { final AuxiliaryResolveInfo instantAppIntentInfo = InstantAppResolver.filterInstantAppIntent( instantAppResolveInfoList, origIntent, null /*resolvedType*/, - 0 /*userId*/, origIntent.getPackage(), requestObj.digest, - token); + 0 /*userId*/, origIntent.getPackage(), + token, requestObj.hostDigestPrefixSecure); if (instantAppIntentInfo != null) { failureIntent = instantAppIntentInfo.failureIntent; } else { @@ -223,8 +239,7 @@ public abstract class InstantAppResolver { } }; try { - connection.getInstantAppIntentFilterList(sanitizedIntent, - requestObj.digest.getDigestPrefixSecure(), requestObj.userId, token, callback, + connection.getInstantAppIntentFilterList(buildRequestInfo(requestObj), callback, callbackHandler, startTime); } catch (ConnectionException e) { @ResolutionStatus int resolutionStatus = RESOLUTION_FAILURE; @@ -356,10 +371,22 @@ public abstract class InstantAppResolver { return intent; } + private static InstantAppRequestInfo buildRequestInfo(InstantAppRequest request) { + return new InstantAppRequestInfo( + sanitizeIntent(request.origIntent), + // This must only expose the secured version of the host + request.hostDigestPrefixSecure, + UserHandle.getUserHandleForUid(request.userId), + request.isRequesterInstantApp, + request.token + ); + } + private static AuxiliaryResolveInfo filterInstantAppIntent( - List<InstantAppResolveInfo> instantAppResolveInfoList, - Intent origIntent, String resolvedType, int userId, String packageName, - InstantAppDigest digest, String token) { + List<InstantAppResolveInfo> instantAppResolveInfoList, Intent origIntent, + String resolvedType, int userId, String packageName, String token, + int[] hostDigestPrefixSecure) { + InstantAppDigest digest = InstantAppResolver.parseDigest(origIntent); final int[] shaPrefix = digest.getDigestPrefix(); final byte[][] digestBytes = digest.getDigestBytes(); boolean requiresSecondPhase = false; @@ -404,7 +431,7 @@ public abstract class InstantAppResolver { } if (filters != null && !filters.isEmpty()) { return new AuxiliaryResolveInfo(token, requiresSecondPhase, - createFailureIntent(origIntent, token), filters); + createFailureIntent(origIntent, token), filters, hostDigestPrefixSecure); } // Hash or filter mis-match; no instant apps for this domain. return null; diff --git a/services/core/java/com/android/server/pm/InstantAppResolverConnection.java b/services/core/java/com/android/server/pm/InstantAppResolverConnection.java index c0e9f58f3b8e..0fe2eb1e6f4b 100644 --- a/services/core/java/com/android/server/pm/InstantAppResolverConnection.java +++ b/services/core/java/com/android/server/pm/InstantAppResolverConnection.java @@ -24,6 +24,7 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; +import android.content.pm.InstantAppRequestInfo; import android.content.pm.InstantAppResolveInfo; import android.os.Binder; import android.os.Build; @@ -85,13 +86,13 @@ final class InstantAppResolverConnection implements DeathRecipient { mBgHandler = BackgroundThread.getHandler(); } - public List<InstantAppResolveInfo> getInstantAppResolveInfoList(Intent sanitizedIntent, - int[] hashPrefix, int userId, String token) throws ConnectionException { + public List<InstantAppResolveInfo> getInstantAppResolveInfoList(InstantAppRequestInfo request) + throws ConnectionException { throwIfCalledOnMainThread(); IInstantAppResolver target = null; try { try { - target = getRemoteInstanceLazy(token); + target = getRemoteInstanceLazy(request.token); } catch (TimeoutException e) { throw new ConnectionException(ConnectionException.FAILURE_BIND); } catch (InterruptedException e) { @@ -99,8 +100,7 @@ final class InstantAppResolverConnection implements DeathRecipient { } try { return mGetInstantAppResolveInfoCaller - .getInstantAppResolveInfoList(target, sanitizedIntent, hashPrefix, userId, - token); + .getInstantAppResolveInfoList(target, request); } catch (TimeoutException e) { throw new ConnectionException(ConnectionException.FAILURE_CALL); } catch (RemoteException ignore) { @@ -113,8 +113,8 @@ final class InstantAppResolverConnection implements DeathRecipient { return null; } - public void getInstantAppIntentFilterList(Intent sanitizedIntent, int[] hashPrefix, int userId, - String token, PhaseTwoCallback callback, Handler callbackHandler, final long startTime) + public void getInstantAppIntentFilterList(InstantAppRequestInfo request, + PhaseTwoCallback callback, Handler callbackHandler, final long startTime) throws ConnectionException { final IRemoteCallback remoteCallback = new IRemoteCallback.Stub() { @Override @@ -126,9 +126,8 @@ final class InstantAppResolverConnection implements DeathRecipient { } }; try { - getRemoteInstanceLazy(token) - .getInstantAppIntentFilterList(sanitizedIntent, hashPrefix, userId, token, - remoteCallback); + getRemoteInstanceLazy(request.token) + .getInstantAppIntentFilterList(request, remoteCallback); } catch (TimeoutException e) { throw new ConnectionException(ConnectionException.FAILURE_BIND); } catch (InterruptedException e) { @@ -352,12 +351,10 @@ final class InstantAppResolverConnection implements DeathRecipient { }; } - public List<InstantAppResolveInfo> getInstantAppResolveInfoList( - IInstantAppResolver target, Intent sanitizedIntent, int[] hashPrefix, int userId, - String token) throws RemoteException, TimeoutException { + public List<InstantAppResolveInfo> getInstantAppResolveInfoList(IInstantAppResolver target, + InstantAppRequestInfo request) throws RemoteException, TimeoutException { final int sequence = onBeforeRemoteCall(); - target.getInstantAppResolveInfoList(sanitizedIntent, hashPrefix, userId, token, - sequence, mCallback); + target.getInstantAppResolveInfoList(request, sequence, mCallback); return getResultTimed(sequence); } } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index fa98c962afbf..7b002f1f7929 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -154,6 +154,7 @@ import android.content.pm.IPackageMoveObserver; import android.content.pm.IPackageStatsObserver; import android.content.pm.InstantAppInfo; import android.content.pm.InstantAppRequest; +import android.content.pm.InstantAppResolveInfo.InstantAppDigest; import android.content.pm.InstrumentationInfo; import android.content.pm.IntentFilterVerificationInfo; import android.content.pm.KeySet; @@ -363,6 +364,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.UUID; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; @@ -6048,10 +6050,12 @@ public class PackageManagerService extends IPackageManager.Stub private void requestInstantAppResolutionPhaseTwo(AuxiliaryResolveInfo responseObj, Intent origIntent, String resolvedType, String callingPackage, - Bundle verificationBundle, int userId) { + boolean isRequesterInstantApp, Bundle verificationBundle, int userId) { final Message msg = mHandler.obtainMessage(INSTANT_APP_RESOLUTION_PHASE_TWO, new InstantAppRequest(responseObj, origIntent, resolvedType, - callingPackage, userId, verificationBundle, false /*resolveForStart*/)); + callingPackage, isRequesterInstantApp, userId, verificationBundle, + false /*resolveForStart*/, responseObj.hostDigestPrefixSecure, + responseObj.token)); mHandler.sendMessage(msg); } @@ -6668,8 +6672,10 @@ public class PackageManagerService extends IPackageManager.Stub } } if (addInstant) { - result = maybeAddInstantAppInstaller( - result, intent, resolvedType, flags, userId, resolveForStart); + String callingPkgName = getInstantAppPackageName(filterCallingUid); + boolean isRequesterInstantApp = isInstantApp(callingPkgName, userId); + result = maybeAddInstantAppInstaller(result, intent, resolvedType, flags, userId, + resolveForStart, isRequesterInstantApp); } if (sortResult) { Collections.sort(result, RESOLVE_PRIORITY_SORTER); @@ -6680,7 +6686,8 @@ public class PackageManagerService extends IPackageManager.Stub } private List<ResolveInfo> maybeAddInstantAppInstaller(List<ResolveInfo> result, Intent intent, - String resolvedType, int flags, int userId, boolean resolveForStart) { + String resolvedType, int flags, int userId, boolean resolveForStart, + boolean isRequesterInstantApp) { // first, check to see if we've got an instant app already installed final boolean alreadyResolvedLocally = (flags & PackageManager.MATCH_INSTANT) != 0; ResolveInfo localInstantApp = null; @@ -6728,10 +6735,13 @@ public class PackageManagerService extends IPackageManager.Stub if (localInstantApp == null) { // we don't have an instant app locally, resolve externally Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveEphemeral"); + String token = UUID.randomUUID().toString(); + InstantAppDigest digest = InstantAppResolver.parseDigest(intent); final InstantAppRequest requestObject = new InstantAppRequest( null /*responseObj*/, intent /*origIntent*/, resolvedType, - null /*callingPackage*/, userId, null /*verificationBundle*/, - resolveForStart); + null /*callingPackage*/, isRequesterInstantApp, + userId, null /*verificationBundle*/, resolveForStart, + digest.getDigestPrefixSecure(), token); auxiliaryResponse = InstantAppResolver.doInstantAppResolutionPhaseOne( mInstantAppResolverConnection, requestObject); Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); @@ -23167,10 +23177,10 @@ public class PackageManagerService extends IPackageManager.Stub @Override public void requestInstantAppResolutionPhaseTwo(AuxiliaryResolveInfo responseObj, Intent origIntent, String resolvedType, String callingPackage, - Bundle verificationBundle, int userId) { + boolean isRequesterInstantApp, Bundle verificationBundle, int userId) { PackageManagerService.this.requestInstantAppResolutionPhaseTwo( - responseObj, origIntent, resolvedType, callingPackage, verificationBundle, - userId); + responseObj, origIntent, resolvedType, callingPackage, isRequesterInstantApp, + verificationBundle, userId); } @Override diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index be7f88700d88..7aee19e9b766 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -99,6 +99,7 @@ import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.AuxiliaryResolveInfo; import android.content.pm.PackageManager; +import android.content.pm.PackageManagerInternal; import android.content.pm.ResolveInfo; import android.content.pm.UserInfo; import android.content.res.Configuration; @@ -1302,9 +1303,11 @@ class ActivityStarter { String resolvedType, int userId) { if (auxiliaryResponse != null && auxiliaryResponse.needsPhaseTwo) { // request phase two resolution - mService.getPackageManagerInternalLocked().requestInstantAppResolutionPhaseTwo( + PackageManagerInternal packageManager = mService.getPackageManagerInternalLocked(); + boolean isRequesterInstantApp = packageManager.isInstantApp(callingPackage, userId); + packageManager.requestInstantAppResolutionPhaseTwo( auxiliaryResponse, originalIntent, resolvedType, callingPackage, - verificationBundle, userId); + isRequesterInstantApp, verificationBundle, userId); } return InstantAppResolver.buildEphemeralInstallerIntent( originalIntent, |