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

Commit 40725b15 authored by Matías Hernández's avatar Matías Hernández
Browse files

[conflict] Merge "Fix allowlist token issues" into udc-dev am: ef34c77b

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/29565526



Change-Id: I1346cd69090daa6ffbd6a562c6c4d7dadfc1eeac
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
Merged-In: I232e9b74eece745560ed2e762071b48984b3f176
parents 638d070a ef34c77b
Loading
Loading
Loading
Loading
+38 −9
Original line number Original line Diff line number Diff line
@@ -2598,8 +2598,11 @@ public class Notification implements Parcelable
        if (mAllowlistToken == null) {
        if (mAllowlistToken == null) {
            mAllowlistToken = processAllowlistToken;
            mAllowlistToken = processAllowlistToken;
        }
        }
        // Propagate this token to all pending intents that are unmarshalled from the parcel.
        // Propagate this token to all pending intents that are unmarshalled from the parcel,
        // or keep the one we're already propagating, if that's the case.
        if (!parcel.hasClassCookie(PendingIntent.class)) {
            parcel.setClassCookie(PendingIntent.class, mAllowlistToken);
            parcel.setClassCookie(PendingIntent.class, mAllowlistToken);
        }
        when = parcel.readLong();
        when = parcel.readLong();
        creationTime = parcel.readLong();
        creationTime = parcel.readLong();
@@ -3058,10 +3061,25 @@ public class Notification implements Parcelable
                }
                }
            });
            });
        }
        }
        try {
            boolean mustClearCookie = false;
            if (!parcel.hasClassCookie(Notification.class)) {
                // This is the "root" notification, and not an "inner" notification (including
                // publicVersion or anything else that might be embedded in extras). So we want
                // to use its token for every inner notification (might be null).
                parcel.setClassCookie(Notification.class, mAllowlistToken);
                mustClearCookie = true;
            }
            try {
            try {
                // IMPORTANT: Add marshaling code in writeToParcelImpl as we
                // IMPORTANT: Add marshaling code in writeToParcelImpl as we
                // want to intercept all pending events written to the parcel.
                // want to intercept all pending events written to the parcel.
                writeToParcelImpl(parcel, flags);
                writeToParcelImpl(parcel, flags);
            } finally {
                if (mustClearCookie) {
                    parcel.removeClassCookie(Notification.class, mAllowlistToken);
                }
            }
            synchronized (this) {
            synchronized (this) {
                // Must be written last!
                // Must be written last!
                parcel.writeArraySet(allPendingIntents);
                parcel.writeArraySet(allPendingIntents);
@@ -3076,7 +3094,10 @@ public class Notification implements Parcelable
    private void writeToParcelImpl(Parcel parcel, int flags) {
    private void writeToParcelImpl(Parcel parcel, int flags) {
        parcel.writeInt(1);
        parcel.writeInt(1);
        parcel.writeStrongBinder(mAllowlistToken);
        // Always use the same token as the root notification (might be null).
        IBinder rootNotificationToken = (IBinder) parcel.getClassCookie(Notification.class);
        parcel.writeStrongBinder(rootNotificationToken);
        parcel.writeLong(when);
        parcel.writeLong(when);
        parcel.writeLong(creationTime);
        parcel.writeLong(creationTime);
        if (mSmallIcon == null && icon != 0) {
        if (mSmallIcon == null && icon != 0) {
@@ -3469,13 +3490,21 @@ public class Notification implements Parcelable
     * Sets the token used for background operations for the pending intents associated with this
     * Sets the token used for background operations for the pending intents associated with this
     * notification.
     * notification.
     *
     *
     * This token is automatically set during deserialization for you, you usually won't need to
     * Note: Should <em>only</em> be invoked by NotificationManagerService, since this is normally
     * call this unless you want to change the existing token, if any.
     * populated by unparceling (and also used there). Any other usage is suspect.
     *
     *
     * @hide
     * @hide
     */
     */
    public void setAllowlistToken(@Nullable IBinder token) {
    public void overrideAllowlistToken(IBinder token) {
        mAllowlistToken = token;
        mAllowlistToken = token;
        if (publicVersion != null) {
            publicVersion.overrideAllowlistToken(token);
        }
    }
    /** @hide */
    public IBinder getAllowlistToken() {
        return mAllowlistToken;
    }
    }
    /**
    /**
+22 −0
Original line number Original line Diff line number Diff line
@@ -815,6 +815,28 @@ public final class Parcel {
        return mClassCookies != null ? mClassCookies.get(clz) : null;
        return mClassCookies != null ? mClassCookies.get(clz) : null;
    }
    }


    /** @hide */
    public void removeClassCookie(Class clz, Object expectedCookie) {
        if (mClassCookies != null) {
            Object removedCookie = mClassCookies.remove(clz);
            if (removedCookie != expectedCookie) {
                Log.wtf(TAG, "Expected to remove " + expectedCookie + " (with key=" + clz
                        + ") but instead removed " + removedCookie);
            }
        } else {
            Log.wtf(TAG, "Expected to remove " + expectedCookie + " (with key=" + clz
                    + ") but no cookies were present");
        }
    }

    /**
     * Whether {@link #setClassCookie} has been called with the specified {@code clz}.
     * @hide
     */
    public boolean hasClassCookie(Class clz) {
        return mClassCookies != null && mClassCookies.containsKey(clz);
    }

    /** @hide */
    /** @hide */
    public final void adoptClassCookies(Parcel from) {
    public final void adoptClassCookies(Parcel from) {
        mClassCookies = from.mClassCookies;
        mClassCookies = from.mClassCookies;
+49 −0
Original line number Original line Diff line number Diff line
@@ -16,18 +16,23 @@


package android.os;
package android.os;


import static com.google.common.truth.Truth.assertThat;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertTrue;


import android.platform.test.annotations.Presubmit;
import android.platform.test.annotations.Presubmit;
import android.util.Log;


import androidx.test.runner.AndroidJUnit4;
import androidx.test.runner.AndroidJUnit4;


import org.junit.Test;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runner.RunWith;


import java.util.ArrayList;

@Presubmit
@Presubmit
@RunWith(AndroidJUnit4.class)
@RunWith(AndroidJUnit4.class)
public class ParcelTest {
public class ParcelTest {
@@ -246,4 +251,48 @@ public class ParcelTest {
        assertThrows(IllegalArgumentException.class, () -> Parcel.compareData(pA, -1, pB, iB, 0));
        assertThrows(IllegalArgumentException.class, () -> Parcel.compareData(pA, -1, pB, iB, 0));
        assertThrows(IllegalArgumentException.class, () -> Parcel.compareData(pA, 0, pB, -1, 0));
        assertThrows(IllegalArgumentException.class, () -> Parcel.compareData(pA, 0, pB, -1, 0));
    }
    }

    @Test
    public void testClassCookies() {
        Parcel p = Parcel.obtain();
        assertThat(p.hasClassCookie(ParcelTest.class)).isFalse();

        p.setClassCookie(ParcelTest.class, "string_cookie");
        assertThat(p.hasClassCookie(ParcelTest.class)).isTrue();
        assertThat(p.getClassCookie(ParcelTest.class)).isEqualTo("string_cookie");

        p.removeClassCookie(ParcelTest.class, "string_cookie");
        assertThat(p.hasClassCookie(ParcelTest.class)).isFalse();
        assertThat(p.getClassCookie(ParcelTest.class)).isEqualTo(null);

        p.setClassCookie(ParcelTest.class, "to_be_discarded_cookie");
        p.recycle();
        assertThat(p.getClassCookie(ParcelTest.class)).isNull();
    }

    @Test
    public void testClassCookies_removeUnexpected() {
        Parcel p = Parcel.obtain();

        assertLogsWtf(() -> p.removeClassCookie(ParcelTest.class, "not_present"));

        p.setClassCookie(ParcelTest.class, "value");

        assertLogsWtf(() -> p.removeClassCookie(ParcelTest.class, "different"));
        assertThat(p.getClassCookie(ParcelTest.class)).isNull(); // still removed

        p.recycle();
    }

    private static void assertLogsWtf(Runnable test) {
        ArrayList<Log.TerribleFailure> wtfs = new ArrayList<>();
        Log.TerribleFailureHandler oldHandler = Log.setWtfHandler(
                (tag, what, system) -> wtfs.add(what));
        try {
            test.run();
        } finally {
            Log.setWtfHandler(oldHandler);
        }
        assertThat(wtfs).hasSize(1);
    }
}
}
+16 −2
Original line number Original line Diff line number Diff line
@@ -667,7 +667,7 @@ public class NotificationManagerService extends SystemService {
    private static final int MY_UID = Process.myUid();
    private static final int MY_UID = Process.myUid();
    private static final int MY_PID = Process.myPid();
    private static final int MY_PID = Process.myPid();
    private static final IBinder ALLOWLIST_TOKEN = new Binder();
    static final IBinder ALLOWLIST_TOKEN = new Binder();
    protected RankingHandler mRankingHandler;
    protected RankingHandler mRankingHandler;
    private long mLastOverRateLogTime;
    private long mLastOverRateLogTime;
    private float mMaxPackageEnqueueRate = DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE;
    private float mMaxPackageEnqueueRate = DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE;
@@ -4472,7 +4472,7 @@ public class NotificationManagerService extends SystemService {
                    // Remove background token before returning notification to untrusted app, this
                    // Remove background token before returning notification to untrusted app, this
                    // ensures the app isn't able to perform background operations that are
                    // ensures the app isn't able to perform background operations that are
                    // associated with notification interactions.
                    // associated with notification interactions.
                    notification.setAllowlistToken(null);
                    notification.overrideAllowlistToken(null);
                    return new StatusBarNotification(
                    return new StatusBarNotification(
                            sbn.getPackageName(),
                            sbn.getPackageName(),
                            sbn.getOpPkg(),
                            sbn.getOpPkg(),
@@ -6713,6 +6713,15 @@ public class NotificationManagerService extends SystemService {
                    + " trying to post for invalid pkg " + pkg + " in user " + incomingUserId);
                    + " trying to post for invalid pkg " + pkg + " in user " + incomingUserId);
        }
        }
        IBinder allowlistToken = notification.getAllowlistToken();
        if (allowlistToken != null && allowlistToken != ALLOWLIST_TOKEN) {
            throw new SecurityException(
                    "Unexpected allowlist token received from " + callingUid);
        }
        // allowlistToken is populated by unparceling, so it can be null if the notification was
        // posted from inside system_server. Ensure it's the expected value.
        notification.overrideAllowlistToken(ALLOWLIST_TOKEN);
        checkRestrictedCategories(notification);
        checkRestrictedCategories(notification);
        // Notifications passed to setForegroundService() have FLAG_FOREGROUND_SERVICE,
        // Notifications passed to setForegroundService() have FLAG_FOREGROUND_SERVICE,
@@ -7776,6 +7785,11 @@ public class NotificationManagerService extends SystemService {
         */
         */
        private boolean enqueueNotification() {
        private boolean enqueueNotification() {
            synchronized (mNotificationLock) {
            synchronized (mNotificationLock) {
                // allowlistToken is populated by unparceling, so it will be absent if the
                // EnqueueNotificationRunnable is created directly by NMS (as we do for group
                // summaries) instead of via notify(). Fix that.
                r.getNotification().overrideAllowlistToken(ALLOWLIST_TOKEN);
                final long snoozeAt =
                final long snoozeAt =
                        mSnoozeHelper.getSnoozeTimeForUnpostedNotification(
                        mSnoozeHelper.getSnoozeTimeForUnpostedNotification(
                                r.getUser().getIdentifier(),
                                r.getUser().getIdentifier(),
+346 −3

File changed.

Preview size limit exceeded, changes collapsed.