diff options
author | Nicolas Prevot <nprevot@google.com> | 2014-07-24 19:59:48 +0000 |
---|---|---|
committer | Android Git Automerger <android-git-automerger@android.com> | 2014-07-24 19:59:48 +0000 |
commit | b593e79436593b5b73416c65743c86118d03a6bc (patch) | |
tree | c23e6b4e6d92e8f3e4781d3fa26306596b2d69ba | |
parent | 811dce520d7e1ef4076156472c316152d7f4cde7 (diff) | |
parent | f2e791fcdd9b86738c1599b4da3f2301bffddff2 (diff) | |
download | frameworks_base-b593e79436593b5b73416c65743c86118d03a6bc.zip frameworks_base-b593e79436593b5b73416c65743c86118d03a6bc.tar.gz frameworks_base-b593e79436593b5b73416c65743c86118d03a6bc.tar.bz2 |
am 498694c6: am 1b4a211d: am 4fe8fe2b: Merge "Making the clipboard work across users." into lmp-dev
* commit '498694c67112923f85f3572c4b7ad093283d1f68':
Making the clipboard work across users.
-rw-r--r-- | api/current.txt | 1 | ||||
-rw-r--r-- | core/java/android/app/ActivityManagerNative.java | 11 | ||||
-rw-r--r-- | core/java/android/app/IActivityManager.java | 2 | ||||
-rw-r--r-- | core/java/android/content/ClipData.java | 20 | ||||
-rw-r--r-- | core/java/android/os/UserManager.java | 12 | ||||
-rwxr-xr-x | services/core/java/com/android/server/am/ActivityManagerService.java | 22 | ||||
-rw-r--r-- | services/core/java/com/android/server/clipboard/ClipboardService.java | 129 |
7 files changed, 147 insertions, 50 deletions
diff --git a/api/current.txt b/api/current.txt index 61b0cb2..c2ba4a3 100644 --- a/api/current.txt +++ b/api/current.txt @@ -22733,6 +22733,7 @@ package android.os { field public static final java.lang.String DISALLOW_CONFIG_VPN = "no_config_vpn"; field public static final java.lang.String DISALLOW_CONFIG_WIFI = "no_config_wifi"; field public static final java.lang.String DISALLOW_CREATE_WINDOWS = "no_create_windows"; + field public static final java.lang.String DISALLOW_CROSS_PROFILE_COPY_PASTE = "no_cross_profile_copy_paste"; field public static final java.lang.String DISALLOW_DEBUGGING_FEATURES = "no_debugging_features"; field public static final java.lang.String DISALLOW_FACTORY_RESET = "no_factory_reset"; field public static final java.lang.String DISALLOW_INSTALL_APPS = "no_install_apps"; diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index 342155d..318a520 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -1661,8 +1661,10 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM String targetPkg = data.readString(); Uri uri = Uri.CREATOR.createFromParcel(data); int mode = data.readInt(); - int userId = data.readInt(); - grantUriPermissionFromOwner(owner, fromUid, targetPkg, uri, mode, userId); + int sourceUserId = data.readInt(); + int targetUserId = data.readInt(); + grantUriPermissionFromOwner(owner, fromUid, targetPkg, uri, mode, sourceUserId, + targetUserId); reply.writeNoException(); return true; } @@ -4343,7 +4345,7 @@ class ActivityManagerProxy implements IActivityManager } public void grantUriPermissionFromOwner(IBinder owner, int fromUid, String targetPkg, - Uri uri, int mode, int userId) throws RemoteException { + Uri uri, int mode, int sourceUserId, int targetUserId) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); @@ -4352,7 +4354,8 @@ class ActivityManagerProxy implements IActivityManager data.writeString(targetPkg); uri.writeToParcel(data, 0); data.writeInt(mode); - data.writeInt(userId); + data.writeInt(sourceUserId); + data.writeInt(targetUserId); mRemote.transact(GRANT_URI_PERMISSION_TRANSACTION, data, reply, 0); reply.readException(); data.recycle(); diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index cc13a3b..53c1408 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -332,7 +332,7 @@ 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, int userId) throws RemoteException; + Uri uri, int mode, int sourceUserId, int targetUserId) throws RemoteException; public void revokeUriPermissionFromOwner(IBinder owner, Uri uri, int mode, int userId) throws RemoteException; diff --git a/core/java/android/content/ClipData.java b/core/java/android/content/ClipData.java index b44abf9..7a16ef8 100644 --- a/core/java/android/content/ClipData.java +++ b/core/java/android/content/ClipData.java @@ -828,6 +828,26 @@ public class ClipData implements Parcelable { } } + /** + * Only fixing the data field of the intents + * @hide + */ + public void fixUrisLight(int contentUserHint) { + final int size = mItems.size(); + for (int i = 0; i < size; i++) { + final Item item = mItems.get(i); + if (item.mIntent != null) { + Uri data = item.mIntent.getData(); + if (data != null) { + item.mIntent.setData(maybeAddUserId(data, contentUserHint)); + } + } + if (item.mUri != null) { + item.mUri = maybeAddUserId(item.mUri, contentUserHint); + } + } + } + @Override public String toString() { StringBuilder b = new StringBuilder(128); diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index d3aee50..45edf28 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -310,6 +310,18 @@ public class UserManager { */ public static final String DISALLOW_CREATE_WINDOWS = "no_create_windows"; + /** + * Key for user restrictions. Specifies if what is copied in the clipboard of this profile can + * be pasted in related profiles. Does not restrict if the clipboard of related profiles can be + * pasted in this profile. + * The default value is <code>false</code>. + * <p/> + * Type: Boolean + * @see #setUserRestrictions(Bundle) + * @see #getUserRestrictions() + */ + public static final String DISALLOW_CROSS_PROFILE_COPY_PASTE = "no_cross_profile_copy_paste"; + /** @hide */ public static final int PIN_VERIFICATION_FAILED_INCORRECT = -3; /** @hide */ diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index ab8f2f5..c0ac023 100755 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -6563,13 +6563,20 @@ public final class ActivityManagerService extends ActivityManagerNative } void grantUriPermissionLocked(int callingUid, String targetPkg, GrantUri grantUri, - final int modeFlags, UriPermissionOwner owner) { + final int modeFlags, UriPermissionOwner owner, int targetUserId) { if (targetPkg == null) { throw new NullPointerException("targetPkg"); } + int targetUid; + final IPackageManager pm = AppGlobals.getPackageManager(); + try { + targetUid = pm.getPackageUid(targetPkg, targetUserId); + } catch (RemoteException ex) { + return; + } - int targetUid = checkGrantUriPermissionLocked(callingUid, targetPkg, grantUri, modeFlags, - -1); + targetUid = checkGrantUriPermissionLocked(callingUid, targetPkg, grantUri, modeFlags, + targetUid); if (targetUid < 0) { return; } @@ -6720,7 +6727,8 @@ public final class ActivityManagerService extends ActivityManagerNative | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION); - grantUriPermissionLocked(r.uid, targetPkg, grantUri, modeFlags, null); + grantUriPermissionLocked(r.uid, targetPkg, grantUri, modeFlags, null, + UserHandle.getUserId(r.uid)); } } @@ -6897,7 +6905,7 @@ public final class ActivityManagerService extends ActivityManagerNative @Override public void grantUriPermissionFromOwner(IBinder token, int fromUid, String targetPkg, Uri uri, - final int modeFlags, int userId) { + final int modeFlags, int sourceUserId, int targetUserId) { synchronized(this) { UriPermissionOwner owner = UriPermissionOwner.fromExternalToken(token); if (owner == null) { @@ -6917,8 +6925,8 @@ public final class ActivityManagerService extends ActivityManagerNative throw new IllegalArgumentException("null uri"); } - grantUriPermissionLocked(fromUid, targetPkg, new GrantUri(userId, uri, false), - modeFlags, owner); + grantUriPermissionLocked(fromUid, targetPkg, new GrantUri(sourceUserId, uri, false), + modeFlags, owner, targetUserId); } } diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java index 15e3e89..1c26846 100644 --- a/services/core/java/com/android/server/clipboard/ClipboardService.java +++ b/services/core/java/com/android/server/clipboard/ClipboardService.java @@ -32,18 +32,23 @@ import android.content.IntentFilter; import android.content.pm.IPackageManager; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.content.pm.UserInfo; import android.net.Uri; import android.os.Binder; import android.os.IBinder; +import android.os.IUserManager; import android.os.Parcel; import android.os.Process; import android.os.RemoteCallbackList; import android.os.RemoteException; +import android.os.ServiceManager; import android.os.UserHandle; +import android.os.UserManager; import android.util.Slog; import android.util.SparseArray; import java.util.HashSet; +import java.util.List; /** * Implementation of the clipboard for copy and paste. @@ -54,6 +59,7 @@ public class ClipboardService extends IClipboard.Stub { private final Context mContext; private final IActivityManager mAm; + private final IUserManager mUm; private final PackageManager mPm; private final AppOpsManager mAppOps; private final IBinder mPermissionOwner; @@ -92,6 +98,7 @@ public class ClipboardService extends IClipboard.Stub { mContext = context; mAm = ActivityManagerNative.getDefault(); mPm = context.getPackageManager(); + mUm = (IUserManager) ServiceManager.getService(Context.USER_SERVICE); mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE); IBinder permOwner = null; try { @@ -161,30 +168,79 @@ public class ClipboardService extends IClipboard.Stub { return; } checkDataOwnerLocked(clip, callingUid); - clearActiveOwnersLocked(); - PerUserClipboard clipboard = getClipboard(); - clipboard.primaryClip = clip; - final long ident = Binder.clearCallingIdentity(); - final int n = clipboard.primaryClipListeners.beginBroadcast(); - try { - for (int i = 0; i < n; i++) { + final int userId = UserHandle.getUserId(callingUid); + PerUserClipboard clipboard = getClipboard(userId); + revokeUris(clipboard); + setPrimaryClipInternal(clipboard, clip); + List<UserInfo> related = getRelatedProfiles(userId); + if (related != null) { + int size = related.size(); + if (size > 1) { // Related profiles list include the current profile. + boolean canCopy = false; try { - ListenerInfo li = (ListenerInfo) - clipboard.primaryClipListeners.getBroadcastCookie(i); - if (mAppOps.checkOpNoThrow(AppOpsManager.OP_READ_CLIPBOARD, li.mUid, - li.mPackageName) == AppOpsManager.MODE_ALLOWED) { - clipboard.primaryClipListeners.getBroadcastItem(i) - .dispatchPrimaryClipChanged(); - } + canCopy = !mUm.getUserRestrictions(userId).getBoolean( + UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE); } catch (RemoteException e) { - // The RemoteCallbackList will take care of removing - // the dead object for us. + Slog.e(TAG, "Remote Exception calling UserManager: " + e); + } + // Copy clip data to related users if allowed. If disallowed, then remove + // primary clip in related users to prevent pasting stale content. + if (!canCopy) { + clip = null; + } else { + clip.fixUrisLight(userId); + } + for (int i = 0; i < size; i++) { + int id = related.get(i).id; + if (id != userId) { + setPrimaryClipInternal(getClipboard(id), clip); + } + } + } + } + } + } + + List<UserInfo> getRelatedProfiles(int userId) { + final List<UserInfo> related; + final long origId = Binder.clearCallingIdentity(); + try { + related = mUm.getProfiles(userId, true); + } catch (RemoteException e) { + Slog.e(TAG, "Remote Exception calling UserManager: " + e); + return null; + } finally{ + Binder.restoreCallingIdentity(origId); + } + return related; + } + + void setPrimaryClipInternal(PerUserClipboard clipboard, ClipData clip) { + clipboard.activePermissionOwners.clear(); + if (clip == null && clipboard.primaryClip == null) { + return; + } + clipboard.primaryClip = clip; + final long ident = Binder.clearCallingIdentity(); + final int n = clipboard.primaryClipListeners.beginBroadcast(); + try { + for (int i = 0; i < n; i++) { + try { + ListenerInfo li = (ListenerInfo) + clipboard.primaryClipListeners.getBroadcastCookie(i); + if (mAppOps.checkOpNoThrow(AppOpsManager.OP_READ_CLIPBOARD, li.mUid, + li.mPackageName) == AppOpsManager.MODE_ALLOWED) { + clipboard.primaryClipListeners.getBroadcastItem(i) + .dispatchPrimaryClipChanged(); } + } catch (RemoteException e) { + // The RemoteCallbackList will take care of removing + // the dead object for us. } - } finally { - clipboard.primaryClipListeners.finishBroadcast(); - Binder.restoreCallingIdentity(ident); } + } finally { + clipboard.primaryClipListeners.finishBroadcast(); + Binder.restoreCallingIdentity(ident); } } @@ -257,7 +313,8 @@ public class ClipboardService extends IClipboard.Stub { try { // This will throw SecurityException for us. mAm.checkGrantUriPermission(uid, null, ContentProvider.getUriWithoutUserId(uri), - Intent.FLAG_GRANT_READ_URI_PERMISSION, resolveUserId(uri, uid)); + Intent.FLAG_GRANT_READ_URI_PERMISSION, + ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(uid))); } catch (RemoteException e) { } finally { Binder.restoreCallingIdentity(ident); @@ -281,26 +338,26 @@ public class ClipboardService extends IClipboard.Stub { } } - private final void grantUriLocked(Uri uri, String pkg) { + private final void grantUriLocked(Uri uri, String pkg, int userId) { long ident = Binder.clearCallingIdentity(); try { + int sourceUserId = ContentProvider.getUserIdFromUri(uri, userId); + uri = ContentProvider.getUriWithoutUserId(uri); mAm.grantUriPermissionFromOwner(mPermissionOwner, Process.myUid(), pkg, - ContentProvider.getUriWithoutUserId(uri), - Intent.FLAG_GRANT_READ_URI_PERMISSION, - resolveUserId(uri, Process.myUid())); + uri, Intent.FLAG_GRANT_READ_URI_PERMISSION, sourceUserId, userId); } catch (RemoteException e) { } finally { Binder.restoreCallingIdentity(ident); } } - private final void grantItemLocked(ClipData.Item item, String pkg) { + private final void grantItemLocked(ClipData.Item item, String pkg, int userId) { if (item.getUri() != null) { - grantUriLocked(item.getUri(), pkg); + grantUriLocked(item.getUri(), pkg, userId); } Intent intent = item.getIntent(); if (intent != null && intent.getData() != null) { - grantUriLocked(intent.getData(), pkg); + grantUriLocked(intent.getData(), pkg, userId); } } @@ -326,19 +383,21 @@ public class ClipboardService extends IClipboard.Stub { if (clipboard.primaryClip != null && !clipboard.activePermissionOwners.contains(pkg)) { final int N = clipboard.primaryClip.getItemCount(); for (int i=0; i<N; i++) { - grantItemLocked(clipboard.primaryClip.getItemAt(i), pkg); + grantItemLocked(clipboard.primaryClip.getItemAt(i), pkg, UserHandle.getUserId(uid)); } clipboard.activePermissionOwners.add(pkg); } } private final void revokeUriLocked(Uri uri) { + int userId = ContentProvider.getUserIdFromUri(uri, + UserHandle.getUserId(Binder.getCallingUid())); long ident = Binder.clearCallingIdentity(); try { - mAm.revokeUriPermissionFromOwner(mPermissionOwner, - ContentProvider.getUriWithoutUserId(uri), + uri = ContentProvider.getUriWithoutUserId(uri); + mAm.revokeUriPermissionFromOwner(mPermissionOwner, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION, - resolveUserId(uri, Process.myUid())); + userId); } catch (RemoteException e) { } finally { Binder.restoreCallingIdentity(ident); @@ -355,9 +414,7 @@ public class ClipboardService extends IClipboard.Stub { } } - private final void clearActiveOwnersLocked() { - PerUserClipboard clipboard = getClipboard(); - clipboard.activePermissionOwners.clear(); + private final void revokeUris(PerUserClipboard clipboard) { if (clipboard.primaryClip == null) { return; } @@ -366,8 +423,4 @@ 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)); - } } |