diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java index af33149867bda..f664fdc949de0 100644 --- a/media/java/android/media/session/MediaSession.java +++ b/media/java/android/media/session/MediaSession.java @@ -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. - *

- * 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. + * + *

If your app is started in this way an {@link Intent#ACTION_MEDIA_BUTTON} intent will be + * sent via the pending intent. + * + *

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 guide + * for more information. + * + *

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. - * @see PendingIntent#getActivity - * * @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(); } } diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java index 9185a00da5702..95ca08cc7fe9b 100644 --- a/services/core/java/com/android/server/media/MediaSessionRecord.java +++ b/services/core/java/com/android/server/media/MediaSessionRecord.java @@ -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);