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

Commit fda5a94a authored by Iván Budnik's avatar Iván Budnik
Browse files

Prevent media button receivers targeting activities

This enforcement prevents a bypass of background activity launches.

Bug: 272737196
Test: atest MediaSessionHostTest MediaSessionTest
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:edf219ab08fdf5390aac6dd18fcdab76daa3488a)
Change-Id: I07c2521f3d97f94e245a25bbb6f49f75cf54a808
parent 4feda186
Loading
Loading
Loading
Loading
+18 −10
Original line number Diff line number Diff line
@@ -267,25 +267,33 @@ public final class MediaSession {
    }

    /**
     * Set a pending intent for your media button receiver to allow restarting
     * playback after the session has been stopped. If your app is started in
     * this way an {@link Intent#ACTION_MEDIA_BUTTON} intent will be sent via
     * the pending intent.
     * <p>
     * The pending intent is recommended to be explicit to follow the security recommendation of
     * {@link PendingIntent#getActivity}.
     * Set a pending intent for your media button receiver to allow restarting playback after the
     * session has been stopped.
     *
     * @param mbr The {@link PendingIntent} to send the media button event to.
     * @see PendingIntent#getActivity
     * <p>If your app is started in this way an {@link Intent#ACTION_MEDIA_BUTTON} intent will be
     * sent via the pending intent.
     *
     * <p>The provided {@link PendingIntent} must not target an activity. On apps targeting Android
     * V and above, passing an activity pending intent to this method causes an {@link
     * IllegalArgumentException}. On apps targeting Android U and below, passing an activity pending
     * intent causes the call to be ignored. Refer to this <a
     * href="https://developer.android.com/guide/components/activities/background-starts">guide</a>
     * for more information.
     *
     * <p>The pending intent is recommended to be explicit to follow the security recommendation of
     * {@link PendingIntent#getService}.
     *
     * @param mbr The {@link PendingIntent} to send the media button event to.
     * @deprecated Use {@link #setMediaButtonBroadcastReceiver(ComponentName)} instead.
     * @throws IllegalArgumentException if the pending intent targets an activity on apps targeting
     * Android V and above.
     */
    @Deprecated
    public void setMediaButtonReceiver(@Nullable PendingIntent mbr) {
        try {
            mBinder.setMediaButtonReceiver(mbr);
        } catch (RemoteException e) {
            Log.wtf(TAG, "Failure in setMediaButtonReceiver.", e);
            e.rethrowFromSystemServer();
        }
    }

+24 −1
Original line number Diff line number Diff line
@@ -106,6 +106,16 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
    @EnabledSince(targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
    static final long THROW_FOR_INVALID_BROADCAST_RECEIVER = 270049379L;

    /**
     * {@link MediaSession#setMediaButtonReceiver(PendingIntent)} throws an {@link
     * IllegalArgumentException} if the provided {@link PendingIntent} targets an {@link
     * android.app.Activity activity} for apps targeting Android V and above. For apps targeting
     * Android U and below, the request will be ignored.
     */
    @ChangeId
    @EnabledSince(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM)
    static final long THROW_FOR_ACTIVITY_MEDIA_BUTTON_RECEIVER = 272737196L;

    private static final String TAG = "MediaSessionRecord";
    private static final String[] ART_URIS = new String[] {
            MediaMetadata.METADATA_KEY_ALBUM_ART_URI,
@@ -1055,13 +1065,26 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
        }

        @Override
        public void setMediaButtonReceiver(PendingIntent pi) throws RemoteException {
        public void setMediaButtonReceiver(@Nullable PendingIntent pi) throws RemoteException {
            final int uid = Binder.getCallingUid();
            final long token = Binder.clearCallingIdentity();
            try {
                if ((mPolicies & MediaSessionPolicyProvider.SESSION_POLICY_IGNORE_BUTTON_RECEIVER)
                        != 0) {
                    return;
                }

                if (pi != null && pi.isActivity()) {
                    if (CompatChanges.isChangeEnabled(
                            THROW_FOR_ACTIVITY_MEDIA_BUTTON_RECEIVER, uid)) {
                        throw new IllegalArgumentException(
                                "The media button receiver cannot be set to an activity.");
                    } else {
                        Log.w(TAG, "Ignoring invalid media button receiver targeting an activity.");
                        return;
                    }
                }

                mMediaButtonReceiverHolder =
                        MediaButtonReceiverHolder.create(mUserId, pi, mPackageName);
                mService.onMediaButtonReceiverChanged(MediaSessionRecord.this);