From 0606861de50995e997d7c117e3bab1eb5db06da8 Mon Sep 17 00:00:00 2001 From: Chad Brubaker Date: Thu, 6 Apr 2017 09:43:47 -0700 Subject: [PATCH] Allow apps to provide the Instant App installer extra information Apps may want to provide additional context information to the instant app installer in order to allow the installer to make smarter choices about the context of the launch. This CL adds a bundle to ActivityOptions that is sent to the Installer (if an Instant App is launched) but not to any other application if something else on the device handles the Intent instead. Bug: 35180854 Test: manual Change-Id: Ifc69a420a9c68041b39acd8a4b83db8a789822a6 --- api/current.txt | 1 + api/system-current.txt | 1 + api/test-current.txt | 1 + core/java/android/app/ActivityOptions.java | 32 +++++++++++++++++++ core/java/android/content/Intent.java | 15 +++++++++ .../android/content/pm/InstantAppRequest.java | 10 ++++-- .../content/pm/PackageManagerInternal.java | 5 ++- .../android/server/am/ActivityStarter.java | 13 +++++--- .../android/server/pm/InstantAppResolver.java | 7 ++++ .../server/pm/PackageManagerService.java | 12 ++++--- 10 files changed, 85 insertions(+), 12 deletions(-) diff --git a/api/current.txt b/api/current.txt index e8c13ece884e6..50d81063937c7 100644 --- a/api/current.txt +++ b/api/current.txt @@ -4029,6 +4029,7 @@ package android.app { method public static android.app.ActivityOptions makeTaskLaunchBehind(); method public static android.app.ActivityOptions makeThumbnailScaleUpAnimation(android.view.View, android.graphics.Bitmap, int, int); method public void requestUsageTimeReport(android.app.PendingIntent); + method public android.app.ActivityOptions setAppVerificationBundle(android.os.Bundle); method public android.app.ActivityOptions setLaunchBounds(android.graphics.Rect); method public android.app.ActivityOptions setLaunchDisplayId(int); method public android.os.Bundle toBundle(); diff --git a/api/system-current.txt b/api/system-current.txt index c8742bbf883f1..dc370fddc55ae 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -4178,6 +4178,7 @@ package android.app { method public static android.app.ActivityOptions makeTaskLaunchBehind(); method public static android.app.ActivityOptions makeThumbnailScaleUpAnimation(android.view.View, android.graphics.Bitmap, int, int); method public void requestUsageTimeReport(android.app.PendingIntent); + method public android.app.ActivityOptions setAppVerificationBundle(android.os.Bundle); method public android.app.ActivityOptions setLaunchBounds(android.graphics.Rect); method public android.app.ActivityOptions setLaunchDisplayId(int); method public android.os.Bundle toBundle(); diff --git a/api/test-current.txt b/api/test-current.txt index adc305b01582b..5e408af1abb57 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -4039,6 +4039,7 @@ package android.app { method public static android.app.ActivityOptions makeTaskLaunchBehind(); method public static android.app.ActivityOptions makeThumbnailScaleUpAnimation(android.view.View, android.graphics.Bitmap, int, int); method public void requestUsageTimeReport(android.app.PendingIntent); + method public android.app.ActivityOptions setAppVerificationBundle(android.os.Bundle); method public android.app.ActivityOptions setLaunchBounds(android.graphics.Rect); method public android.app.ActivityOptions setLaunchDisplayId(int); method public void setLaunchStackId(int); diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java index 63e8cc641ce98..3eec596fcb174 100644 --- a/core/java/android/app/ActivityOptions.java +++ b/core/java/android/app/ActivityOptions.java @@ -211,6 +211,9 @@ public class ActivityOptions { private static final String KEY_USAGE_TIME_REPORT = "android:activity.usageTimeReport"; private static final String KEY_ROTATION_ANIMATION_HINT = "android:activity.rotationAnimationHint"; + private static final String KEY_INSTANT_APP_VERIFICATION_BUNDLE + = "android:instantapps.installerbundle"; + /** @hide */ public static final int ANIM_NONE = 0; /** @hide */ @@ -264,6 +267,7 @@ public class ActivityOptions { private boolean mTaskOverlayCanResume; private AppTransitionAnimationSpec mAnimSpecs[]; private int mRotationAnimationHint = -1; + private Bundle mAppVerificationBundle; /** * Create an ActivityOptions specifying a custom animation to run when @@ -886,6 +890,7 @@ public class ActivityOptions { opts.getBinder(KEY_ANIMATION_FINISHED_LISTENER)); } mRotationAnimationHint = opts.getInt(KEY_ROTATION_ANIMATION_HINT); + mAppVerificationBundle = opts.getBundle(KEY_INSTANT_APP_VERIFICATION_BUNDLE); } /** @@ -1275,6 +1280,9 @@ public class ActivityOptions { b.putBinder(KEY_ANIMATION_FINISHED_LISTENER, mAnimationFinishedListener.asBinder()); } b.putInt(KEY_ROTATION_ANIMATION_HINT, mRotationAnimationHint); + if (mAppVerificationBundle != null) { + b.putBundle(KEY_INSTANT_APP_VERIFICATION_BUNDLE, mAppVerificationBundle); + } return b; } @@ -1342,6 +1350,30 @@ public class ActivityOptions { mRotationAnimationHint = hint; } + /** + * Pop the extra verification bundle for the installer. + * This removes the bundle from the ActivityOptions to make sure the installer bundle + * is only available once. + * @hide + */ + public Bundle popAppVerificationBundle() { + Bundle out = mAppVerificationBundle; + mAppVerificationBundle = null; + return out; + } + + /** + * Set the {@link Bundle} that is provided to the app installer for additional verification + * if the call to {@link Context#startActivity} results in an app being installed. + * + * This Bundle is not provided to any other app besides the installer. + */ + public ActivityOptions setAppVerificationBundle(Bundle bundle) { + mAppVerificationBundle = bundle; + return this; + + } + /** @hide */ @Override public String toString() { diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 9c87ff27caafa..857cbe82d07da 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -4416,6 +4416,21 @@ public class Intent implements Parcelable, Cloneable { */ public static final String EXTRA_VERSION_CODE = "android.intent.extra.VERSION_CODE"; + /** + * The app that triggered the ephemeral installation. + * @hide + */ + public static final String EXTRA_CALLING_PACKAGE + = "android.intent.extra.CALLING_PACKAGE"; + + /** + * Optional calling app provided bundle containing additional launch information the + * installer may use. + * @hide + */ + public static final String EXTRA_VERIFICATION_BUNDLE + = "android.intent.extra.VERIFICATION_BUNDLE"; + /** * A Bundle forming a mapping of potential target package names to different extras Bundles * to add to the default intent extras in {@link #EXTRA_INTENT} when used with diff --git a/core/java/android/content/pm/InstantAppRequest.java b/core/java/android/content/pm/InstantAppRequest.java index b45169d324be6..27d28287b6ae3 100644 --- a/core/java/android/content/pm/InstantAppRequest.java +++ b/core/java/android/content/pm/InstantAppRequest.java @@ -17,6 +17,7 @@ package android.content.pm; import android.content.Intent; +import android.os.Bundle; /** * Information needed to make an instant application resolution request. @@ -33,13 +34,18 @@ public final class InstantAppRequest { public final String callingPackage; /** 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. */ + public final Bundle verificationBundle; public InstantAppRequest(AuxiliaryResolveInfo responseObj, Intent origIntent, - String resolvedType, String callingPackage, int userId) { + String resolvedType, String callingPackage, int userId, Bundle verificationBundle) { this.responseObj = responseObj; this.origIntent = origIntent; this.resolvedType = resolvedType; this.callingPackage = callingPackage; this.userId = userId; + this.verificationBundle = verificationBundle; } -} \ No newline at end of file +} diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java index 7bfde751e1559..8e34728efcb16 100644 --- a/core/java/android/content/pm/PackageManagerInternal.java +++ b/core/java/android/content/pm/PackageManagerInternal.java @@ -19,6 +19,7 @@ package android.content.pm; import android.content.ComponentName; import android.content.Intent; import android.content.pm.PackageManager.NameNotFoundException; +import android.os.Bundle; import android.util.SparseArray; import java.util.List; @@ -215,11 +216,13 @@ public abstract class PackageManagerInternal { * @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 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, - int userId); + Bundle verificationBundle, int userId); /** * Grants access to the package metadata for an ephemeral application. diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java index 1f4b21b14ed59..ca842d5574d32 100644 --- a/services/core/java/com/android/server/am/ActivityStarter.java +++ b/services/core/java/com/android/server/am/ActivityStarter.java @@ -245,6 +245,9 @@ class ActivityStarter { ActivityRecord[] outActivity, ActivityStackSupervisor.ActivityContainer container, TaskRecord inTask) { int err = ActivityManager.START_SUCCESS; + // Pull the optional Ephemeral Installer-only bundle out of the options early. + final Bundle verificationBundle + = options != null ? options.popAppVerificationBundle() : null; ProcessRecord callerApp = null; if (caller != null) { @@ -466,7 +469,7 @@ class ActivityStarter { // app [on install success]. if (rInfo != null && rInfo.auxiliaryInfo != null) { intent = createLaunchIntent(rInfo.auxiliaryInfo, ephemeralIntent, - callingPackage, resolvedType, userId); + callingPackage, verificationBundle, resolvedType, userId); resolvedType = null; callingUid = realCallingUid; callingPid = realCallingPid; @@ -522,14 +525,16 @@ class ActivityStarter { * Creates a launch intent for the given auxiliary resolution data. */ private @NonNull Intent createLaunchIntent(@NonNull AuxiliaryResolveInfo auxiliaryResponse, - Intent originalIntent, String callingPackage, String resolvedType, int userId) { + Intent originalIntent, String callingPackage, Bundle verificationBundle, + String resolvedType, int userId) { if (auxiliaryResponse.needsPhaseTwo) { // request phase two resolution mService.getPackageManagerInternalLocked().requestInstantAppResolutionPhaseTwo( - auxiliaryResponse, originalIntent, resolvedType, callingPackage, userId); + auxiliaryResponse, originalIntent, resolvedType, callingPackage, + verificationBundle, userId); } return InstantAppResolver.buildEphemeralInstallerIntent(originalIntent, - callingPackage, resolvedType, userId, auxiliaryResponse.packageName, + callingPackage, verificationBundle, resolvedType, userId, auxiliaryResponse.packageName, auxiliaryResponse.splitName, auxiliaryResponse.versionCode, auxiliaryResponse.token, auxiliaryResponse.needsPhaseTwo); } diff --git a/services/core/java/com/android/server/pm/InstantAppResolver.java b/services/core/java/com/android/server/pm/InstantAppResolver.java index b56db047fd302..624d8c9ef13ea 100644 --- a/services/core/java/com/android/server/pm/InstantAppResolver.java +++ b/services/core/java/com/android/server/pm/InstantAppResolver.java @@ -41,6 +41,7 @@ import android.content.pm.InstantAppResolveInfo.InstantAppDigest; import android.metrics.LogMaker; import android.os.Binder; import android.os.Build; +import android.os.Bundle; import android.os.Handler; import android.os.RemoteException; import android.util.Log; @@ -147,6 +148,7 @@ public abstract class InstantAppResolver { final Intent installerIntent = buildEphemeralInstallerIntent( requestObj.origIntent, requestObj.callingPackage, + requestObj.verificationBundle, requestObj.resolvedType, requestObj.userId, packageName, @@ -172,6 +174,7 @@ public abstract class InstantAppResolver { */ public static Intent buildEphemeralInstallerIntent(@NonNull Intent origIntent, @NonNull String callingPackage, + @Nullable Bundle verificationBundle, @NonNull String resolvedType, int userId, @NonNull String instantAppPackageName, @@ -234,6 +237,10 @@ public abstract class InstantAppResolver { intent.putExtra(Intent.EXTRA_PACKAGE_NAME, instantAppPackageName); intent.putExtra(Intent.EXTRA_SPLIT_NAME, instantAppSplitName); intent.putExtra(Intent.EXTRA_VERSION_CODE, versionCode); + intent.putExtra(Intent.EXTRA_CALLING_PACKAGE, callingPackage); + if (verificationBundle != null) { + intent.putExtra(Intent.EXTRA_VERIFICATION_BUNDLE, verificationBundle); + } } return intent; diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index faa99342b9dc6..c1c3537b1950b 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -5807,10 +5807,10 @@ public class PackageManagerService extends IPackageManager.Stub private void requestInstantAppResolutionPhaseTwo(AuxiliaryResolveInfo responseObj, Intent origIntent, String resolvedType, String callingPackage, - int userId) { + Bundle verificationBundle, int userId) { final Message msg = mHandler.obtainMessage(INSTANT_APP_RESOLUTION_PHASE_TWO, new InstantAppRequest(responseObj, origIntent, resolvedType, - callingPackage, userId)); + callingPackage, userId, verificationBundle)); mHandler.sendMessage(msg); } @@ -6350,7 +6350,7 @@ public class PackageManagerService extends IPackageManager.Stub Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveEphemeral"); final InstantAppRequest requestObject = new InstantAppRequest( null /*responseObj*/, intent /*origIntent*/, resolvedType, - null /*callingPackage*/, userId); + null /*callingPackage*/, userId, null /*verificationBundle*/); final AuxiliaryResolveInfo auxiliaryResponse = InstantAppResolver.doInstantAppResolutionPhaseOne( mContext, mInstantAppResolverConnection, requestObject); @@ -23392,9 +23392,11 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); @Override public void requestInstantAppResolutionPhaseTwo(AuxiliaryResolveInfo responseObj, - Intent origIntent, String resolvedType, String callingPackage, int userId) { + Intent origIntent, String resolvedType, String callingPackage, + Bundle verificationBundle, int userId) { PackageManagerService.this.requestInstantAppResolutionPhaseTwo( - responseObj, origIntent, resolvedType, callingPackage, userId); + responseObj, origIntent, resolvedType, callingPackage, verificationBundle, + userId); } @Override