diff options
15 files changed, 479 insertions, 165 deletions
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index ec2868a..296e9d3 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -1114,7 +1114,8 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM int pid = data.readInt(); int uid = data.readInt(); int mode = data.readInt(); - int res = checkUriPermission(uri, pid, uid, mode); + int userId = data.readInt(); + int res = checkUriPermission(uri, pid, uid, mode, userId); reply.writeNoException(); reply.writeInt(res); return true; @@ -1139,7 +1140,8 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM String targetPkg = data.readString(); Uri uri = Uri.CREATOR.createFromParcel(data); int mode = data.readInt(); - grantUriPermission(app, targetPkg, uri, mode); + int userId = data.readInt(); + grantUriPermission(app, targetPkg, uri, mode, userId); reply.writeNoException(); return true; } @@ -1150,7 +1152,8 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM IApplicationThread app = ApplicationThreadNative.asInterface(b); Uri uri = Uri.CREATOR.createFromParcel(data); int mode = data.readInt(); - revokeUriPermission(app, uri, mode); + int userId = data.readInt(); + revokeUriPermission(app, uri, mode, userId); reply.writeNoException(); return true; } @@ -1159,7 +1162,8 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM data.enforceInterface(IActivityManager.descriptor); Uri uri = Uri.CREATOR.createFromParcel(data); int mode = data.readInt(); - takePersistableUriPermission(uri, mode); + int userId = data.readInt(); + takePersistableUriPermission(uri, mode, userId); reply.writeNoException(); return true; } @@ -1168,7 +1172,8 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM data.enforceInterface(IActivityManager.descriptor); Uri uri = Uri.CREATOR.createFromParcel(data); int mode = data.readInt(); - releasePersistableUriPermission(uri, mode); + int userId = data.readInt(); + releasePersistableUriPermission(uri, mode, userId); reply.writeNoException(); return true; } @@ -1602,7 +1607,8 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM String targetPkg = data.readString(); Uri uri = Uri.CREATOR.createFromParcel(data); int mode = data.readInt(); - grantUriPermissionFromOwner(owner, fromUid, targetPkg, uri, mode); + int userId = data.readInt(); + grantUriPermissionFromOwner(owner, fromUid, targetPkg, uri, mode, userId); reply.writeNoException(); return true; } @@ -1612,10 +1618,11 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM IBinder owner = data.readStrongBinder(); Uri uri = null; if (data.readInt() != 0) { - Uri.CREATOR.createFromParcel(data); + uri = Uri.CREATOR.createFromParcel(data); } int mode = data.readInt(); - revokeUriPermissionFromOwner(owner, uri, mode); + int userId = data.readInt(); + revokeUriPermissionFromOwner(owner, uri, mode, userId); reply.writeNoException(); return true; } @@ -1626,7 +1633,8 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM String targetPkg = data.readString(); Uri uri = Uri.CREATOR.createFromParcel(data); int modeFlags = data.readInt(); - int res = checkGrantUriPermission(callingUid, targetPkg, uri, modeFlags); + int userId = data.readInt(); + int res = checkGrantUriPermission(callingUid, targetPkg, uri, modeFlags, userId); reply.writeNoException(); reply.writeInt(res); return true; @@ -3540,7 +3548,7 @@ class ActivityManagerProxy implements IActivityManager reply.recycle(); return res; } - public int checkUriPermission(Uri uri, int pid, int uid, int mode) + public int checkUriPermission(Uri uri, int pid, int uid, int mode, int userId) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); @@ -3549,6 +3557,7 @@ class ActivityManagerProxy implements IActivityManager data.writeInt(pid); data.writeInt(uid); data.writeInt(mode); + data.writeInt(userId); mRemote.transact(CHECK_URI_PERMISSION_TRANSACTION, data, reply, 0); reply.readException(); int res = reply.readInt(); @@ -3557,7 +3566,7 @@ class ActivityManagerProxy implements IActivityManager return res; } public void grantUriPermission(IApplicationThread caller, String targetPkg, - Uri uri, int mode) throws RemoteException { + Uri uri, int mode, int userId) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); @@ -3565,19 +3574,21 @@ class ActivityManagerProxy implements IActivityManager data.writeString(targetPkg); uri.writeToParcel(data, 0); data.writeInt(mode); + data.writeInt(userId); mRemote.transact(GRANT_URI_PERMISSION_TRANSACTION, data, reply, 0); reply.readException(); data.recycle(); reply.recycle(); } public void revokeUriPermission(IApplicationThread caller, Uri uri, - int mode) throws RemoteException { + int mode, int userId) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); data.writeStrongBinder(caller.asBinder()); uri.writeToParcel(data, 0); data.writeInt(mode); + data.writeInt(userId); mRemote.transact(REVOKE_URI_PERMISSION_TRANSACTION, data, reply, 0); reply.readException(); data.recycle(); @@ -3585,12 +3596,14 @@ class ActivityManagerProxy implements IActivityManager } @Override - public void takePersistableUriPermission(Uri uri, int mode) throws RemoteException { + public void takePersistableUriPermission(Uri uri, int mode, int userId) + throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); uri.writeToParcel(data, 0); data.writeInt(mode); + data.writeInt(userId); mRemote.transact(TAKE_PERSISTABLE_URI_PERMISSION_TRANSACTION, data, reply, 0); reply.readException(); data.recycle(); @@ -3598,12 +3611,14 @@ class ActivityManagerProxy implements IActivityManager } @Override - public void releasePersistableUriPermission(Uri uri, int mode) throws RemoteException { + public void releasePersistableUriPermission(Uri uri, int mode, int userId) + throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); uri.writeToParcel(data, 0); data.writeInt(mode); + data.writeInt(userId); mRemote.transact(RELEASE_PERSISTABLE_URI_PERMISSION_TRANSACTION, data, reply, 0); reply.readException(); data.recycle(); @@ -4157,7 +4172,7 @@ class ActivityManagerProxy implements IActivityManager } public void grantUriPermissionFromOwner(IBinder owner, int fromUid, String targetPkg, - Uri uri, int mode) throws RemoteException { + Uri uri, int mode, int userId) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); @@ -4166,6 +4181,7 @@ class ActivityManagerProxy implements IActivityManager data.writeString(targetPkg); uri.writeToParcel(data, 0); data.writeInt(mode); + data.writeInt(userId); mRemote.transact(GRANT_URI_PERMISSION_TRANSACTION, data, reply, 0); reply.readException(); data.recycle(); @@ -4173,7 +4189,7 @@ class ActivityManagerProxy implements IActivityManager } public void revokeUriPermissionFromOwner(IBinder owner, Uri uri, - int mode) throws RemoteException { + int mode, int userId) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); @@ -4185,6 +4201,7 @@ class ActivityManagerProxy implements IActivityManager data.writeInt(0); } data.writeInt(mode); + data.writeInt(userId); mRemote.transact(REVOKE_URI_PERMISSION_TRANSACTION, data, reply, 0); reply.readException(); data.recycle(); @@ -4192,7 +4209,7 @@ class ActivityManagerProxy implements IActivityManager } public int checkGrantUriPermission(int callingUid, String targetPkg, - Uri uri, int modeFlags) throws RemoteException { + Uri uri, int modeFlags, int userId) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); @@ -4200,6 +4217,7 @@ class ActivityManagerProxy implements IActivityManager data.writeString(targetPkg); uri.writeToParcel(data, 0); data.writeInt(modeFlags); + data.writeInt(userId); mRemote.transact(CHECK_GRANT_URI_PERMISSION_TRANSACTION, data, reply, 0); reply.readException(); int res = reply.readInt(); diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 801182d..b4d8942 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -26,6 +26,7 @@ import com.android.internal.util.Preconditions; import android.bluetooth.BluetoothManager; import android.content.BroadcastReceiver; import android.content.ComponentName; +import android.content.ContentProvider; import android.content.ContentResolver; import android.content.Context; import android.content.ContextWrapper; @@ -1818,8 +1819,8 @@ class ContextImpl extends Context { public void grantUriPermission(String toPackage, Uri uri, int modeFlags) { try { ActivityManagerNative.getDefault().grantUriPermission( - mMainThread.getApplicationThread(), toPackage, uri, - modeFlags); + mMainThread.getApplicationThread(), toPackage, + ContentProvider.getUriWithoutUserId(uri), modeFlags, resolveUserId(uri)); } catch (RemoteException e) { } } @@ -1828,8 +1829,8 @@ class ContextImpl extends Context { public void revokeUriPermission(Uri uri, int modeFlags) { try { ActivityManagerNative.getDefault().revokeUriPermission( - mMainThread.getApplicationThread(), uri, - modeFlags); + mMainThread.getApplicationThread(), + ContentProvider.getUriWithoutUserId(uri), modeFlags, resolveUserId(uri)); } catch (RemoteException e) { } } @@ -1838,12 +1839,17 @@ class ContextImpl extends Context { public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) { try { return ActivityManagerNative.getDefault().checkUriPermission( - uri, pid, uid, modeFlags); + ContentProvider.getUriWithoutUserId(uri), pid, uid, modeFlags, + resolveUserId(uri)); } catch (RemoteException e) { return PackageManager.PERMISSION_DENIED; } } + private int resolveUserId(Uri uri) { + return ContentProvider.getUserIdFromUri(uri, getUserId()); + } + @Override public int checkCallingUriPermission(Uri uri, int modeFlags) { int pid = Binder.getCallingPid(); @@ -2280,12 +2286,16 @@ class ContextImpl extends Context { @Override protected IContentProvider acquireProvider(Context context, String auth) { - return mMainThread.acquireProvider(context, auth, mUser.getIdentifier(), true); + return mMainThread.acquireProvider(context, + ContentProvider.getAuthorityWithoutUserId(auth), + resolveUserIdFromAuthority(auth), true); } @Override protected IContentProvider acquireExistingProvider(Context context, String auth) { - return mMainThread.acquireExistingProvider(context, auth, mUser.getIdentifier(), true); + return mMainThread.acquireExistingProvider(context, + ContentProvider.getAuthorityWithoutUserId(auth), + resolveUserIdFromAuthority(auth), true); } @Override @@ -2295,7 +2305,9 @@ class ContextImpl extends Context { @Override protected IContentProvider acquireUnstableProvider(Context c, String auth) { - return mMainThread.acquireProvider(c, auth, mUser.getIdentifier(), false); + return mMainThread.acquireProvider(c, + ContentProvider.getAuthorityWithoutUserId(auth), + resolveUserIdFromAuthority(auth), false); } @Override @@ -2312,5 +2324,10 @@ class ContextImpl extends Context { public void appNotRespondingViaProvider(IContentProvider icp) { mMainThread.appNotRespondingViaProvider(icp.asBinder()); } + + /** @hide */ + protected int resolveUserIdFromAuthority(String auth) { + return ContentProvider.getUserIdFromAuthority(auth, mUser.getIdentifier()); + } } } diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index 074b427..a30a64a 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -210,14 +210,16 @@ public interface IActivityManager extends IInterface { public int checkPermission(String permission, int pid, int uid) throws RemoteException; - public int checkUriPermission(Uri uri, int pid, int uid, int mode) + public int checkUriPermission(Uri uri, int pid, int uid, int mode, int userId) + throws RemoteException; + public void grantUriPermission(IApplicationThread caller, String targetPkg, Uri uri, + int mode, int userId) throws RemoteException; + public void revokeUriPermission(IApplicationThread caller, Uri uri, int mode, int userId) + throws RemoteException; + public void takePersistableUriPermission(Uri uri, int modeFlags, int userId) + throws RemoteException; + public void releasePersistableUriPermission(Uri uri, int modeFlags, int userId) throws RemoteException; - public void grantUriPermission(IApplicationThread caller, String targetPkg, - Uri uri, int mode) throws RemoteException; - public void revokeUriPermission(IApplicationThread caller, Uri uri, - int mode) throws RemoteException; - public void takePersistableUriPermission(Uri uri, int modeFlags) throws RemoteException; - public void releasePersistableUriPermission(Uri uri, int modeFlags) throws RemoteException; public ParceledListSlice<UriPermission> getPersistedUriPermissions( String packageName, boolean incoming) throws RemoteException; @@ -323,12 +325,12 @@ public interface IActivityManager extends IInterface { public IBinder newUriPermissionOwner(String name) throws RemoteException; public void grantUriPermissionFromOwner(IBinder owner, int fromUid, String targetPkg, - Uri uri, int mode) throws RemoteException; + Uri uri, int mode, int userId) throws RemoteException; public void revokeUriPermissionFromOwner(IBinder owner, Uri uri, - int mode) throws RemoteException; + int mode, int userId) throws RemoteException; - public int checkGrantUriPermission(int callingUid, String targetPkg, - Uri uri, int modeFlags) throws RemoteException; + public int checkGrantUriPermission(int callingUid, String targetPkg, Uri uri, + int modeFlags, int userId) throws RemoteException; // Cause the specified process to dump the specified heap. public boolean dumpHeap(String process, int userId, boolean managed, String path, diff --git a/core/java/android/content/ClipData.java b/core/java/android/content/ClipData.java index 50c4fed..b44abf9 100644 --- a/core/java/android/content/ClipData.java +++ b/core/java/android/content/ClipData.java @@ -16,6 +16,7 @@ package android.content; +import static android.content.ContentProvider.maybeAddUserId; import android.content.res.AssetFileDescriptor; import android.graphics.Bitmap; import android.net.Uri; @@ -186,7 +187,7 @@ public class ClipData implements Parcelable { final CharSequence mText; final String mHtmlText; final Intent mIntent; - final Uri mUri; + Uri mUri; /** * Create an Item consisting of a single block of (possibly styled) text. @@ -809,6 +810,24 @@ public class ClipData implements Parcelable { } } + /** + * Prepare this {@link ClipData} to leave an app process. + * + * @hide + */ + public void prepareToLeaveUser(int userId) { + final int size = mItems.size(); + for (int i = 0; i < size; i++) { + final Item item = mItems.get(i); + if (item.mIntent != null) { + item.mIntent.prepareToLeaveUser(userId); + } + if (item.mUri != null) { + item.mUri = maybeAddUserId(item.mUri, userId); + } + } + } + @Override public String toString() { StringBuilder b = new StringBuilder(128); diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java index 02c850b..be9782f 100644 --- a/core/java/android/content/ContentProvider.java +++ b/core/java/android/content/ContentProvider.java @@ -36,6 +36,7 @@ import android.os.ParcelFileDescriptor; import android.os.Process; import android.os.UserHandle; import android.util.Log; +import android.text.TextUtils; import java.io.File; import java.io.FileDescriptor; @@ -195,6 +196,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 { return rejectQuery(uri, projection, selection, selectionArgs, sortOrder, CancellationSignal.fromTransport(cancellationSignal)); } + uri = getUriWithoutUserId(uri); final String original = setCallingPackage(callingPkg); try { return ContentProvider.this.query( @@ -207,6 +209,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 { @Override public String getType(Uri uri) { + uri = getUriWithoutUserId(uri); return ContentProvider.this.getType(uri); } @@ -215,9 +218,11 @@ public abstract class ContentProvider implements ComponentCallbacks2 { if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) { return rejectInsert(uri, initialValues); } + int userId = getUserIdFromUri(uri); + uri = getUriWithoutUserId(uri); final String original = setCallingPackage(callingPkg); try { - return ContentProvider.this.insert(uri, initialValues); + return maybeAddUserId(ContentProvider.this.insert(uri, initialValues), userId); } finally { setCallingPackage(original); } @@ -228,6 +233,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 { if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) { return 0; } + uri = getUriWithoutUserId(uri); final String original = setCallingPackage(callingPkg); try { return ContentProvider.this.bulkInsert(uri, initialValues); @@ -240,24 +246,39 @@ public abstract class ContentProvider implements ComponentCallbacks2 { public ContentProviderResult[] applyBatch(String callingPkg, ArrayList<ContentProviderOperation> operations) throws OperationApplicationException { - for (ContentProviderOperation operation : operations) { + int numOperations = operations.size(); + final int[] userIds = new int[numOperations]; + for (int i = 0; i < numOperations; i++) { + ContentProviderOperation operation = operations.get(i); + userIds[i] = getUserIdFromUri(operation.getUri()); if (operation.isReadOperation()) { if (enforceReadPermission(callingPkg, operation.getUri()) != AppOpsManager.MODE_ALLOWED) { throw new OperationApplicationException("App op not allowed", 0); } } - if (operation.isWriteOperation()) { if (enforceWritePermission(callingPkg, operation.getUri()) != AppOpsManager.MODE_ALLOWED) { throw new OperationApplicationException("App op not allowed", 0); } } + if (userIds[i] != UserHandle.USER_CURRENT) { + // Removing the user id from the uri. + operation = new ContentProviderOperation(operation, true); + } + operations.set(i, operation); } final String original = setCallingPackage(callingPkg); try { - return ContentProvider.this.applyBatch(operations); + ContentProviderResult[] results = ContentProvider.this.applyBatch(operations); + for (int i = 0; i < results.length ; i++) { + if (userIds[i] != UserHandle.USER_CURRENT) { + // Adding the userId to the uri. + results[i] = new ContentProviderResult(results[i], userIds[i]); + } + } + return results; } finally { setCallingPackage(original); } @@ -268,6 +289,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 { if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) { return 0; } + uri = getUriWithoutUserId(uri); final String original = setCallingPackage(callingPkg); try { return ContentProvider.this.delete(uri, selection, selectionArgs); @@ -282,6 +304,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 { if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) { return 0; } + uri = getUriWithoutUserId(uri); final String original = setCallingPackage(callingPkg); try { return ContentProvider.this.update(uri, values, selection, selectionArgs); @@ -295,6 +318,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 { String callingPkg, Uri uri, String mode, ICancellationSignal cancellationSignal) throws FileNotFoundException { enforceFilePermission(callingPkg, uri, mode); + uri = getUriWithoutUserId(uri); final String original = setCallingPackage(callingPkg); try { return ContentProvider.this.openFile( @@ -309,6 +333,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 { String callingPkg, Uri uri, String mode, ICancellationSignal cancellationSignal) throws FileNotFoundException { enforceFilePermission(callingPkg, uri, mode); + uri = getUriWithoutUserId(uri); final String original = setCallingPackage(callingPkg); try { return ContentProvider.this.openAssetFile( @@ -330,6 +355,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 { @Override public String[] getStreamTypes(Uri uri, String mimeTypeFilter) { + uri = getUriWithoutUserId(uri); return ContentProvider.this.getStreamTypes(uri, mimeTypeFilter); } @@ -337,6 +363,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 { public AssetFileDescriptor openTypedAssetFile(String callingPkg, Uri uri, String mimeType, Bundle opts, ICancellationSignal cancellationSignal) throws FileNotFoundException { enforceFilePermission(callingPkg, uri, "r"); + uri = getUriWithoutUserId(uri); final String original = setCallingPackage(callingPkg); try { return ContentProvider.this.openTypedAssetFile( @@ -356,9 +383,11 @@ public abstract class ContentProvider implements ComponentCallbacks2 { if (enforceReadPermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) { return null; } + int userId = getUserIdFromUri(uri); + uri = getUriWithoutUserId(uri); final String original = setCallingPackage(callingPkg); try { - return ContentProvider.this.canonicalize(uri); + return maybeAddUserId(ContentProvider.this.canonicalize(uri), userId); } finally { setCallingPackage(original); } @@ -369,9 +398,11 @@ public abstract class ContentProvider implements ComponentCallbacks2 { if (enforceReadPermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) { return null; } + int userId = getUserIdFromUri(uri); + uri = getUriWithoutUserId(uri); final String original = setCallingPackage(callingPkg); try { - return ContentProvider.this.uncanonicalize(uri); + return maybeAddUserId(ContentProvider.this.uncanonicalize(uri), userId); } finally { setCallingPackage(original); } @@ -1680,4 +1711,75 @@ public abstract class ContentProvider implements ComponentCallbacks2 { public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { writer.println("nothing to dump"); } + + /** @hide */ + public static int getUserIdFromAuthority(String auth, int defaultUserId) { + if (auth == null) return defaultUserId; + int end = auth.indexOf('@'); + if (end == -1) return defaultUserId; + String userIdString = auth.substring(0, end); + try { + return Integer.parseInt(userIdString); + } catch (NumberFormatException e) { + Log.w(TAG, "Error parsing userId.", e); + return UserHandle.USER_NULL; + } + } + + /** @hide */ + public static int getUserIdFromAuthority(String auth) { + return getUserIdFromAuthority(auth, UserHandle.USER_CURRENT); + } + + /** @hide */ + public static int getUserIdFromUri(Uri uri, int defaultUserId) { + if (uri == null) return defaultUserId; + return getUserIdFromAuthority(uri.getAuthority(), defaultUserId); + } + + /** @hide */ + public static int getUserIdFromUri(Uri uri) { + return getUserIdFromUri(uri, UserHandle.USER_CURRENT); + } + + /** + * Removes userId part from authority string. Expects format: + * userId@some.authority + * If there is no userId in the authority, it symply returns the argument + * @hide + */ + public static String getAuthorityWithoutUserId(String auth) { + if (auth == null) return null; + int end = auth.indexOf('@'); + return auth.substring(end+1); + } + + /** @hide */ + public static Uri getUriWithoutUserId(Uri uri) { + if (uri == null) return null; + Uri.Builder builder = uri.buildUpon(); + builder.authority(getAuthorityWithoutUserId(uri.getAuthority())); + return builder.build(); + } + + /** @hide */ + public static boolean uriHasUserId(Uri uri) { + if (uri == null) return false; + return !TextUtils.isEmpty(uri.getUserInfo()); + } + + /** @hide */ + public static Uri maybeAddUserId(Uri uri, int userId) { + if (uri == null) return null; + if (userId != UserHandle.USER_CURRENT + && ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) { + if (!uriHasUserId(uri)) { + //We don't add the user Id if there's already one + Uri.Builder builder = uri.buildUpon(); + builder.encodedAuthority("" + userId + "@" + uri.getEncodedAuthority()); + return builder.build(); + } + } + return uri; + } } diff --git a/core/java/android/content/ContentProviderOperation.java b/core/java/android/content/ContentProviderOperation.java index 12e9bab..136e54d 100644 --- a/core/java/android/content/ContentProviderOperation.java +++ b/core/java/android/content/ContentProviderOperation.java @@ -16,6 +16,7 @@ package android.content; +import android.content.ContentProvider; import android.database.Cursor; import android.net.Uri; import android.os.Parcel; @@ -87,6 +88,31 @@ public class ContentProviderOperation implements Parcelable { mYieldAllowed = source.readInt() != 0; } + /** @hide */ + public ContentProviderOperation(ContentProviderOperation cpo, boolean removeUserIdFromUri) { + mType = cpo.mType; + if (removeUserIdFromUri) { + mUri = ContentProvider.getUriWithoutUserId(cpo.mUri); + } else { + mUri = cpo.mUri; + } + mValues = cpo.mValues; + mSelection = cpo.mSelection; + mSelectionArgs = cpo.mSelectionArgs; + mExpectedCount = cpo.mExpectedCount; + mSelectionArgsBackReferences = cpo.mSelectionArgsBackReferences; + mValuesBackReferences = cpo.mValuesBackReferences; + mYieldAllowed = cpo.mYieldAllowed; + } + + /** @hide */ + public ContentProviderOperation getWithoutUserIdInUri() { + if (ContentProvider.uriHasUserId(mUri)) { + return new ContentProviderOperation(this, true); + } + return this; + } + public void writeToParcel(Parcel dest, int flags) { dest.writeInt(mType); Uri.writeToParcel(dest, mUri); @@ -387,7 +413,6 @@ public class ContentProviderOperation implements Parcelable { } }; - /** * Used to add parameters to a {@link ContentProviderOperation}. The {@link Builder} is * first created by calling {@link ContentProviderOperation#newInsert(android.net.Uri)}, diff --git a/core/java/android/content/ContentProviderResult.java b/core/java/android/content/ContentProviderResult.java index 5d188ef..ec3d002 100644 --- a/core/java/android/content/ContentProviderResult.java +++ b/core/java/android/content/ContentProviderResult.java @@ -16,7 +16,9 @@ package android.content; +import android.content.ContentProvider; import android.net.Uri; +import android.os.UserHandle; import android.os.Parcelable; import android.os.Parcel; @@ -50,6 +52,12 @@ public class ContentProviderResult implements Parcelable { } } + /** @hide */ + public ContentProviderResult(ContentProviderResult cpr, int userId) { + uri = ContentProvider.maybeAddUserId(cpr.uri, userId); + count = cpr.count; + } + public void writeToParcel(Parcel dest, int flags) { if (uri == null) { dest.writeInt(1); @@ -81,4 +89,4 @@ public class ContentProviderResult implements Parcelable { } return "ContentProviderResult(count=" + count + ")"; } -}
\ No newline at end of file +} diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java index 5b41394..7642e13 100644 --- a/core/java/android/content/ContentResolver.java +++ b/core/java/android/content/ContentResolver.java @@ -1643,7 +1643,8 @@ public abstract class ContentResolver { */ public void takePersistableUriPermission(Uri uri, @Intent.AccessUriMode int modeFlags) { try { - ActivityManagerNative.getDefault().takePersistableUriPermission(uri, modeFlags); + ActivityManagerNative.getDefault().takePersistableUriPermission( + ContentProvider.getUriWithoutUserId(uri), modeFlags, resolveUserId(uri)); } catch (RemoteException e) { } } @@ -1658,7 +1659,8 @@ public abstract class ContentResolver { */ public void releasePersistableUriPermission(Uri uri, @Intent.AccessUriMode int modeFlags) { try { - ActivityManagerNative.getDefault().releasePersistableUriPermission(uri, modeFlags); + ActivityManagerNative.getDefault().releasePersistableUriPermission( + ContentProvider.getUriWithoutUserId(uri), modeFlags, resolveUserId(uri)); } catch (RemoteException e) { } } @@ -2462,4 +2464,9 @@ public abstract class ContentResolver { private final Context mContext; final String mPackageName; private static final String TAG = "ContentResolver"; + + /** @hide */ + public int resolveUserId(Uri uri) { + return ContentProvider.getUserIdFromUri(uri, mContext.getUserId()); + } } diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 3cfc56c..076f657 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -26,6 +26,7 @@ import android.annotation.IntDef; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.content.pm.ActivityInfo; +import static android.content.ContentProvider.maybeAddUserId; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.res.Resources; @@ -7433,6 +7434,41 @@ public class Intent implements Parcelable, Cloneable { } /** + * Prepare this {@link Intent} to be sent to another user + * + * @hide + */ + public void prepareToLeaveUser(int userId) { + Uri data = getData(); + if (data != null) { + mData = maybeAddUserId(data, userId); + } + if (mSelector != null) { + mSelector.prepareToLeaveUser(userId); + } + if (mClipData != null) { + mClipData.prepareToLeaveUser(userId); + } + String action = getAction(); + if (ACTION_SEND.equals(action)) { + final Uri stream = getParcelableExtra(EXTRA_STREAM); + if (stream != null) { + putExtra(EXTRA_STREAM, maybeAddUserId(stream, userId)); + } + } + if (ACTION_SEND_MULTIPLE.equals(action)) { + final ArrayList<Uri> streams = getParcelableArrayListExtra(EXTRA_STREAM); + if (streams != null) { + ArrayList<Uri> newStreams = new ArrayList<Uri>(); + for (int i = 0; i < streams.size(); i++) { + newStreams.add(maybeAddUserId(streams.get(i), userId)); + } + putParcelableArrayListExtra(EXTRA_STREAM, newStreams); + } + } + } + + /** * Migrate any {@link #EXTRA_STREAM} in {@link #ACTION_SEND} and * {@link #ACTION_SEND_MULTIPLE} to {@link ClipData}. Also inspects nested * intents in {@link #ACTION_CHOOSER}. diff --git a/core/java/com/android/internal/app/IntentForwarderActivity.java b/core/java/com/android/internal/app/IntentForwarderActivity.java index 2f74372..47ef65a 100644 --- a/core/java/com/android/internal/app/IntentForwarderActivity.java +++ b/core/java/com/android/internal/app/IntentForwarderActivity.java @@ -84,6 +84,7 @@ public class IntentForwarderActivity extends Activity { Slog.e(TAG, "PackageManagerService is dead?"); } if (canForward) { + newIntent.prepareToLeaveUser(callingUserId); startActivityAsUser(newIntent, userDest); } else { Slog.wtf(TAG, "the intent: " + newIntent + "cannot be forwarded from user " diff --git a/core/java/com/android/internal/util/XmlUtils.java b/core/java/com/android/internal/util/XmlUtils.java index b35de93..5b59599 100644 --- a/core/java/com/android/internal/util/XmlUtils.java +++ b/core/java/com/android/internal/util/XmlUtils.java @@ -912,6 +912,15 @@ public class XmlUtils { } } + public static int readIntAttribute(XmlPullParser in, String name, int defaultValue) { + final String value = in.getAttributeValue(null, name); + try { + return Integer.parseInt(value); + } catch (NumberFormatException e) { + return defaultValue; + } + } + public static int readIntAttribute(XmlPullParser in, String name) throws IOException { final String value = in.getAttributeValue(null, name); try { diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 344268a..d6457c3 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -722,6 +722,8 @@ public final class ActivityManagerService extends ActivityManagerNative private static final String TAG_URI_GRANTS = "uri-grants"; private static final String TAG_URI_GRANT = "uri-grant"; private static final String ATTR_USER_HANDLE = "userHandle"; + private static final String ATTR_SOURCE_USER_ID = "sourceUserId"; + private static final String ATTR_TARGET_USER_ID = "targetUserId"; private static final String ATTR_SOURCE_PKG = "sourcePkg"; private static final String ATTR_TARGET_PKG = "targetPkg"; private static final String ATTR_URI = "uri"; @@ -739,10 +741,12 @@ public final class ActivityManagerService extends ActivityManagerNative mGrantedUriPermissions = new SparseArray<ArrayMap<GrantUri, UriPermission>>(); public static class GrantUri { + public final int sourceUserId; public final Uri uri; - public final boolean prefix; + public boolean prefix; - public GrantUri(Uri uri, boolean prefix) { + public GrantUri(int sourceUserId, Uri uri, boolean prefix) { + this.sourceUserId = sourceUserId; this.uri = uri; this.prefix = prefix; } @@ -756,18 +760,28 @@ public final class ActivityManagerService extends ActivityManagerNative public boolean equals(Object o) { if (o instanceof GrantUri) { GrantUri other = (GrantUri) o; - return uri.equals(other.uri) && prefix == other.prefix; + return uri.equals(other.uri) && (sourceUserId == other.sourceUserId) + && prefix == other.prefix; } return false; } @Override public String toString() { - if (prefix) { - return uri.toString() + " [prefix]"; - } else { - return uri.toString(); - } + String result = Integer.toString(sourceUserId) + " @ " + uri.toString(); + if (prefix) result += " [prefix]"; + return result; + } + + public String toSafeString() { + String result = Integer.toString(sourceUserId) + " @ " + uri.toSafeString(); + if (prefix) result += " [prefix]"; + return result; + } + + public static GrantUri resolve(int defaultSourceUserHandle, Uri uri) { + return new GrantUri(ContentProvider.getUserIdFromUri(uri, defaultSourceUserHandle), + ContentProvider.getUriWithoutUserId(uri), false); } } @@ -5991,9 +6005,9 @@ public final class ActivityManagerService extends ActivityManagerNative * in {@link ContentProvider}. */ private final boolean checkHoldingPermissionsLocked( - IPackageManager pm, ProviderInfo pi, Uri uri, int uid, final int modeFlags) { + IPackageManager pm, ProviderInfo pi, GrantUri grantUri, int uid, final int modeFlags) { if (DEBUG_URI_PERMISSION) Slog.v(TAG, - "checkHoldingPermissionsLocked: uri=" + uri + " uid=" + uid); + "checkHoldingPermissionsLocked: uri=" + grantUri + " uid=" + uid); if (pi.applicationInfo.uid == uid) { return true; @@ -6022,7 +6036,7 @@ public final class ActivityManagerService extends ActivityManagerNative // check if target holds any <path-permission> that match uri final PathPermission[] pps = pi.pathPermissions; if (pps != null) { - final String path = uri.getPath(); + final String path = grantUri.uri.getPath(); int i = pps.length; while (i > 0 && (!readMet || !writeMet)) { i--; @@ -6087,32 +6101,33 @@ public final class ActivityManagerService extends ActivityManagerNative return pi; } - private UriPermission findUriPermissionLocked(int targetUid, GrantUri uri) { + private UriPermission findUriPermissionLocked(int targetUid, GrantUri grantUri) { final ArrayMap<GrantUri, UriPermission> targetUris = mGrantedUriPermissions.get(targetUid); if (targetUris != null) { - return targetUris.get(uri); + return targetUris.get(grantUri); } return null; } private UriPermission findOrCreateUriPermissionLocked(String sourcePkg, - String targetPkg, int targetUid, GrantUri uri) { + String targetPkg, int targetUid, GrantUri grantUri) { ArrayMap<GrantUri, UriPermission> targetUris = mGrantedUriPermissions.get(targetUid); if (targetUris == null) { targetUris = Maps.newArrayMap(); mGrantedUriPermissions.put(targetUid, targetUris); } - UriPermission perm = targetUris.get(uri); + UriPermission perm = targetUris.get(grantUri); if (perm == null) { - perm = new UriPermission(sourcePkg, targetPkg, targetUid, uri); - targetUris.put(uri, perm); + perm = new UriPermission(sourcePkg, targetPkg, targetUid, grantUri); + targetUris.put(grantUri, perm); } return perm; } - private final boolean checkUriPermissionLocked(Uri uri, int uid, final int modeFlags) { + private final boolean checkUriPermissionLocked(GrantUri grantUri, int uid, + final int modeFlags) { final boolean persistable = (modeFlags & Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) != 0; final int minStrength = persistable ? UriPermission.STRENGTH_PERSISTABLE : UriPermission.STRENGTH_OWNED; @@ -6126,7 +6141,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (perms == null) return false; // First look for exact match - final UriPermission exactPerm = perms.get(new GrantUri(uri, false)); + final UriPermission exactPerm = perms.get(grantUri); if (exactPerm != null && exactPerm.getStrength(modeFlags) >= minStrength) { return true; } @@ -6135,7 +6150,7 @@ public final class ActivityManagerService extends ActivityManagerNative final int N = perms.size(); for (int i = 0; i < N; i++) { final UriPermission perm = perms.valueAt(i); - if (perm.uri.prefix && uri.isPathPrefixMatch(perm.uri.uri) + if (perm.uri.prefix && grantUri.uri.isPathPrefixMatch(perm.uri.uri) && perm.getStrength(modeFlags) >= minStrength) { return true; } @@ -6145,7 +6160,8 @@ public final class ActivityManagerService extends ActivityManagerNative } @Override - public int checkUriPermission(Uri uri, int pid, int uid, final int modeFlags) { + public int checkUriPermission(Uri uri, int pid, int uid, + final int modeFlags, int userId) { enforceNotIsolatedCaller("checkUriPermission"); // Another redirected-binder-call permissions check as in @@ -6161,7 +6177,7 @@ public final class ActivityManagerService extends ActivityManagerNative return PackageManager.PERMISSION_GRANTED; } synchronized (this) { - return checkUriPermissionLocked(uri, uid, modeFlags) + return checkUriPermissionLocked(new GrantUri(userId, uri, false), uid, modeFlags) ? PackageManager.PERMISSION_GRANTED : PackageManager.PERMISSION_DENIED; } @@ -6176,30 +6192,31 @@ public final class ActivityManagerService extends ActivityManagerNative * If you already know the uid of the target, you can supply it in * lastTargetUid else set that to -1. */ - int checkGrantUriPermissionLocked(int callingUid, String targetPkg, - Uri uri, final int modeFlags, int lastTargetUid) { + int checkGrantUriPermissionLocked(int callingUid, String targetPkg, GrantUri grantUri, + final int modeFlags, int lastTargetUid) { if (!Intent.isAccessUriMode(modeFlags)) { return -1; } if (targetPkg != null) { if (DEBUG_URI_PERMISSION) Slog.v(TAG, - "Checking grant " + targetPkg + " permission to " + uri); + "Checking grant " + targetPkg + " permission to " + grantUri); } final IPackageManager pm = AppGlobals.getPackageManager(); // If this is not a content: uri, we can't do anything with it. - if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) { + if (!ContentResolver.SCHEME_CONTENT.equals(grantUri.uri.getScheme())) { if (DEBUG_URI_PERMISSION) Slog.v(TAG, - "Can't grant URI permission for non-content URI: " + uri); + "Can't grant URI permission for non-content URI: " + grantUri); return -1; } - final String authority = uri.getAuthority(); - final ProviderInfo pi = getProviderInfoLocked(authority, UserHandle.getUserId(callingUid)); + final String authority = grantUri.uri.getAuthority(); + final ProviderInfo pi = getProviderInfoLocked(authority, grantUri.sourceUserId); if (pi == null) { - Slog.w(TAG, "No content provider found for permission check: " + uri.toSafeString()); + Slog.w(TAG, "No content provider found for permission check: " + + grantUri.uri.toSafeString()); return -1; } @@ -6219,10 +6236,10 @@ public final class ActivityManagerService extends ActivityManagerNative if (targetUid >= 0) { // First... does the target actually need this permission? - if (checkHoldingPermissionsLocked(pm, pi, uri, targetUid, modeFlags)) { + if (checkHoldingPermissionsLocked(pm, pi, grantUri, targetUid, modeFlags)) { // No need to grant the target this permission. if (DEBUG_URI_PERMISSION) Slog.v(TAG, - "Target " + targetPkg + " already has full permission to " + uri); + "Target " + targetPkg + " already has full permission to " + grantUri); return -1; } } else { @@ -6248,14 +6265,14 @@ public final class ActivityManagerService extends ActivityManagerNative throw new SecurityException("Provider " + pi.packageName + "/" + pi.name + " does not allow granting of Uri permissions (uri " - + uri + ")"); + + grantUri + ")"); } if (pi.uriPermissionPatterns != null) { final int N = pi.uriPermissionPatterns.length; boolean allowed = false; for (int i=0; i<N; i++) { if (pi.uriPermissionPatterns[i] != null - && pi.uriPermissionPatterns[i].match(uri.getPath())) { + && pi.uriPermissionPatterns[i].match(grantUri.uri.getPath())) { allowed = true; break; } @@ -6264,35 +6281,35 @@ public final class ActivityManagerService extends ActivityManagerNative throw new SecurityException("Provider " + pi.packageName + "/" + pi.name + " does not allow granting of permission to path of Uri " - + uri); + + grantUri); } } // Third... does the caller itself have permission to access // this uri? - if (callingUid != Process.myUid()) { - if (!checkHoldingPermissionsLocked(pm, pi, uri, callingUid, modeFlags)) { + if (UserHandle.getAppId(callingUid) != Process.SYSTEM_UID) { + if (!checkHoldingPermissionsLocked(pm, pi, grantUri, callingUid, modeFlags)) { // Require they hold a strong enough Uri permission - if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) { + if (!checkUriPermissionLocked(grantUri, callingUid, modeFlags)) { throw new SecurityException("Uid " + callingUid - + " does not have permission to uri " + uri); + + " does not have permission to uri " + grantUri); } } } - return targetUid; } @Override - public int checkGrantUriPermission(int callingUid, String targetPkg, - Uri uri, final int modeFlags) { + public int checkGrantUriPermission(int callingUid, String targetPkg, Uri uri, + final int modeFlags, int userId) { enforceNotIsolatedCaller("checkGrantUriPermission"); synchronized(this) { - return checkGrantUriPermissionLocked(callingUid, targetPkg, uri, modeFlags, -1); + return checkGrantUriPermissionLocked(callingUid, targetPkg, + new GrantUri(userId, uri, false), modeFlags, -1); } } - void grantUriPermissionUncheckedLocked(int targetUid, String targetPkg, Uri uri, + void grantUriPermissionUncheckedLocked(int targetUid, String targetPkg, GrantUri grantUri, final int modeFlags, UriPermissionOwner owner) { if (!Intent.isAccessUriMode(modeFlags)) { return; @@ -6303,36 +6320,40 @@ public final class ActivityManagerService extends ActivityManagerNative // the target. if (DEBUG_URI_PERMISSION) Slog.v(TAG, - "Granting " + targetPkg + "/" + targetUid + " permission to " + uri); + "Granting " + targetPkg + "/" + targetUid + " permission to " + grantUri); - final String authority = uri.getAuthority(); - final ProviderInfo pi = getProviderInfoLocked(authority, UserHandle.getUserId(targetUid)); + final String authority = grantUri.uri.getAuthority(); + final ProviderInfo pi = getProviderInfoLocked(authority, grantUri.sourceUserId); if (pi == null) { - Slog.w(TAG, "No content provider found for grant: " + uri.toSafeString()); + Slog.w(TAG, "No content provider found for grant: " + grantUri.toSafeString()); return; } - final boolean prefix = (modeFlags & Intent.FLAG_GRANT_PREFIX_URI_PERMISSION) != 0; + if ((modeFlags & Intent.FLAG_GRANT_PREFIX_URI_PERMISSION) != 0) { + grantUri.prefix = true; + } final UriPermission perm = findOrCreateUriPermissionLocked( - pi.packageName, targetPkg, targetUid, new GrantUri(uri, prefix)); + pi.packageName, targetPkg, targetUid, grantUri); perm.grantModes(modeFlags, owner); } - void grantUriPermissionLocked(int callingUid, String targetPkg, Uri uri, + void grantUriPermissionLocked(int callingUid, String targetPkg, GrantUri grantUri, final int modeFlags, UriPermissionOwner owner) { if (targetPkg == null) { throw new NullPointerException("targetPkg"); } - int targetUid = checkGrantUriPermissionLocked(callingUid, targetPkg, uri, modeFlags, -1); + int targetUid = checkGrantUriPermissionLocked(callingUid, targetPkg, grantUri, modeFlags, + -1); if (targetUid < 0) { return; } - grantUriPermissionUncheckedLocked(targetUid, targetPkg, uri, modeFlags, owner); + grantUriPermissionUncheckedLocked(targetUid, targetPkg, grantUri, modeFlags, + owner); } - static class NeededUriGrants extends ArrayList<Uri> { + static class NeededUriGrants extends ArrayList<GrantUri> { final String targetPkg; final int targetUid; final int flags; @@ -6369,13 +6390,14 @@ public final class ActivityManagerService extends ActivityManagerNative } if (data != null) { - int targetUid = checkGrantUriPermissionLocked(callingUid, targetPkg, data, - mode, needed != null ? needed.targetUid : -1); + GrantUri grantUri = GrantUri.resolve(UserHandle.getUserId(callingUid), data); + int targetUid = checkGrantUriPermissionLocked(callingUid, targetPkg, grantUri, mode, + needed != null ? needed.targetUid : -1); if (targetUid > 0) { if (needed == null) { needed = new NeededUriGrants(targetPkg, targetUid, mode); } - needed.add(data); + needed.add(grantUri); } } if (clip != null) { @@ -6383,13 +6405,14 @@ public final class ActivityManagerService extends ActivityManagerNative Uri uri = clip.getItemAt(i).getUri(); if (uri != null) { int targetUid = -1; - targetUid = checkGrantUriPermissionLocked(callingUid, targetPkg, uri, - mode, needed != null ? needed.targetUid : -1); + GrantUri grantUri = GrantUri.resolve(UserHandle.getUserId(callingUid), uri); + targetUid = checkGrantUriPermissionLocked(callingUid, targetPkg, grantUri, mode, + needed != null ? needed.targetUid : -1); if (targetUid > 0) { if (needed == null) { needed = new NeededUriGrants(targetPkg, targetUid, mode); } - needed.add(uri); + needed.add(grantUri); } } else { Intent clipIntent = clip.getItemAt(i).getIntent(); @@ -6414,8 +6437,9 @@ public final class ActivityManagerService extends ActivityManagerNative UriPermissionOwner owner) { if (needed != null) { for (int i=0; i<needed.size(); i++) { + GrantUri grantUri = needed.get(i); grantUriPermissionUncheckedLocked(needed.targetUid, needed.targetPkg, - needed.get(i), needed.flags, owner); + grantUri, needed.flags, owner); } } } @@ -6432,20 +6456,21 @@ public final class ActivityManagerService extends ActivityManagerNative } @Override - public void grantUriPermission(IApplicationThread caller, String targetPkg, - Uri uri, final int modeFlags) { + public void grantUriPermission(IApplicationThread caller, String targetPkg, Uri uri, + final int modeFlags, int userId) { enforceNotIsolatedCaller("grantUriPermission"); + GrantUri grantUri = new GrantUri(userId, uri, false); synchronized(this) { final ProcessRecord r = getRecordForAppLocked(caller); if (r == null) { throw new SecurityException("Unable to find app for caller " + caller - + " when granting permission to uri " + uri); + + " when granting permission to uri " + grantUri); } if (targetPkg == null) { throw new IllegalArgumentException("null target"); } - if (uri == null) { + if (grantUri == null) { throw new IllegalArgumentException("null uri"); } @@ -6454,7 +6479,7 @@ public final class ActivityManagerService extends ActivityManagerNative | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION); - grantUriPermissionLocked(r.uid, targetPkg, uri, modeFlags, null); + grantUriPermissionLocked(r.uid, targetPkg, grantUri, modeFlags, null); } } @@ -6474,24 +6499,25 @@ public final class ActivityManagerService extends ActivityManagerNative } } - private void revokeUriPermissionLocked(int callingUid, Uri uri, final int modeFlags) { - if (DEBUG_URI_PERMISSION) Slog.v(TAG, "Revoking all granted permissions to " + uri); + private void revokeUriPermissionLocked(int callingUid, GrantUri grantUri, final int modeFlags) { + if (DEBUG_URI_PERMISSION) Slog.v(TAG, "Revoking all granted permissions to " + grantUri); final IPackageManager pm = AppGlobals.getPackageManager(); - final String authority = uri.getAuthority(); - final ProviderInfo pi = getProviderInfoLocked(authority, UserHandle.getUserId(callingUid)); + final String authority = grantUri.uri.getAuthority(); + final ProviderInfo pi = getProviderInfoLocked(authority, grantUri.sourceUserId); if (pi == null) { - Slog.w(TAG, "No content provider found for permission revoke: " + uri.toSafeString()); + Slog.w(TAG, "No content provider found for permission revoke: " + + grantUri.toSafeString()); return; } // Does the caller have this permission on the URI? - if (!checkHoldingPermissionsLocked(pm, pi, uri, callingUid, modeFlags)) { + if (!checkHoldingPermissionsLocked(pm, pi, grantUri, callingUid, modeFlags)) { // Right now, if you are not the original owner of the permission, // you are not allowed to revoke it. //if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) { throw new SecurityException("Uid " + callingUid - + " does not have permission to uri " + uri); + + " does not have permission to uri " + grantUri); //} } @@ -6505,7 +6531,8 @@ public final class ActivityManagerService extends ActivityManagerNative for (Iterator<UriPermission> it = perms.values().iterator(); it.hasNext();) { final UriPermission perm = it.next(); - if (perm.uri.uri.isPathPrefixMatch(uri)) { + if (perm.uri.sourceUserId == grantUri.sourceUserId + && perm.uri.uri.isPathPrefixMatch(grantUri.uri)) { if (DEBUG_URI_PERMISSION) Slog.v(TAG, "Revoking " + perm.targetUid + " permission to " + perm.uri); @@ -6530,8 +6557,8 @@ public final class ActivityManagerService extends ActivityManagerNative } @Override - public void revokeUriPermission(IApplicationThread caller, Uri uri, - final int modeFlags) { + public void revokeUriPermission(IApplicationThread caller, Uri uri, final int modeFlags, + int userId) { enforceNotIsolatedCaller("revokeUriPermission"); synchronized(this) { final ProcessRecord r = getRecordForAppLocked(caller); @@ -6551,14 +6578,14 @@ public final class ActivityManagerService extends ActivityManagerNative final IPackageManager pm = AppGlobals.getPackageManager(); final String authority = uri.getAuthority(); - final ProviderInfo pi = getProviderInfoLocked(authority, r.userId); + final ProviderInfo pi = getProviderInfoLocked(authority, userId); if (pi == null) { Slog.w(TAG, "No content provider found for permission revoke: " + uri.toSafeString()); return; } - revokeUriPermissionLocked(r.uid, uri, modeFlags); + revokeUriPermissionLocked(r.uid, new GrantUri(userId, uri, false), modeFlags); } } @@ -6628,8 +6655,8 @@ public final class ActivityManagerService extends ActivityManagerNative } @Override - public void grantUriPermissionFromOwner(IBinder token, int fromUid, String targetPkg, - Uri uri, final int modeFlags) { + public void grantUriPermissionFromOwner(IBinder token, int fromUid, String targetPkg, Uri uri, + final int modeFlags, int userId) { synchronized(this) { UriPermissionOwner owner = UriPermissionOwner.fromExternalToken(token); if (owner == null) { @@ -6649,12 +6676,13 @@ public final class ActivityManagerService extends ActivityManagerNative throw new IllegalArgumentException("null uri"); } - grantUriPermissionLocked(fromUid, targetPkg, uri, modeFlags, owner); + grantUriPermissionLocked(fromUid, targetPkg, new GrantUri(userId, uri, false), + modeFlags, owner); } } @Override - public void revokeUriPermissionFromOwner(IBinder token, Uri uri, int mode) { + public void revokeUriPermissionFromOwner(IBinder token, Uri uri, int mode, int userId) { synchronized(this) { UriPermissionOwner owner = UriPermissionOwner.fromExternalToken(token); if (owner == null) { @@ -6664,7 +6692,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (uri == null) { owner.removeUriPermissionsLocked(mode); } else { - owner.removeUriPermissionLocked(uri, mode); + owner.removeUriPermissionLocked(new GrantUri(userId, uri, false), mode); } } } @@ -6703,7 +6731,8 @@ public final class ActivityManagerService extends ActivityManagerNative out.startTag(null, TAG_URI_GRANTS); for (UriPermission.Snapshot perm : persist) { out.startTag(null, TAG_URI_GRANT); - writeIntAttribute(out, ATTR_USER_HANDLE, perm.userHandle); + writeIntAttribute(out, ATTR_SOURCE_USER_ID, perm.uri.sourceUserId); + writeIntAttribute(out, ATTR_TARGET_USER_ID, perm.targetUserId); out.attribute(null, ATTR_SOURCE_PKG, perm.sourcePkg); out.attribute(null, ATTR_TARGET_PKG, perm.targetPkg); out.attribute(null, ATTR_URI, String.valueOf(perm.uri.uri)); @@ -6739,7 +6768,18 @@ public final class ActivityManagerService extends ActivityManagerNative final String tag = in.getName(); if (type == START_TAG) { if (TAG_URI_GRANT.equals(tag)) { - final int userHandle = readIntAttribute(in, ATTR_USER_HANDLE); + final int sourceUserId; + final int targetUserId; + final int userHandle = readIntAttribute(in, + ATTR_USER_HANDLE, UserHandle.USER_NULL); + if (userHandle != UserHandle.USER_NULL) { + // For backwards compatibility. + sourceUserId = userHandle; + targetUserId = userHandle; + } else { + sourceUserId = readIntAttribute(in, ATTR_SOURCE_USER_ID); + targetUserId = readIntAttribute(in, ATTR_TARGET_USER_ID); + } final String sourcePkg = in.getAttributeValue(null, ATTR_SOURCE_PKG); final String targetPkg = in.getAttributeValue(null, ATTR_TARGET_PKG); final Uri uri = Uri.parse(in.getAttributeValue(null, ATTR_URI)); @@ -6749,17 +6789,18 @@ public final class ActivityManagerService extends ActivityManagerNative // Sanity check that provider still belongs to source package final ProviderInfo pi = getProviderInfoLocked( - uri.getAuthority(), userHandle); + uri.getAuthority(), sourceUserId); if (pi != null && sourcePkg.equals(pi.packageName)) { int targetUid = -1; try { targetUid = AppGlobals.getPackageManager() - .getPackageUid(targetPkg, userHandle); + .getPackageUid(targetPkg, targetUserId); } catch (RemoteException e) { } if (targetUid != -1) { final UriPermission perm = findOrCreateUriPermissionLocked( - sourcePkg, targetPkg, targetUid, new GrantUri(uri, prefix)); + sourcePkg, targetPkg, targetUid, + new GrantUri(sourceUserId, uri, prefix)); perm.initPersistedModes(modeFlags, createdTime); } } else { @@ -6781,7 +6822,7 @@ public final class ActivityManagerService extends ActivityManagerNative } @Override - public void takePersistableUriPermission(Uri uri, final int modeFlags) { + public void takePersistableUriPermission(Uri uri, final int modeFlags, int userId) { enforceNotIsolatedCaller("takePersistableUriPermission"); Preconditions.checkFlagsArgument(modeFlags, @@ -6790,9 +6831,12 @@ public final class ActivityManagerService extends ActivityManagerNative synchronized (this) { final int callingUid = Binder.getCallingUid(); boolean persistChanged = false; + GrantUri grantUri = new GrantUri(userId, uri, false); - UriPermission exactPerm = findUriPermissionLocked(callingUid, new GrantUri(uri, false)); - UriPermission prefixPerm = findUriPermissionLocked(callingUid, new GrantUri(uri, true)); + UriPermission exactPerm = findUriPermissionLocked(callingUid, + new GrantUri(userId, uri, false)); + UriPermission prefixPerm = findUriPermissionLocked(callingUid, + new GrantUri(userId, uri, true)); final boolean exactValid = (exactPerm != null) && ((modeFlags & exactPerm.persistableModeFlags) == modeFlags); @@ -6801,7 +6845,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (!(exactValid || prefixValid)) { throw new SecurityException("No persistable permission grants found for UID " - + callingUid + " and Uri " + uri.toSafeString()); + + callingUid + " and Uri " + grantUri.toSafeString()); } if (exactValid) { @@ -6820,7 +6864,7 @@ public final class ActivityManagerService extends ActivityManagerNative } @Override - public void releasePersistableUriPermission(Uri uri, final int modeFlags) { + public void releasePersistableUriPermission(Uri uri, final int modeFlags, int userId) { enforceNotIsolatedCaller("releasePersistableUriPermission"); Preconditions.checkFlagsArgument(modeFlags, @@ -6830,8 +6874,10 @@ public final class ActivityManagerService extends ActivityManagerNative final int callingUid = Binder.getCallingUid(); boolean persistChanged = false; - UriPermission exactPerm = findUriPermissionLocked(callingUid, new GrantUri(uri, false)); - UriPermission prefixPerm = findUriPermissionLocked(callingUid, new GrantUri(uri, true)); + UriPermission exactPerm = findUriPermissionLocked(callingUid, + new GrantUri(userId, uri, false)); + UriPermission prefixPerm = findUriPermissionLocked(callingUid, + new GrantUri(userId, uri, true)); if (exactPerm == null && prefixPerm == null) { throw new SecurityException("No permission grants found for UID " + callingUid + " and Uri " + uri.toSafeString()); @@ -7676,9 +7722,25 @@ public final class ActivityManagerService extends ActivityManagerNative * in {@link ContentProvider}. */ private final String checkContentProviderPermissionLocked( - ProviderInfo cpi, ProcessRecord r) { + ProviderInfo cpi, ProcessRecord r, int userId) { final int callingPid = (r != null) ? r.pid : Binder.getCallingPid(); final int callingUid = (r != null) ? r.uid : Binder.getCallingUid(); + final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.get(callingUid); + // Looking for cross-user grants before to enforce the typical cross-users permissions + if (userId != UserHandle.getUserId(callingUid)) { + if (perms != null) { + for (GrantUri grantUri : perms.keySet()) { + if (grantUri.sourceUserId == userId) { + String authority = grantUri.uri.getAuthority(); + if (authority.equals(cpi.authority)) { + return null; + } + } + } + } + } + userId = handleIncomingUser(callingPid, callingUid, userId, + false, true, "checkContentProviderPermissionLocked", null); if (checkComponentPermission(cpi.readPermission, callingPid, callingUid, cpi.applicationInfo.uid, cpi.exported) == PackageManager.PERMISSION_GRANTED) { @@ -7709,10 +7771,9 @@ public final class ActivityManagerService extends ActivityManagerNative } } - final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.get(callingUid); if (perms != null) { - for (GrantUri uri : perms.keySet()) { - if (uri.uri.getAuthority().equals(cpi.authority)) { + for (GrantUri grantUri : perms.keySet()) { + if (grantUri.uri.getAuthority().equals(cpi.authority)) { return null; } } @@ -7820,7 +7881,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (providerRunning) { cpi = cpr.info; String msg; - if ((msg=checkContentProviderPermissionLocked(cpi, r)) != null) { + if ((msg=checkContentProviderPermissionLocked(cpi, r, userId)) != null) { throw new SecurityException(msg); } @@ -7908,7 +7969,7 @@ public final class ActivityManagerService extends ActivityManagerNative cpi.applicationInfo = getAppInfoForUser(cpi.applicationInfo, userId); String msg; - if ((msg=checkContentProviderPermissionLocked(cpi, r)) != null) { + if ((msg=checkContentProviderPermissionLocked(cpi, r, userId)) != null) { throw new SecurityException(msg); } @@ -8074,6 +8135,7 @@ public final class ActivityManagerService extends ActivityManagerNative return cpr != null ? cpr.newHolder(conn) : null; } + @Override public final ContentProviderHolder getContentProvider( IApplicationThread caller, String name, int userId, boolean stable) { enforceNotIsolatedCaller("getContentProvider"); @@ -8083,9 +8145,8 @@ public final class ActivityManagerService extends ActivityManagerNative Slog.w(TAG, msg); throw new SecurityException(msg); } - - userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId, - false, true, "getContentProvider", null); + // The incoming user check is now handled in checkContentProviderPermissionLocked() to deal + // with cross-user grant. return getContentProviderImpl(caller, name, null, stable, userId); } diff --git a/services/core/java/com/android/server/am/UriPermission.java b/services/core/java/com/android/server/am/UriPermission.java index 4970b8d..284086d 100644 --- a/services/core/java/com/android/server/am/UriPermission.java +++ b/services/core/java/com/android/server/am/UriPermission.java @@ -44,7 +44,7 @@ final class UriPermission { public static final int STRENGTH_GLOBAL = 2; public static final int STRENGTH_PERSISTABLE = 3; - final int userHandle; + final int targetUserId; final String sourcePkg; final String targetPkg; @@ -86,7 +86,7 @@ final class UriPermission { private String stringName; UriPermission(String sourcePkg, String targetPkg, int targetUid, GrantUri uri) { - this.userHandle = UserHandle.getUserId(targetUid); + this.targetUserId = UserHandle.getUserId(targetUid); this.sourcePkg = sourcePkg; this.targetPkg = targetPkg; this.targetUid = targetUid; @@ -307,7 +307,7 @@ final class UriPermission { void dump(PrintWriter pw, String prefix) { pw.print(prefix); - pw.print("userHandle=" + userHandle); + pw.print("targetUserId=" + targetUserId); pw.print(" sourcePkg=" + sourcePkg); pw.println(" targetPkg=" + targetPkg); @@ -352,7 +352,7 @@ final class UriPermission { * {@link UriPermission#persistedModeFlags} state. */ public static class Snapshot { - final int userHandle; + final int targetUserId; final String sourcePkg; final String targetPkg; final GrantUri uri; @@ -360,7 +360,7 @@ final class UriPermission { final long persistedCreateTime; private Snapshot(UriPermission perm) { - this.userHandle = perm.userHandle; + this.targetUserId = perm.targetUserId; this.sourcePkg = perm.sourcePkg; this.targetPkg = perm.targetPkg; this.uri = perm.uri; diff --git a/services/core/java/com/android/server/am/UriPermissionOwner.java b/services/core/java/com/android/server/am/UriPermissionOwner.java index 65d7047..ae83940 100644 --- a/services/core/java/com/android/server/am/UriPermissionOwner.java +++ b/services/core/java/com/android/server/am/UriPermissionOwner.java @@ -70,13 +70,13 @@ final class UriPermissionOwner { removeUriPermissionLocked(null, mode); } - void removeUriPermissionLocked(Uri uri, int mode) { + void removeUriPermissionLocked(ActivityManagerService.GrantUri grantUri, int mode) { if ((mode & Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0 && mReadPerms != null) { Iterator<UriPermission> it = mReadPerms.iterator(); while (it.hasNext()) { UriPermission perm = it.next(); - if (uri == null || uri.equals(perm.uri)) { + if (grantUri == null || grantUri.equals(perm.uri)) { perm.removeReadOwner(this); service.removeUriPermissionIfNeededLocked(perm); it.remove(); @@ -91,7 +91,7 @@ final class UriPermissionOwner { Iterator<UriPermission> it = mWritePerms.iterator(); while (it.hasNext()) { UriPermission perm = it.next(); - if (uri == null || uri.equals(perm.uri)) { + if (grantUri == null || grantUri.equals(perm.uri)) { perm.removeWriteOwner(this); service.removeUriPermissionIfNeededLocked(perm); it.remove(); diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java index f47d66d..15e3e89 100644 --- a/services/core/java/com/android/server/clipboard/ClipboardService.java +++ b/services/core/java/com/android/server/clipboard/ClipboardService.java @@ -23,6 +23,7 @@ import android.app.IActivityManager; import android.content.BroadcastReceiver; import android.content.ClipData; import android.content.ClipDescription; +import android.content.ContentProvider; import android.content.IClipboard; import android.content.IOnPrimaryClipChangedListener; import android.content.Context; @@ -255,7 +256,8 @@ public class ClipboardService extends IClipboard.Stub { long ident = Binder.clearCallingIdentity(); try { // This will throw SecurityException for us. - mAm.checkGrantUriPermission(uid, null, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION); + mAm.checkGrantUriPermission(uid, null, ContentProvider.getUriWithoutUserId(uri), + Intent.FLAG_GRANT_READ_URI_PERMISSION, resolveUserId(uri, uid)); } catch (RemoteException e) { } finally { Binder.restoreCallingIdentity(ident); @@ -282,8 +284,10 @@ public class ClipboardService extends IClipboard.Stub { private final void grantUriLocked(Uri uri, String pkg) { long ident = Binder.clearCallingIdentity(); try { - mAm.grantUriPermissionFromOwner(mPermissionOwner, Process.myUid(), pkg, uri, - Intent.FLAG_GRANT_READ_URI_PERMISSION); + mAm.grantUriPermissionFromOwner(mPermissionOwner, Process.myUid(), pkg, + ContentProvider.getUriWithoutUserId(uri), + Intent.FLAG_GRANT_READ_URI_PERMISSION, + resolveUserId(uri, Process.myUid())); } catch (RemoteException e) { } finally { Binder.restoreCallingIdentity(ident); @@ -331,9 +335,10 @@ public class ClipboardService extends IClipboard.Stub { private final void revokeUriLocked(Uri uri) { long ident = Binder.clearCallingIdentity(); try { - mAm.revokeUriPermissionFromOwner(mPermissionOwner, uri, - Intent.FLAG_GRANT_READ_URI_PERMISSION - | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); + mAm.revokeUriPermissionFromOwner(mPermissionOwner, + ContentProvider.getUriWithoutUserId(uri), + Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION, + resolveUserId(uri, Process.myUid())); } catch (RemoteException e) { } finally { Binder.restoreCallingIdentity(ident); @@ -361,4 +366,8 @@ public class ClipboardService extends IClipboard.Stub { revokeItemLocked(clipboard.primaryClip.getItemAt(i)); } } + + private final int resolveUserId(Uri uri, int uid) { + return ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(uid)); + } } |