Merge "Do not allow adding custom Parcelable in Bundles" into qt-dev

This commit is contained in:
Hyundo Moon
2019-06-24 04:26:17 +00:00
committed by Android (Google) Code Review
7 changed files with 144 additions and 17 deletions

View File

@@ -75,5 +75,4 @@ public class Media2Utils {
Log.v(TAG, "storeCookies: cookieHandler: " + cookieHandler + " Cookies: " + cookies);
}
}

View File

@@ -100,7 +100,7 @@ public class MediaController2 implements AutoCloseable {
* @param callback controller callback to receive changes in.
*/
MediaController2(@NonNull Context context, @NonNull Session2Token token,
@Nullable Bundle connectionHints, @NonNull Executor executor,
@NonNull Bundle connectionHints, @NonNull Executor executor,
@NonNull ControllerCallback callback) {
if (context == null) {
throw new IllegalArgumentException("context shouldn't be null");
@@ -259,7 +259,16 @@ public class MediaController2 implements AutoCloseable {
Session2CommandGroup allowedCommands =
connectionResult.getParcelable(KEY_ALLOWED_COMMANDS);
boolean playbackActive = connectionResult.getBoolean(KEY_PLAYBACK_ACTIVE);
Bundle tokenExtras = connectionResult.getBundle(KEY_TOKEN_EXTRAS);
if (tokenExtras == null) {
Log.w(TAG, "extras shouldn't be null.");
tokenExtras = Bundle.EMPTY;
} else if (MediaSession2.hasCustomParcelable(tokenExtras)) {
Log.w(TAG, "extras contain custom parcelable. Ignoring.");
tokenExtras = Bundle.EMPTY;
}
if (DEBUG) {
Log.d(TAG, "notifyConnected sessionBinder=" + sessionBinder
+ ", allowedCommands=" + allowedCommands);
@@ -343,7 +352,7 @@ public class MediaController2 implements AutoCloseable {
}
}
private Bundle createConnectionRequest(@Nullable Bundle connectionHints) {
private Bundle createConnectionRequest(@NonNull Bundle connectionHints) {
Bundle connectionRequest = new Bundle();
connectionRequest.putString(KEY_PACKAGE_NAME, mContext.getPackageName());
connectionRequest.putInt(KEY_PID, Process.myPid());
@@ -351,7 +360,7 @@ public class MediaController2 implements AutoCloseable {
return connectionRequest;
}
private boolean requestConnectToSession(@Nullable Bundle connectionHints) {
private boolean requestConnectToSession(@NonNull Bundle connectionHints) {
Session2Link sessionBinder = mSessionToken.getSessionLink();
Bundle connectionRequest = createConnectionRequest(connectionHints);
try {
@@ -430,6 +439,9 @@ public class MediaController2 implements AutoCloseable {
* <p>
* {@code connectionHints} is a session-specific argument to send to the session when
* connecting. The contents of this bundle may affect the connection result.
* <p>
* An {@link IllegalArgumentException} will be thrown if the bundle contains any
* non-framework Parcelable objects.
*
* @param connectionHints a bundle which contains the connection hints
* @return The Builder to allow chaining
@@ -439,6 +451,10 @@ public class MediaController2 implements AutoCloseable {
if (connectionHints == null) {
throw new IllegalArgumentException("connectionHints shouldn't be null");
}
if (MediaSession2.hasCustomParcelable(connectionHints)) {
throw new IllegalArgumentException("connectionHints shouldn't contain any custom "
+ "parcelables");
}
mConnectionHints = new Bundle(connectionHints);
return this;
}
@@ -477,6 +493,9 @@ public class MediaController2 implements AutoCloseable {
if (mCallback == null) {
mCallback = new ControllerCallback() {};
}
if (mConnectionHints == null) {
mConnectionHints = Bundle.EMPTY;
}
return new MediaController2(
mContext, mToken, mConnectionHints, mCallbackExecutor, mCallback);
}

View File

@@ -34,8 +34,10 @@ import android.content.Context;
import android.content.Intent;
import android.media.session.MediaSessionManager;
import android.media.session.MediaSessionManager.RemoteUserInfo;
import android.os.BadParcelableException;
import android.os.Bundle;
import android.os.Handler;
import android.os.Parcel;
import android.os.Process;
import android.os.ResultReceiver;
import android.util.ArrayMap;
@@ -97,7 +99,7 @@ public class MediaSession2 implements AutoCloseable {
MediaSession2(@NonNull Context context, @NonNull String id, PendingIntent sessionActivity,
@NonNull Executor callbackExecutor, @NonNull SessionCallback callback,
Bundle tokenExtras) {
@NonNull Bundle tokenExtras) {
synchronized (MediaSession2.class) {
if (SESSION_ID_LIST.contains(id)) {
throw new IllegalStateException("Session ID must be unique. ID=" + id);
@@ -276,6 +278,35 @@ public class MediaSession2 implements AutoCloseable {
return controllers;
}
/**
* Returns whether the given bundle includes non-framework Parcelables.
*/
static boolean hasCustomParcelable(@Nullable Bundle bundle) {
if (bundle == null) {
return false;
}
// Try writing the bundle to parcel, and read it with framework classloader.
Parcel parcel = null;
try {
parcel = Parcel.obtain();
parcel.writeBundle(bundle);
parcel.setDataPosition(0);
Bundle out = parcel.readBundle(null);
// Calling Bundle#size() will trigger Bundle#unparcel().
out.size();
} catch (BadParcelableException e) {
Log.d(TAG, "Custom parcelable in bundle.", e);
return true;
} finally {
if (parcel != null) {
parcel.recycle();
}
}
return false;
}
boolean isClosed() {
synchronized (mLock) {
return mClosed;
@@ -309,11 +340,21 @@ public class MediaSession2 implements AutoCloseable {
String callingPkg = connectionRequest.getString(KEY_PACKAGE_NAME);
RemoteUserInfo remoteUserInfo = new RemoteUserInfo(callingPkg, callingPid, callingUid);
Bundle connectionHints = connectionRequest.getBundle(KEY_CONNECTION_HINTS);
if (connectionHints == null) {
Log.w(TAG, "connectionHints shouldn't be null.");
connectionHints = Bundle.EMPTY;
} else if (hasCustomParcelable(connectionHints)) {
Log.w(TAG, "connectionHints contain custom parcelable. Ignoring.");
connectionHints = Bundle.EMPTY;
}
final ControllerInfo controllerInfo = new ControllerInfo(
remoteUserInfo,
mSessionManager.isTrustedForMediaControl(remoteUserInfo),
controller,
connectionRequest.getBundle(KEY_CONNECTION_HINTS));
connectionHints);
mCallbackExecutor.execute(() -> {
boolean connected = false;
try {
@@ -516,7 +557,8 @@ public class MediaSession2 implements AutoCloseable {
/**
* Set extras for the session token. If null or not set, {@link Session2Token#getExtras()}
* will return {@link Bundle#EMPTY}.
* will return an empty {@link Bundle}. An {@link IllegalArgumentException} will be thrown
* if the bundle contains any non-framework Parcelable objects.
*
* @return The Builder to allow chaining
* @see Session2Token#getExtras()
@@ -526,7 +568,11 @@ public class MediaSession2 implements AutoCloseable {
if (extras == null) {
throw new NullPointerException("extras shouldn't be null");
}
mExtras = extras;
if (hasCustomParcelable(extras)) {
throw new IllegalArgumentException(
"extras shouldn't contain any custom parcelables");
}
mExtras = new Bundle(extras);
return this;
}
@@ -548,6 +594,9 @@ public class MediaSession2 implements AutoCloseable {
if (mId == null) {
mId = "";
}
if (mExtras == null) {
mExtras = Bundle.EMPTY;
}
MediaSession2 session2 = new MediaSession2(mContext, mId, mSessionActivity,
mCallbackExecutor, mCallback, mExtras);
@@ -596,7 +645,7 @@ public class MediaSession2 implements AutoCloseable {
* connection result.
*/
ControllerInfo(@NonNull RemoteUserInfo remoteUserInfo, boolean trusted,
@Nullable Controller2Link controllerBinder, @Nullable Bundle connectionHints) {
@Nullable Controller2Link controllerBinder, @NonNull Bundle connectionHints) {
mRemoteUserInfo = remoteUserInfo;
mIsTrusted = trusted;
mControllerBinder = controllerBinder;
@@ -629,11 +678,11 @@ public class MediaSession2 implements AutoCloseable {
}
/**
* @return connection hints sent from controller, or {@link Bundle#EMPTY} if none.
* @return connection hints sent from controller.
*/
@NonNull
public Bundle getConnectionHints() {
return mConnectionHints == null ? Bundle.EMPTY : new Bundle(mConnectionHints);
return new Bundle(mConnectionHints);
}
/**

View File

@@ -378,12 +378,22 @@ public abstract class MediaSession2Service extends Service {
callingPkg,
pid == 0 ? connectionRequest.getInt(KEY_PID) : pid,
uid);
Bundle connectionHints = connectionRequest.getBundle(KEY_CONNECTION_HINTS);
if (connectionHints == null) {
Log.w(TAG, "connectionHints shouldn't be null.");
connectionHints = Bundle.EMPTY;
} else if (MediaSession2.hasCustomParcelable(connectionHints)) {
Log.w(TAG, "connectionHints contain custom parcelable. Ignoring.");
connectionHints = Bundle.EMPTY;
}
final ControllerInfo controllerInfo = new ControllerInfo(
remoteUserInfo,
service.getMediaSessionManager()
.isTrustedForMediaControl(remoteUserInfo),
caller,
connectionRequest.getBundle(KEY_CONNECTION_HINTS));
connectionHints);
if (DEBUG) {
Log.d(TAG, "Handling incoming connection request from the"

View File

@@ -118,11 +118,11 @@ public final class Session2Token implements Parcelable {
mUid = uid;
mType = TYPE_SESSION_SERVICE;
mSessionLink = null;
mExtras = null;
mExtras = Bundle.EMPTY;
}
Session2Token(int uid, int type, String packageName, Session2Link sessionLink,
Bundle tokenExtras) {
@NonNull Bundle tokenExtras) {
mUid = uid;
mType = type;
mPackageName = packageName;
@@ -139,7 +139,16 @@ public final class Session2Token implements Parcelable {
mServiceName = in.readString();
mSessionLink = in.readParcelable(null);
mComponentName = ComponentName.unflattenFromString(in.readString());
mExtras = in.readBundle();
Bundle extras = in.readBundle();
if (extras == null) {
Log.w(TAG, "extras shouldn't be null.");
extras = Bundle.EMPTY;
} else if (MediaSession2.hasCustomParcelable(extras)) {
Log.w(TAG, "extras contain custom parcelable. Ignoring.");
extras = Bundle.EMPTY;
}
mExtras = extras;
}
@Override
@@ -220,7 +229,7 @@ public final class Session2Token implements Parcelable {
*/
@NonNull
public Bundle getExtras() {
return mExtras == null ? Bundle.EMPTY : mExtras;
return new Bundle(mExtras);
}
Session2Link getSessionLink() {

View File

@@ -414,7 +414,7 @@ public final class MediaController {
/**
* Gets the additional session information which was set when the session was created.
*
* @return The additional session information, or {@link Bundle#EMPTY} if not set.
* @return The additional session information, or an empty {@link Bundle} if not set.
*/
@NonNull
public Bundle getSessionInfo() {
@@ -430,6 +430,10 @@ public final class MediaController {
}
if (mSessionInfo == null) {
Log.w(TAG, "sessionInfo shouldn't be null.");
mSessionInfo = Bundle.EMPTY;
} else if (MediaSession.hasCustomParcelable(mSessionInfo)) {
Log.w(TAG, "sessionInfo contains custom parcelable. Ignoring.");
mSessionInfo = Bundle.EMPTY;
}
return new Bundle(mSessionInfo);

View File

@@ -32,6 +32,7 @@ import android.media.Rating;
import android.media.VolumeProvider;
import android.media.session.MediaSessionManager.RemoteUserInfo;
import android.net.Uri;
import android.os.BadParcelableException;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
@@ -168,6 +169,8 @@ public final class MediaSession {
* @param sessionInfo A bundle for additional information about this session.
* Controllers can get this information by calling
* {@link MediaController#getSessionInfo()}.
* An {@link IllegalArgumentException} will be thrown if this contains
* any non-framework Parcelable objects.
*/
public MediaSession(@NonNull Context context, @NonNull String tag,
@Nullable Bundle sessionInfo) {
@@ -177,6 +180,11 @@ public final class MediaSession {
if (TextUtils.isEmpty(tag)) {
throw new IllegalArgumentException("tag cannot be null or empty");
}
if (hasCustomParcelable(sessionInfo)) {
throw new IllegalArgumentException("sessionInfo shouldn't contain any custom "
+ "parcelables");
}
mMaxBitmapSize = context.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.config_mediaMetadataBitmapMaxSize);
mCbStub = new CallbackStub(this);
@@ -600,6 +608,35 @@ public final class MediaSession {
return false;
}
/**
* Returns whether the given bundle includes non-framework Parcelables.
*/
static boolean hasCustomParcelable(@Nullable Bundle bundle) {
if (bundle == null) {
return false;
}
// Try writing the bundle to parcel, and read it with framework classloader.
Parcel parcel = null;
try {
parcel = Parcel.obtain();
parcel.writeBundle(bundle);
parcel.setDataPosition(0);
Bundle out = parcel.readBundle(null);
// Calling Bundle#size() will trigger Bundle#unparcel().
out.size();
} catch (BadParcelableException e) {
Log.d(TAG, "Custom parcelable in bundle.", e);
return true;
} finally {
if (parcel != null) {
parcel.recycle();
}
}
return false;
}
void dispatchPrepare(RemoteUserInfo caller) {
postToCallback(caller, CallbackMessageHandler.MSG_PREPARE, null, null);
}