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

Commit 6f192031 authored by Matías Hernández's avatar Matías Hernández Committed by Android (Google) Code Review
Browse files

Merge "Fix collection of Notification allPendingIntents" into udc-qpr-dev

parents 937c9230 761c4439
Loading
Loading
Loading
Loading
+7 −7
Original line number Diff line number Diff line
@@ -3047,10 +3047,9 @@ public class Notification implements Parcelable
        // cannot look into the extras as there may be parcelables there that
        // the platform does not know how to handle. To go around that we have
        // an explicit list of the pending intents in the extras bundle.
        final boolean collectPendingIntents = (allPendingIntents == null);
        if (collectPendingIntents) {
            PendingIntent.setOnMarshaledListener(
                    (PendingIntent intent, Parcel out, int outFlags) -> {
        PendingIntent.OnMarshaledListener addedListener = null;
        if (allPendingIntents == null) {
            addedListener = (PendingIntent intent, Parcel out, int outFlags) -> {
                if (parcel == out) {
                    synchronized (this) {
                        if (allPendingIntents == null) {
@@ -3059,7 +3058,8 @@ public class Notification implements Parcelable
                        allPendingIntents.add(intent);
                    }
                }
            });
            };
            PendingIntent.addOnMarshaledListener(addedListener);
        }
        try {
            // IMPORTANT: Add marshaling code in writeToParcelImpl as we
@@ -3070,8 +3070,8 @@ public class Notification implements Parcelable
                parcel.writeArraySet(allPendingIntents);
            }
        } finally {
            if (collectPendingIntents) {
                PendingIntent.setOnMarshaledListener(null);
            if (addedListener != null) {
                PendingIntent.removeOnMarshaledListener(addedListener);
            }
        }
    }
+34 −11
Original line number Diff line number Diff line
@@ -64,6 +64,7 @@ import com.android.internal.os.IResultReceiver;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
@@ -391,11 +392,12 @@ public final class PendingIntent implements Parcelable {
        void onMarshaled(PendingIntent intent, Parcel parcel, int flags);
    }

    private static final ThreadLocal<OnMarshaledListener> sOnMarshaledListener
            = new ThreadLocal<>();
    private static final ThreadLocal<List<OnMarshaledListener>> sOnMarshaledListener =
            ThreadLocal.withInitial(ArrayList::new);

    /**
     * Registers an listener for pending intents being written to a parcel.
     * Registers an listener for pending intents being written to a parcel. This replaces any
     * listeners previously added.
     *
     * @param listener The listener, null to clear.
     *
@@ -403,7 +405,27 @@ public final class PendingIntent implements Parcelable {
     */
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    public static void setOnMarshaledListener(OnMarshaledListener listener) {
        sOnMarshaledListener.set(listener);
        final List<OnMarshaledListener> listeners = sOnMarshaledListener.get();
        listeners.clear();
        if (listener != null) {
            listeners.add(listener);
        }
    }

    /**
     * Adds a listener for pending intents being written to a parcel.
     * @hide
     */
    static void addOnMarshaledListener(OnMarshaledListener listener) {
        sOnMarshaledListener.get().add(listener);
    }

    /**
     * Removes a listener for pending intents being written to a parcel.
     * @hide
     */
    static void removeOnMarshaledListener(OnMarshaledListener listener) {
        sOnMarshaledListener.get().remove(listener);
    }

    private static void checkPendingIntent(int flags, @NonNull Intent intent,
@@ -1451,11 +1473,11 @@ public final class PendingIntent implements Parcelable {

    public void writeToParcel(Parcel out, int flags) {
        out.writeStrongBinder(mTarget.asBinder());
        OnMarshaledListener listener = sOnMarshaledListener.get();
        if (listener != null) {
            listener.onMarshaled(this, out, flags);
        final List<OnMarshaledListener> listeners = sOnMarshaledListener.get();
        final int numListeners = listeners.size();
        for (int i = 0; i < numListeners; i++) {
            listeners.get(i).onMarshaled(this, out, flags);
        }

    }

    public static final @NonNull Creator<PendingIntent> CREATOR = new Creator<PendingIntent>() {
@@ -1483,9 +1505,10 @@ public final class PendingIntent implements Parcelable {
            @NonNull Parcel out) {
        out.writeStrongBinder(sender != null ? sender.mTarget.asBinder() : null);
        if (sender != null) {
            OnMarshaledListener listener = sOnMarshaledListener.get();
            if (listener != null) {
                listener.onMarshaled(sender, out, 0 /* flags */);
            final List<OnMarshaledListener> listeners = sOnMarshaledListener.get();
            final int numListeners = listeners.size();
            for (int i = 0; i < numListeners; i++) {
                listeners.get(i).onMarshaled(sender, out, 0 /* flags */);
            }
        }
    }
+48 −0
Original line number Diff line number Diff line
@@ -270,6 +270,54 @@ public class NotificationTest {
        assertTrue(n.allPendingIntents.contains(intent));
    }

    @Test
    public void allPendingIntents_resilientToAnotherNotificationInExtras() {
        PendingIntent contentIntent = createPendingIntent("content");
        PendingIntent actionIntent = createPendingIntent("action");
        Notification another = new Notification.Builder(mContext, "channel").build();
        Bundle bundleContainingAnotherNotification = new Bundle();
        bundleContainingAnotherNotification.putParcelable(null, another);
        Notification source = new Notification.Builder(mContext, "channel")
                .setContentIntent(contentIntent)
                .addAction(new Notification.Action.Builder(null, "action", actionIntent).build())
                .setExtras(bundleContainingAnotherNotification)
                .build();

        Parcel p = Parcel.obtain();
        source.writeToParcel(p, 0);
        p.setDataPosition(0);
        Notification unparceled = new Notification(p);

        assertThat(unparceled.allPendingIntents).containsExactly(contentIntent, actionIntent);
    }

    @Test
    public void allPendingIntents_alsoInPublicVersion() {
        PendingIntent contentIntent = createPendingIntent("content");
        PendingIntent actionIntent = createPendingIntent("action");
        PendingIntent publicContentIntent = createPendingIntent("publicContent");
        PendingIntent publicActionIntent = createPendingIntent("publicAction");
        Notification source = new Notification.Builder(mContext, "channel")
                .setContentIntent(contentIntent)
                .addAction(new Notification.Action.Builder(null, "action", actionIntent).build())
                .setPublicVersion(new Notification.Builder(mContext, "channel")
                        .setContentIntent(publicContentIntent)
                        .addAction(new Notification.Action.Builder(
                                null, "publicAction", publicActionIntent).build())
                        .build())
                .build();

        Parcel p = Parcel.obtain();
        source.writeToParcel(p, 0);
        p.setDataPosition(0);
        Notification unparceled = new Notification(p);

        assertThat(unparceled.allPendingIntents).containsExactly(contentIntent, actionIntent,
                publicContentIntent, publicActionIntent);
        assertThat(unparceled.publicVersion.allPendingIntents).containsExactly(publicContentIntent,
                publicActionIntent);
    }

    @Test
    public void messagingStyle_isGroupConversation() {
        mContext.getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.P;
+71 −0
Original line number Diff line number Diff line
@@ -62,6 +62,8 @@ import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.Build.VERSION_CODES.O_MR1;
import static android.os.Build.VERSION_CODES.P;
import static android.os.PowerManager.PARTIAL_WAKE_LOCK;
import static android.os.PowerWhitelistManager.REASON_NOTIFICATION_SERVICE;
import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
import static android.os.UserHandle.USER_SYSTEM;
import static android.os.UserManager.USER_TYPE_FULL_SECONDARY;
import static android.os.UserManager.USER_TYPE_PROFILE_CLONE;
@@ -83,6 +85,9 @@ import static com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.No
import static com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags.SHOW_STICKY_HUN_FOR_DENIED_FSI;
import static com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags.WAKE_LOCK_FOR_POSTING_NOTIFICATION;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
import static com.android.server.am.PendingIntentRecord.FLAG_ACTIVITY_SENDER;
import static com.android.server.am.PendingIntentRecord.FLAG_BROADCAST_SENDER;
import static com.android.server.am.PendingIntentRecord.FLAG_SERVICE_SENDER;
import static com.android.server.notification.NotificationManagerService.DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE;
import static com.android.server.notification.NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_ADJUSTED;
import static com.android.server.notification.NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_POSTED;
@@ -186,6 +191,7 @@ import android.os.Bundle;
import android.os.IBinder;
import android.os.Looper;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.os.Process;
@@ -716,6 +722,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
    @After
    public void assertAllWakeLocksReleased() {
        waitForIdle(); // Finish async work.
        for (WakeLock wakeLock : mAcquiredWakeLocks) {
            assertThat(wakeLock.isHeld()).isFalse();
        }
@@ -12117,6 +12124,70 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        assertThat(mService.mNotificationList.get(0).getNotification().when).isEqualTo(111); // old
    }
    @Test
    public void enqueueNotification_allowlistsPendingIntents() throws RemoteException {
        PendingIntent contentIntent = createPendingIntent("content");
        PendingIntent actionIntent1 = createPendingIntent("action1");
        PendingIntent actionIntent2 = createPendingIntent("action2");
        Notification n = new Notification.Builder(mContext, TEST_CHANNEL_ID)
                .setContentIntent(contentIntent)
                .addAction(new Notification.Action.Builder(null, "action1", actionIntent1).build())
                .addAction(new Notification.Action.Builder(null, "action2", actionIntent2).build())
                .build();
        mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", 1,
                parcelAndUnparcel(n, Notification.CREATOR), mUserId);
        verify(mAmi, times(3)).setPendingIntentAllowlistDuration(
                any(), any(), anyLong(),
                eq(TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED),
                eq(REASON_NOTIFICATION_SERVICE), any());
        verify(mAmi, times(3)).setPendingIntentAllowBgActivityStarts(any(),
                any(), eq(FLAG_ACTIVITY_SENDER | FLAG_BROADCAST_SENDER | FLAG_SERVICE_SENDER));
    }
    @Test
    public void enqueueNotification_allowlistsPendingIntents_includingFromPublicVersion()
            throws RemoteException {
        PendingIntent contentIntent = createPendingIntent("content");
        PendingIntent actionIntent = createPendingIntent("action");
        PendingIntent publicContentIntent = createPendingIntent("publicContent");
        PendingIntent publicActionIntent = createPendingIntent("publicAction");
        Notification source = new Notification.Builder(mContext, TEST_CHANNEL_ID)
                .setContentIntent(contentIntent)
                .addAction(new Notification.Action.Builder(null, "action", actionIntent).build())
                .setPublicVersion(new Notification.Builder(mContext, "channel")
                        .setContentIntent(publicContentIntent)
                        .addAction(new Notification.Action.Builder(
                                null, "publicAction", publicActionIntent).build())
                        .build())
                .build();
        mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", 1,
                parcelAndUnparcel(source, Notification.CREATOR), mUserId);
        verify(mAmi, times(4)).setPendingIntentAllowlistDuration(
                any(), any(), anyLong(),
                eq(TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED),
                eq(REASON_NOTIFICATION_SERVICE), any());
        verify(mAmi, times(4)).setPendingIntentAllowBgActivityStarts(any(),
                any(), eq(FLAG_ACTIVITY_SENDER | FLAG_BROADCAST_SENDER | FLAG_SERVICE_SENDER));
    }
    private static <T extends Parcelable> T parcelAndUnparcel(T source,
            Parcelable.Creator<T> creator) {
        Parcel parcel = Parcel.obtain();
        source.writeToParcel(parcel, 0);
        parcel.setDataPosition(0);
        return creator.createFromParcel(parcel);
    }
    private PendingIntent createPendingIntent(String action) {
        return PendingIntent.getActivity(mContext, 0,
                new Intent(action).setPackage(mContext.getPackageName()),
                PendingIntent.FLAG_MUTABLE);
    }
    private void setDpmAppOppsExemptFromDismissal(boolean isOn) {
        DeviceConfig.setProperty(
                DeviceConfig.NAMESPACE_DEVICE_POLICY_MANAGER,