Verify URI permissions in MediaMetadata
Add a check for URI permission to make sure that user can access the URI set in MediaMetadata. If permission is denied, clear the URI string set in metadata. Bug: 271851153 Test: atest MediaSessionTest Test: Verified by POC app attached in bug, image of second user is not the UMO background of the first user. Change-Id: I384f8e230c909d8fc8e5f147e2fd3558fec44626 Merged-In: I384f8e230c909d8fc8e5f147e2fd3558fec44626
This commit is contained in:
@@ -19,6 +19,8 @@ package com.android.server.media;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.ComponentName;
|
||||
import android.content.ContentProvider;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ParceledListSlice;
|
||||
@@ -57,6 +59,9 @@ import android.util.EventLog;
|
||||
import android.util.Log;
|
||||
import android.view.KeyEvent;
|
||||
|
||||
import com.android.server.LocalServices;
|
||||
import com.android.server.uri.UriGrantsManagerInternal;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@@ -71,6 +76,10 @@ import java.util.concurrent.CopyOnWriteArrayList;
|
||||
// TODO(jaewan): Do not call service method directly -- introduce listener instead.
|
||||
public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionRecordImpl {
|
||||
private static final String TAG = "MediaSessionRecord";
|
||||
private static final String[] ART_URIS = new String[] {
|
||||
MediaMetadata.METADATA_KEY_ALBUM_ART_URI,
|
||||
MediaMetadata.METADATA_KEY_ART_URI,
|
||||
MediaMetadata.METADATA_KEY_DISPLAY_ICON_URI};
|
||||
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
|
||||
|
||||
/**
|
||||
@@ -124,6 +133,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
|
||||
private final SessionStub mSession;
|
||||
private final SessionCb mSessionCb;
|
||||
private final MediaSessionService mService;
|
||||
private final UriGrantsManagerInternal mUgmInternal;
|
||||
private final Context mContext;
|
||||
private final boolean mVolumeAdjustmentForRemoteGroupSessions;
|
||||
|
||||
@@ -185,6 +195,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
|
||||
mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
|
||||
mAudioAttrs = DEFAULT_ATTRIBUTES;
|
||||
mPolicies = policies;
|
||||
mUgmInternal = LocalServices.getService(UriGrantsManagerInternal.class);
|
||||
mVolumeAdjustmentForRemoteGroupSessions = mContext.getResources().getBoolean(
|
||||
com.android.internal.R.bool.config_volumeAdjustmentForRemoteGroupSessions);
|
||||
|
||||
@@ -980,21 +991,45 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
|
||||
public void setMetadata(MediaMetadata metadata, long duration, String metadataDescription)
|
||||
throws RemoteException {
|
||||
synchronized (mLock) {
|
||||
MediaMetadata temp = metadata == null ? null : new MediaMetadata.Builder(metadata)
|
||||
.build();
|
||||
// This is to guarantee that the underlying bundle is unparceled
|
||||
// before we set it to prevent concurrent reads from throwing an
|
||||
// exception
|
||||
if (temp != null) {
|
||||
temp.size();
|
||||
}
|
||||
mMetadata = temp;
|
||||
mDuration = duration;
|
||||
mMetadataDescription = metadataDescription;
|
||||
mMetadata = sanitizeMediaMetadata(metadata);
|
||||
}
|
||||
mHandler.post(MessageHandler.MSG_UPDATE_METADATA);
|
||||
}
|
||||
|
||||
private MediaMetadata sanitizeMediaMetadata(MediaMetadata metadata) {
|
||||
if (metadata == null) {
|
||||
return null;
|
||||
}
|
||||
MediaMetadata.Builder metadataBuilder = new MediaMetadata.Builder(metadata);
|
||||
for (String key: ART_URIS) {
|
||||
String uriString = metadata.getString(key);
|
||||
if (TextUtils.isEmpty(uriString)) {
|
||||
continue;
|
||||
}
|
||||
Uri uri = Uri.parse(uriString);
|
||||
if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
mUgmInternal.checkGrantUriPermission(getUid(),
|
||||
getPackageName(),
|
||||
ContentProvider.getUriWithoutUserId(uri),
|
||||
Intent.FLAG_GRANT_READ_URI_PERMISSION,
|
||||
ContentProvider.getUserIdFromUri(uri, getUserId()));
|
||||
} catch (SecurityException e) {
|
||||
metadataBuilder.putString(key, null);
|
||||
}
|
||||
}
|
||||
MediaMetadata sanitizedMetadata = metadataBuilder.build();
|
||||
// sanitizedMetadata.size() guarantees that the underlying bundle is unparceled
|
||||
// before we set it to prevent concurrent reads from throwing an
|
||||
// exception
|
||||
sanitizedMetadata.size();
|
||||
return sanitizedMetadata;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPlaybackState(PlaybackState state) throws RemoteException {
|
||||
int oldState = mPlaybackState == null
|
||||
|
||||
Reference in New Issue
Block a user