Loading core/java/android/app/PendingIntent.java +54 −9 Original line number Diff line number Diff line Loading @@ -33,6 +33,8 @@ import android.app.ActivityManager.PendingIntentInfo; import android.compat.Compatibility; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledAfter; import android.compat.annotation.EnabledSince; import android.compat.annotation.Overridable; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.IIntentReceiver; Loading @@ -53,6 +55,7 @@ import android.os.RemoteException; import android.os.UserHandle; import android.util.AndroidException; import android.util.ArraySet; import android.util.Log; import android.util.Pair; import android.util.proto.ProtoOutputStream; Loading Loading @@ -166,6 +169,12 @@ public final class PendingIntent implements Parcelable { @EnabledAfter(targetSdkVersion = android.os.Build.VERSION_CODES.R) static final long PENDING_INTENT_EXPLICIT_MUTABILITY_REQUIRED = 160794467L; /** @hide */ @ChangeId @EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE) @Overridable public static final long BLOCK_MUTABLE_IMPLICIT_PENDING_INTENT = 236704164L; /** @hide */ @IntDef(flag = true, value = { Loading Loading @@ -381,17 +390,19 @@ public final class PendingIntent implements Parcelable { sOnMarshaledListener.set(listener); } private static void checkFlags(int flags, String packageName) { final boolean flagImmutableSet = (flags & PendingIntent.FLAG_IMMUTABLE) != 0; final boolean flagMutableSet = (flags & PendingIntent.FLAG_MUTABLE) != 0; private static void checkPendingIntent(int flags, @NonNull Intent intent, @NonNull Context context) { final boolean isFlagImmutableSet = (flags & PendingIntent.FLAG_IMMUTABLE) != 0; final boolean isFlagMutableSet = (flags & PendingIntent.FLAG_MUTABLE) != 0; final String packageName = context.getPackageName(); if (flagImmutableSet && flagMutableSet) { if (isFlagImmutableSet && isFlagMutableSet) { throw new IllegalArgumentException( "Cannot set both FLAG_IMMUTABLE and FLAG_MUTABLE for PendingIntent"); } if (Compatibility.isChangeEnabled(PENDING_INTENT_EXPLICIT_MUTABILITY_REQUIRED) && !flagImmutableSet && !flagMutableSet) { && !isFlagImmutableSet && !isFlagMutableSet) { String msg = packageName + ": Targeting S+ (version " + Build.VERSION_CODES.S + " and above) requires that one of FLAG_IMMUTABLE or FLAG_MUTABLE" + " be specified when creating a PendingIntent.\nStrongly consider" Loading @@ -400,6 +411,40 @@ public final class PendingIntent implements Parcelable { + " be used with inline replies or bubbles."; throw new IllegalArgumentException(msg); } // Whenever creation or retrieval of a mutable implicit PendingIntent occurs: // - For apps with target SDK >= U, Log.wtfStack() that it is blocked for security reasons. // This will be changed to a throw of an exception on the server side once we finish // migrating to safer PendingIntents b/262253127. // - Otherwise, warn that it will be blocked from target SDK U. if (isNewMutableImplicitPendingIntent(flags, intent)) { if (Compatibility.isChangeEnabled(BLOCK_MUTABLE_IMPLICIT_PENDING_INTENT)) { String msg = packageName + ": Targeting U+ (version " + Build.VERSION_CODES.UPSIDE_DOWN_CAKE + " and above) disallows" + " creating or retrieving a PendingIntent with FLAG_MUTABLE," + " an implicit Intent within and without FLAG_NO_CREATE for" + " security reasons. To retrieve an already existing" + " PendingIntent, use FLAG_NO_CREATE, however, to create a" + " new PendingIntent with an implicit Intent use" + " FLAG_IMMUTABLE."; Log.wtfStack(TAG, msg); } else { String msg = "New mutable implicit PendingIntent: pkg=" + packageName + ", action=" + intent.getAction() + ", featureId=" + context.getAttributionTag() + ". This will be blocked once the app targets U+" + " for security reasons."; Log.w(TAG, new RuntimeException(msg)); } } } /** @hide */ public static boolean isNewMutableImplicitPendingIntent(int flags, @NonNull Intent intent) { boolean isFlagNoCreateSet = (flags & PendingIntent.FLAG_NO_CREATE) != 0; boolean isFlagMutableSet = (flags & PendingIntent.FLAG_MUTABLE) != 0; boolean isImplicit = (intent.getComponent() == null) && (intent.getPackage() == null); return !isFlagNoCreateSet && isFlagMutableSet && isImplicit; } /** Loading Loading @@ -481,7 +526,7 @@ public final class PendingIntent implements Parcelable { @NonNull Intent intent, int flags, Bundle options, UserHandle user) { String packageName = context.getPackageName(); String resolvedType = intent.resolveTypeIfNeeded(context.getContentResolver()); checkFlags(flags, packageName); checkPendingIntent(flags, intent, context); try { intent.migrateExtraStreamToClipData(context); intent.prepareToLeaveProcess(context); Loading Loading @@ -615,8 +660,8 @@ public final class PendingIntent implements Parcelable { intents[i].migrateExtraStreamToClipData(context); intents[i].prepareToLeaveProcess(context); resolvedTypes[i] = intents[i].resolveTypeIfNeeded(context.getContentResolver()); checkPendingIntent(flags, intents[i], context); } checkFlags(flags, packageName); try { IIntentSender target = ActivityManager.getService().getIntentSenderWithFeature( Loading Loading @@ -668,7 +713,7 @@ public final class PendingIntent implements Parcelable { Intent intent, int flags, UserHandle userHandle) { String packageName = context.getPackageName(); String resolvedType = intent.resolveTypeIfNeeded(context.getContentResolver()); checkFlags(flags, packageName); checkPendingIntent(flags, intent, context); try { intent.prepareToLeaveProcess(context); IIntentSender target = Loading Loading @@ -747,7 +792,7 @@ public final class PendingIntent implements Parcelable { Intent intent, int flags, int serviceKind) { String packageName = context.getPackageName(); String resolvedType = intent.resolveTypeIfNeeded(context.getContentResolver()); checkFlags(flags, packageName); checkPendingIntent(flags, intent, context); try { intent.prepareToLeaveProcess(context); IIntentSender target = Loading Loading
core/java/android/app/PendingIntent.java +54 −9 Original line number Diff line number Diff line Loading @@ -33,6 +33,8 @@ import android.app.ActivityManager.PendingIntentInfo; import android.compat.Compatibility; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledAfter; import android.compat.annotation.EnabledSince; import android.compat.annotation.Overridable; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.IIntentReceiver; Loading @@ -53,6 +55,7 @@ import android.os.RemoteException; import android.os.UserHandle; import android.util.AndroidException; import android.util.ArraySet; import android.util.Log; import android.util.Pair; import android.util.proto.ProtoOutputStream; Loading Loading @@ -166,6 +169,12 @@ public final class PendingIntent implements Parcelable { @EnabledAfter(targetSdkVersion = android.os.Build.VERSION_CODES.R) static final long PENDING_INTENT_EXPLICIT_MUTABILITY_REQUIRED = 160794467L; /** @hide */ @ChangeId @EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE) @Overridable public static final long BLOCK_MUTABLE_IMPLICIT_PENDING_INTENT = 236704164L; /** @hide */ @IntDef(flag = true, value = { Loading Loading @@ -381,17 +390,19 @@ public final class PendingIntent implements Parcelable { sOnMarshaledListener.set(listener); } private static void checkFlags(int flags, String packageName) { final boolean flagImmutableSet = (flags & PendingIntent.FLAG_IMMUTABLE) != 0; final boolean flagMutableSet = (flags & PendingIntent.FLAG_MUTABLE) != 0; private static void checkPendingIntent(int flags, @NonNull Intent intent, @NonNull Context context) { final boolean isFlagImmutableSet = (flags & PendingIntent.FLAG_IMMUTABLE) != 0; final boolean isFlagMutableSet = (flags & PendingIntent.FLAG_MUTABLE) != 0; final String packageName = context.getPackageName(); if (flagImmutableSet && flagMutableSet) { if (isFlagImmutableSet && isFlagMutableSet) { throw new IllegalArgumentException( "Cannot set both FLAG_IMMUTABLE and FLAG_MUTABLE for PendingIntent"); } if (Compatibility.isChangeEnabled(PENDING_INTENT_EXPLICIT_MUTABILITY_REQUIRED) && !flagImmutableSet && !flagMutableSet) { && !isFlagImmutableSet && !isFlagMutableSet) { String msg = packageName + ": Targeting S+ (version " + Build.VERSION_CODES.S + " and above) requires that one of FLAG_IMMUTABLE or FLAG_MUTABLE" + " be specified when creating a PendingIntent.\nStrongly consider" Loading @@ -400,6 +411,40 @@ public final class PendingIntent implements Parcelable { + " be used with inline replies or bubbles."; throw new IllegalArgumentException(msg); } // Whenever creation or retrieval of a mutable implicit PendingIntent occurs: // - For apps with target SDK >= U, Log.wtfStack() that it is blocked for security reasons. // This will be changed to a throw of an exception on the server side once we finish // migrating to safer PendingIntents b/262253127. // - Otherwise, warn that it will be blocked from target SDK U. if (isNewMutableImplicitPendingIntent(flags, intent)) { if (Compatibility.isChangeEnabled(BLOCK_MUTABLE_IMPLICIT_PENDING_INTENT)) { String msg = packageName + ": Targeting U+ (version " + Build.VERSION_CODES.UPSIDE_DOWN_CAKE + " and above) disallows" + " creating or retrieving a PendingIntent with FLAG_MUTABLE," + " an implicit Intent within and without FLAG_NO_CREATE for" + " security reasons. To retrieve an already existing" + " PendingIntent, use FLAG_NO_CREATE, however, to create a" + " new PendingIntent with an implicit Intent use" + " FLAG_IMMUTABLE."; Log.wtfStack(TAG, msg); } else { String msg = "New mutable implicit PendingIntent: pkg=" + packageName + ", action=" + intent.getAction() + ", featureId=" + context.getAttributionTag() + ". This will be blocked once the app targets U+" + " for security reasons."; Log.w(TAG, new RuntimeException(msg)); } } } /** @hide */ public static boolean isNewMutableImplicitPendingIntent(int flags, @NonNull Intent intent) { boolean isFlagNoCreateSet = (flags & PendingIntent.FLAG_NO_CREATE) != 0; boolean isFlagMutableSet = (flags & PendingIntent.FLAG_MUTABLE) != 0; boolean isImplicit = (intent.getComponent() == null) && (intent.getPackage() == null); return !isFlagNoCreateSet && isFlagMutableSet && isImplicit; } /** Loading Loading @@ -481,7 +526,7 @@ public final class PendingIntent implements Parcelable { @NonNull Intent intent, int flags, Bundle options, UserHandle user) { String packageName = context.getPackageName(); String resolvedType = intent.resolveTypeIfNeeded(context.getContentResolver()); checkFlags(flags, packageName); checkPendingIntent(flags, intent, context); try { intent.migrateExtraStreamToClipData(context); intent.prepareToLeaveProcess(context); Loading Loading @@ -615,8 +660,8 @@ public final class PendingIntent implements Parcelable { intents[i].migrateExtraStreamToClipData(context); intents[i].prepareToLeaveProcess(context); resolvedTypes[i] = intents[i].resolveTypeIfNeeded(context.getContentResolver()); checkPendingIntent(flags, intents[i], context); } checkFlags(flags, packageName); try { IIntentSender target = ActivityManager.getService().getIntentSenderWithFeature( Loading Loading @@ -668,7 +713,7 @@ public final class PendingIntent implements Parcelable { Intent intent, int flags, UserHandle userHandle) { String packageName = context.getPackageName(); String resolvedType = intent.resolveTypeIfNeeded(context.getContentResolver()); checkFlags(flags, packageName); checkPendingIntent(flags, intent, context); try { intent.prepareToLeaveProcess(context); IIntentSender target = Loading Loading @@ -747,7 +792,7 @@ public final class PendingIntent implements Parcelable { Intent intent, int flags, int serviceKind) { String packageName = context.getPackageName(); String resolvedType = intent.resolveTypeIfNeeded(context.getContentResolver()); checkFlags(flags, packageName); checkPendingIntent(flags, intent, context); try { intent.prepareToLeaveProcess(context); IIntentSender target = Loading