diff --git a/core/java/android/view/inputmethod/InputContentInfo.java b/core/java/android/view/inputmethod/InputContentInfo.java index b39705e0b1fa6..001f6534c7619 100644 --- a/core/java/android/view/inputmethod/InputContentInfo.java +++ b/core/java/android/view/inputmethod/InputContentInfo.java @@ -18,11 +18,14 @@ package android.view.inputmethod; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.UserIdInt; import android.content.ClipDescription; +import android.content.ContentProvider; import android.net.Uri; import android.os.Parcel; import android.os.Parcelable; import android.os.RemoteException; +import android.os.UserHandle; import com.android.internal.inputmethod.IInputContentUriToken; @@ -33,8 +36,21 @@ import java.security.InvalidParameterException; */ public final class InputContentInfo implements Parcelable { + /** + * The content URI that never has a user ID embedded by + * {@link ContentProvider#maybeAddUserId(Uri, int)}. + */ @NonNull private final Uri mContentUri; + /** + * The user ID to which {@link #mContentUri} belongs to. This is always determined based on + * the process ID when the constructor is called. + * + *
CAUTION: If you received {@link InputContentInfo} from a different process, there is no + * guarantee that this value is correct and valid. Never use this for any security purpose
+ */ + @UserIdInt + private final int mContentUriOwnerUserId; @NonNull private final ClipDescription mDescription; @Nullable @@ -73,6 +89,7 @@ public final class InputContentInfo implements Parcelable { @Nullable Uri linkUri) { validateInternal(contentUri, description, linkUri, true /* throwException */); mContentUri = contentUri; + mContentUriOwnerUserId = UserHandle.myUserId(); mDescription = description; mLinkUri = linkUri; } @@ -121,6 +138,13 @@ public final class InputContentInfo implements Parcelable { } return false; } + if (ContentProvider.uriHasUserId(contentUri)) { + if (throwException) { + throw new InvalidParameterException( + "contentUri with a user ID is not currently supported"); + } + return false; + } if (linkUri != null) { final String scheme = linkUri.getScheme(); if (scheme == null || @@ -139,7 +163,14 @@ public final class InputContentInfo implements Parcelable { * @return Content URI with which the content can be obtained. */ @NonNull - public Uri getContentUri() { return mContentUri; } + public Uri getContentUri() { + // Fix up the content URI when and only when the caller's user ID does not match the owner's + // user ID. + if (mContentUriOwnerUserId != UserHandle.myUserId()) { + return ContentProvider.maybeAddUserId(mContentUri, mContentUriOwnerUserId); + } + return mContentUri; + } /** * @return {@link ClipDescription} object that contains the metadata of {@code #getContentUri()} @@ -203,6 +234,7 @@ public final class InputContentInfo implements Parcelable { @Override public void writeToParcel(Parcel dest, int flags) { Uri.writeToParcel(dest, mContentUri); + dest.writeInt(mContentUriOwnerUserId); mDescription.writeToParcel(dest, flags); Uri.writeToParcel(dest, mLinkUri); if (mUriToken != null) { @@ -215,6 +247,7 @@ public final class InputContentInfo implements Parcelable { private InputContentInfo(@NonNull Parcel source) { mContentUri = Uri.CREATOR.createFromParcel(source); + mContentUriOwnerUserId = source.readInt(); mDescription = ClipDescription.CREATOR.createFromParcel(source); mLinkUri = Uri.CREATOR.createFromParcel(source); if (source.readInt() == 1) {