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
This commit is contained in:
Yohei Yukawa
2016-11-10 00:40:56 -08:00
parent 446e723c08
commit 16e67edb36

View File

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