Merge "Log creation of mutable implicit PendingIntent"

This commit is contained in:
Azhara Assanova
2022-12-16 11:53:11 +00:00
committed by Android (Google) Code Review

View File

@@ -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;
@@ -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;
@@ -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 = {
@@ -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"
@@ -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;
}
/**
@@ -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);
@@ -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(
@@ -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 =
@@ -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 =