Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 16e67edb authored by Yohei Yukawa's avatar Yohei Yukawa
Browse files

Fix up content URI for different users

Currently Commit Content API work only when the content URI provided by
the IME is accessible to the target application.  This is non-trivial if
the target application is running as a different user (profile) and it
is actually a possible scenario when managed profile is enabled.

This CL takes care of such a situation, by fixing up the content URI
when and only when InputContentInfo#getContentUri() is called from a
different user than the owner of the content URI.

This CL also makes it clear that we currently do not support content
URIs that already have embedded user IDs.  Since
IActivityManager#grantUriPermissionFromOwner() does not support such
URIs, we should have had a special handling for such a case, which will
be addressed in a subsequent CL.

Bug: 32427307
Bug: 32778718
Test: Made sure that Commit Content API works as expected on a managed
      profile created by
      https://github.com/googlesamples/android-testdpc
Change-Id: I19d87fc19beea248f49b59ec5a5711b95bcbb466
parent 446e723c
Loading
Loading
Loading
Loading
+34 −1
Original line number Diff line number Diff line
@@ -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.
     *
     * <p>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</p>
     */
    @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) {