Define FLAG_MUTABLE and add a compat change for explicit definition of PendingIntent mutability flags

For future releases, we will require that either FLAG_IMMUTABLE or
FLAG_MUTABLE is defined when a PendingIntent is created.

The check only results in a log.wtf for now while we notify, identify,
and update major PendingIntents. We will add a stricter
IllegalArgumentException soon.

- Define FLAG_MUTABLE
- Add a check and log.wtf that either FLAG_IMMUTABLE or FLAG_MUTABLE is
  specified on creation for future releases
- Update api/current.txt and non-updatable-api/current.txt to include
  FLAG_MUTABLE

Test: atest PendingIntentTest
Bug: 160794467
Change-Id: I1f1f72c6ce22358e98e9f38be2fb98b27e60898c
This commit is contained in:
Ashwini Oruganti
2020-08-26 14:24:18 -07:00
parent 38cc1531f3
commit 571ed8dc58
3 changed files with 54 additions and 0 deletions

View File

@@ -6138,6 +6138,7 @@ package android.app {
field @NonNull public static final android.os.Parcelable.Creator<android.app.PendingIntent> CREATOR;
field public static final int FLAG_CANCEL_CURRENT = 268435456; // 0x10000000
field public static final int FLAG_IMMUTABLE = 67108864; // 0x4000000
field public static final int FLAG_MUTABLE = 33554432; // 0x2000000
field public static final int FLAG_NO_CREATE = 536870912; // 0x20000000
field public static final int FLAG_ONE_SHOT = 1073741824; // 0x40000000
field public static final int FLAG_UPDATE_CURRENT = 134217728; // 0x8000000

View File

@@ -19,12 +19,16 @@ package android.app;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.compat.Compatibility;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledAfter;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.IIntentReceiver;
import android.content.IIntentSender;
import android.content.Intent;
import android.content.IntentSender;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -35,6 +39,7 @@ import android.os.RemoteException;
import android.os.UserHandle;
import android.util.AndroidException;
import android.util.ArraySet;
import android.util.Log;
import android.util.proto.ProtoOutputStream;
import com.android.internal.os.IResultReceiver;
@@ -102,11 +107,20 @@ import java.lang.annotation.RetentionPolicy;
* FLAG_ONE_SHOT, <b>both</b> FLAG_ONE_SHOT and FLAG_NO_CREATE need to be supplied.
*/
public final class PendingIntent implements Parcelable {
private static final String TAG = "PendingIntent";
private final IIntentSender mTarget;
private IResultReceiver mCancelReceiver;
private IBinder mWhitelistToken;
private ArraySet<CancelListener> mCancelListeners;
/**
* It is now required to specify either {@link #FLAG_IMMUTABLE}
* or {@link #FLAG_MUTABLE} when creating a PendingIntent.
*/
@ChangeId
@EnabledAfter(targetSdkVersion = android.os.Build.VERSION_CODES.R)
static final long PENDING_INTENT_EXPLICIT_MUTABILITY_REQUIRED = 160794467L;
/** @hide */
@IntDef(flag = true,
value = {
@@ -115,6 +129,7 @@ public final class PendingIntent implements Parcelable {
FLAG_CANCEL_CURRENT,
FLAG_UPDATE_CURRENT,
FLAG_IMMUTABLE,
FLAG_MUTABLE,
Intent.FILL_IN_ACTION,
Intent.FILL_IN_DATA,
@@ -174,6 +189,20 @@ public final class PendingIntent implements Parcelable {
*/
public static final int FLAG_IMMUTABLE = 1<<26;
/**
* Flag indicating that the created PendingIntent should be mutable.
* This flag cannot be combined with {@link #FLAG_IMMUTABLE}. <p>Up until
* {@link android.os.Build.VERSION_CODES#R}, PendingIntents are assumed to
* be mutable by default, unless {@link #FLAG_IMMUTABLE} is set. Starting
* with {@link android.os.Build.VERSION_CODES#S}, it will be required to
* explicitly specify the mutability of PendingIntents on creation with
* either (@link #FLAG_IMMUTABLE} or {@link #FLAG_MUTABLE}. It is strongly
* recommended to use {@link #FLAG_IMMUTABLE} when creating a
* PendingIntent. {@link #FLAG_MUTABLE} should only be used when some
* functionality relies on modifying the underlying intent.
*/
public static final int FLAG_MUTABLE = 1<<25;
/**
* Exception thrown when trying to send through a PendingIntent that
* has been canceled or is otherwise no longer able to execute the request.
@@ -286,6 +315,23 @@ 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;
if (flagImmutableSet && flagMutableSet) {
throw new IllegalArgumentException(
"Cannot set both FLAG_IMMUTABLE and FLAG_MUTABLE for PendingIntent");
}
if (Compatibility.isChangeEnabled(PENDING_INTENT_EXPLICIT_MUTABILITY_REQUIRED)
&& !flagImmutableSet && !flagMutableSet) {
Log.wtf(TAG, 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");
}
}
/**
* Retrieve a PendingIntent that will start a new activity, like calling
* {@link Context#startActivity(Intent) Context.startActivity(Intent)}.
@@ -350,6 +396,7 @@ public final class PendingIntent implements Parcelable {
String packageName = context.getPackageName();
String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
context.getContentResolver()) : null;
checkFlags(flags, packageName);
try {
intent.migrateExtraStreamToClipData(context);
intent.prepareToLeaveProcess(context);
@@ -376,6 +423,7 @@ public final class PendingIntent implements Parcelable {
String packageName = context.getPackageName();
String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
context.getContentResolver()) : null;
checkFlags(flags, packageName);
try {
intent.migrateExtraStreamToClipData(context);
intent.prepareToLeaveProcess(context);
@@ -495,6 +543,7 @@ public final class PendingIntent implements Parcelable {
intents[i].prepareToLeaveProcess(context);
resolvedTypes[i] = intents[i].resolveTypeIfNeeded(context.getContentResolver());
}
checkFlags(flags, packageName);
try {
IIntentSender target =
ActivityManager.getService().getIntentSenderWithFeature(
@@ -521,6 +570,7 @@ public final class PendingIntent implements Parcelable {
intents[i].prepareToLeaveProcess(context);
resolvedTypes[i] = intents[i].resolveTypeIfNeeded(context.getContentResolver());
}
checkFlags(flags, packageName);
try {
IIntentSender target =
ActivityManager.getService().getIntentSenderWithFeature(
@@ -572,6 +622,7 @@ public final class PendingIntent implements Parcelable {
String packageName = context.getPackageName();
String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
context.getContentResolver()) : null;
checkFlags(flags, packageName);
try {
intent.prepareToLeaveProcess(context);
IIntentSender target =
@@ -651,6 +702,7 @@ public final class PendingIntent implements Parcelable {
String packageName = context.getPackageName();
String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
context.getContentResolver()) : null;
checkFlags(flags, packageName);
try {
intent.prepareToLeaveProcess(context);
IIntentSender target =

View File

@@ -6138,6 +6138,7 @@ package android.app {
field @NonNull public static final android.os.Parcelable.Creator<android.app.PendingIntent> CREATOR;
field public static final int FLAG_CANCEL_CURRENT = 268435456; // 0x10000000
field public static final int FLAG_IMMUTABLE = 67108864; // 0x4000000
field public static final int FLAG_MUTABLE = 33554432; // 0x2000000
field public static final int FLAG_NO_CREATE = 536870912; // 0x20000000
field public static final int FLAG_ONE_SHOT = 1073741824; // 0x40000000
field public static final int FLAG_UPDATE_CURRENT = 134217728; // 0x8000000