summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicolas Prevot <nprevot@google.com>2014-07-24 19:59:48 +0000
committerAndroid Git Automerger <android-git-automerger@android.com>2014-07-24 19:59:48 +0000
commitb593e79436593b5b73416c65743c86118d03a6bc (patch)
treec23e6b4e6d92e8f3e4781d3fa26306596b2d69ba
parent811dce520d7e1ef4076156472c316152d7f4cde7 (diff)
parentf2e791fcdd9b86738c1599b4da3f2301bffddff2 (diff)
downloadframeworks_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.txt1
-rw-r--r--core/java/android/app/ActivityManagerNative.java11
-rw-r--r--core/java/android/app/IActivityManager.java2
-rw-r--r--core/java/android/content/ClipData.java20
-rw-r--r--core/java/android/os/UserManager.java12
-rwxr-xr-xservices/core/java/com/android/server/am/ActivityManagerService.java22
-rw-r--r--services/core/java/com/android/server/clipboard/ClipboardService.java129
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));
- }
}