Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 98305523 authored by Dianne Hackborn's avatar Dianne Hackborn
Browse files

Fix issue #37360626: Apps can schedule alarms (and other things) with temp whitelist

There is now an IBinder "token" that must be specified when setting
the whitelist duration for an Intent.  To have the whitelist supplied,
the caller to send a PendingIntent must pass in the same token.  The
PendingIntent and IntentSender classes now internally maintain this token
to pass in when their send() is called.

The big complexity for making this work is we now need to associate this
whitelist token correctly with the actual PendingIntent objects that
applications and other code is getting.  To do this, we propagate the
token in the Notification object, and have a new API on Parcel that allows
us to make it available to PendingIntent when it is unmarshalled.  And
this allows to deal with PendingIntents appearing in nested bundles, as
we can propagate that information from the original Parcel to the new
Parcel that Bundle keeps to delay unmarshalling.

Test: manual
Change-Id: Idda00490ccfe2be37e4ab21354b9ab7528a52750
parent 2af0676b
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -51,6 +51,7 @@ import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.IUserManager;
import android.os.ParcelFileDescriptor;
import android.os.Process;
@@ -347,7 +348,7 @@ public final class Pm {

        private IIntentSender.Stub mLocalSender = new IIntentSender.Stub() {
            @Override
            public void send(int code, Intent intent, String resolvedType,
            public void send(int code, Intent intent, String resolvedType, IBinder whitelistToken,
                    IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
                try {
                    mResult.offer(intent, 5, TimeUnit.SECONDS);
+2 −1
Original line number Diff line number Diff line
@@ -169,7 +169,8 @@ public abstract class ActivityManagerInternal {
     *  Sets how long a {@link PendingIntent} can be temporarily whitelist to by bypass restrictions
     *  such as Power Save mode.
     */
    public abstract void setPendingIntentWhitelistDuration(IIntentSender target, long duration);
    public abstract void setPendingIntentWhitelistDuration(IIntentSender target,
            IBinder whitelistToken, long duration);

    /**
     * Allow DeviceIdleController to tell us about what apps are whitelisted.
+2 −2
Original line number Diff line number Diff line
@@ -562,8 +562,8 @@ interface IActivityManager {
    void notifyLockedProfile(int userId);
    void startConfirmDeviceCredentialIntent(in Intent intent, in Bundle options);
    void sendIdleJobTrigger();
    int sendIntentSender(in IIntentSender target, int code, in Intent intent,
            in String resolvedType, in IIntentReceiver finishedReceiver,
    int sendIntentSender(in IIntentSender target, in IBinder whitelistToken, int code,
            in Intent intent, in String resolvedType, in IIntentReceiver finishedReceiver,
            in String requiredPermission, in Bundle options);


+27 −0
Original line number Diff line number Diff line
@@ -42,8 +42,10 @@ import android.media.PlayerBase;
import android.media.session.MediaSession;
import android.net.Uri;
import android.os.BadParcelableException;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemClock;
@@ -834,6 +836,22 @@ public class Notification implements Parcelable
     */
    public ArraySet<PendingIntent> allPendingIntents;

    /**
     * Token identifying the notification that is applying doze/bgcheck whitelisting to the
     * pending intents inside of it, so only those will get the behavior.
     *
     * @hide
     */
    static public IBinder whitelistToken;

    /**
     * Must be set by a process to start associating tokens with Notification objects
     * coming in to it.  This is set by NotificationManagerService.
     *
     * @hide
     */
    static public IBinder processWhitelistToken;

    /**
     * {@link #extras} key: this is the title of the notification,
     * as supplied to {@link Builder#setContentTitle(CharSequence)}.
@@ -1823,6 +1841,13 @@ public class Notification implements Parcelable
    {
        int version = parcel.readInt();

        whitelistToken = parcel.readStrongBinder();
        if (whitelistToken == null) {
            whitelistToken = processWhitelistToken;
        }
        // Propagate this token to all pending intents that are unmarshalled from the parcel.
        parcel.setClassCookie(PendingIntent.class, whitelistToken);

        when = parcel.readLong();
        creationTime = parcel.readLong();
        if (parcel.readInt() != 0) {
@@ -1929,6 +1954,7 @@ public class Notification implements Parcelable
     * @hide
     */
    public void cloneInto(Notification that, boolean heavy) {
        that.whitelistToken = this.whitelistToken;
        that.when = this.when;
        that.creationTime = this.creationTime;
        that.mSmallIcon = this.mSmallIcon;
@@ -2158,6 +2184,7 @@ public class Notification implements Parcelable
    private void writeToParcelImpl(Parcel parcel, int flags) {
        parcel.writeInt(1);

        parcel.writeStrongBinder(whitelistToken);
        parcel.writeLong(when);
        parcel.writeLong(creationTime);
        if (mSmallIcon == null && icon != 0) {
+20 −9
Original line number Diff line number Diff line
@@ -93,6 +93,7 @@ import java.lang.annotation.RetentionPolicy;
 */
public final class PendingIntent implements Parcelable {
    private final IIntentSender mTarget;
    private IBinder mWhitelistToken;

    /** @hide */
    @IntDef(flag = true,
@@ -656,7 +657,7 @@ public final class PendingIntent implements Parcelable {
     *
     */
    public IntentSender getIntentSender() {
        return new IntentSender(mTarget);
        return new IntentSender(mTarget, mWhitelistToken);
    }

    /**
@@ -870,7 +871,7 @@ public final class PendingIntent implements Parcelable {
                    intent.resolveTypeIfNeeded(context.getContentResolver())
                    : null;
            int res = ActivityManager.getService().sendIntentSender(
                    mTarget, code, intent, resolvedType,
                    mTarget, mWhitelistToken, code, intent, resolvedType,
                    onFinished != null
                            ? new FinishedDispatcher(this, onFinished, handler)
                            : null,
@@ -1085,7 +1086,9 @@ public final class PendingIntent implements Parcelable {
            = new Parcelable.Creator<PendingIntent>() {
        public PendingIntent createFromParcel(Parcel in) {
            IBinder target = in.readStrongBinder();
            return target != null ? new PendingIntent(target) : null;
            return target != null
                    ? new PendingIntent(target, in.getClassCookie(PendingIntent.class))
                    : null;
        }

        public PendingIntent[] newArray(int size) {
@@ -1108,31 +1111,39 @@ public final class PendingIntent implements Parcelable {
    }

    /**
     * Convenience function for reading either a Messenger or null pointer from
     * a Parcel.  You must have previously written the Messenger with
     * Convenience function for reading either a PendingIntent or null pointer from
     * a Parcel.  You must have previously written the PendingIntent with
     * {@link #writePendingIntentOrNullToParcel}.
     *
     * @param in The Parcel containing the written Messenger.
     * @param in The Parcel containing the written PendingIntent.
     *
     * @return Returns the Messenger read from the Parcel, or null if null had
     * @return Returns the PendingIntent read from the Parcel, or null if null had
     * been written.
     */
    @Nullable
    public static PendingIntent readPendingIntentOrNullFromParcel(@NonNull Parcel in) {
        IBinder b = in.readStrongBinder();
        return b != null ? new PendingIntent(b) : null;
        return b != null ? new PendingIntent(b, in.getClassCookie(PendingIntent.class)) : null;
    }

    /*package*/ PendingIntent(IIntentSender target) {
        mTarget = target;
    }

    /*package*/ PendingIntent(IBinder target) {
    /*package*/ PendingIntent(IBinder target, Object cookie) {
        mTarget = IIntentSender.Stub.asInterface(target);
        if (cookie != null) {
            mWhitelistToken = (IBinder)cookie;
        }
    }

    /** @hide */
    public IIntentSender getTarget() {
        return mTarget;
    }

    /** @hide */
    public IBinder getWhitelistToken() {
        return mWhitelistToken;
    }
}
Loading