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
This commit is contained in:
Iván Budnik
2023-06-21 16:34:37 +00:00
parent 4feda1865b
commit fda5a94aaf
2 changed files with 42 additions and 11 deletions

View File

@@ -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.
*
* <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.
* @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();
}
}

View File

@@ -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);