summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author TreeHugger Robot <treehugger-gerrit@google.com> 2019-05-21 16:50:52 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2019-05-21 16:50:52 +0000
commit743288a029deba1df1e0d01eca5d5db9dd855fc5 (patch)
treec1e72a7a5b59bc22ee2b69fab7e6555cfb409209
parent376830178b8055930f7d4ca89702db17572199d1 (diff)
parent33f56060d57a0aca3693caedbc37b5dc94a11ef3 (diff)
Merge "Fix sysui's security issue of cross-user copy/paste" into qt-dev
-rw-r--r--core/java/android/content/ClipboardManager.java19
-rw-r--r--core/java/android/content/IClipboard.aidl17
-rw-r--r--core/java/android/widget/TextView.java31
-rw-r--r--services/core/java/com/android/server/clipboard/ClipboardService.java239
4 files changed, 219 insertions, 87 deletions
diff --git a/core/java/android/content/ClipboardManager.java b/core/java/android/content/ClipboardManager.java
index 8760efeafd8c..dc1c700f5d08 100644
--- a/core/java/android/content/ClipboardManager.java
+++ b/core/java/android/content/ClipboardManager.java
@@ -103,7 +103,7 @@ public class ClipboardManager extends android.text.ClipboardManager {
try {
Preconditions.checkNotNull(clip);
clip.prepareToLeaveProcess(true);
- mService.setPrimaryClip(clip, mContext.getOpPackageName());
+ mService.setPrimaryClip(clip, mContext.getOpPackageName(), mContext.getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -116,7 +116,7 @@ public class ClipboardManager extends android.text.ClipboardManager {
*/
public void clearPrimaryClip() {
try {
- mService.clearPrimaryClip(mContext.getOpPackageName());
+ mService.clearPrimaryClip(mContext.getOpPackageName(), mContext.getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -132,7 +132,7 @@ public class ClipboardManager extends android.text.ClipboardManager {
*/
public @Nullable ClipData getPrimaryClip() {
try {
- return mService.getPrimaryClip(mContext.getOpPackageName());
+ return mService.getPrimaryClip(mContext.getOpPackageName(), mContext.getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -149,7 +149,8 @@ public class ClipboardManager extends android.text.ClipboardManager {
*/
public @Nullable ClipDescription getPrimaryClipDescription() {
try {
- return mService.getPrimaryClipDescription(mContext.getOpPackageName());
+ return mService.getPrimaryClipDescription(mContext.getOpPackageName(),
+ mContext.getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -163,7 +164,7 @@ public class ClipboardManager extends android.text.ClipboardManager {
*/
public boolean hasPrimaryClip() {
try {
- return mService.hasPrimaryClip(mContext.getOpPackageName());
+ return mService.hasPrimaryClip(mContext.getOpPackageName(), mContext.getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -174,7 +175,8 @@ public class ClipboardManager extends android.text.ClipboardManager {
if (mPrimaryClipChangedListeners.isEmpty()) {
try {
mService.addPrimaryClipChangedListener(
- mPrimaryClipChangedServiceListener, mContext.getOpPackageName());
+ mPrimaryClipChangedServiceListener, mContext.getOpPackageName(),
+ mContext.getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -189,7 +191,8 @@ public class ClipboardManager extends android.text.ClipboardManager {
if (mPrimaryClipChangedListeners.isEmpty()) {
try {
mService.removePrimaryClipChangedListener(
- mPrimaryClipChangedServiceListener);
+ mPrimaryClipChangedServiceListener, mContext.getOpPackageName(),
+ mContext.getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -226,7 +229,7 @@ public class ClipboardManager extends android.text.ClipboardManager {
@Deprecated
public boolean hasText() {
try {
- return mService.hasClipboardText(mContext.getOpPackageName());
+ return mService.hasClipboardText(mContext.getOpPackageName(), mContext.getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/content/IClipboard.aidl b/core/java/android/content/IClipboard.aidl
index 135a4363ef21..0d5a46016f19 100644
--- a/core/java/android/content/IClipboard.aidl
+++ b/core/java/android/content/IClipboard.aidl
@@ -26,17 +26,18 @@ import android.content.IOnPrimaryClipChangedListener;
* {@hide}
*/
interface IClipboard {
- void setPrimaryClip(in ClipData clip, String callingPackage);
- void clearPrimaryClip(String callingPackage);
- ClipData getPrimaryClip(String pkg);
- ClipDescription getPrimaryClipDescription(String callingPackage);
- boolean hasPrimaryClip(String callingPackage);
+ void setPrimaryClip(in ClipData clip, String callingPackage, int userId);
+ void clearPrimaryClip(String callingPackage, int userId);
+ ClipData getPrimaryClip(String pkg, int userId);
+ ClipDescription getPrimaryClipDescription(String callingPackage, int userId);
+ boolean hasPrimaryClip(String callingPackage, int userId);
void addPrimaryClipChangedListener(in IOnPrimaryClipChangedListener listener,
- String callingPackage);
- void removePrimaryClipChangedListener(in IOnPrimaryClipChangedListener listener);
+ String callingPackage, int userId);
+ void removePrimaryClipChangedListener(in IOnPrimaryClipChangedListener listener,
+ String callingPackage, int userId);
/**
* Returns true if the clipboard contains text; false otherwise.
*/
- boolean hasClipboardText(String callingPackage);
+ boolean hasClipboardText(String callingPackage, int userId);
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 17c56c3f216a..a9e183ad5bf2 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -11244,13 +11244,23 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
@Nullable
final TextServicesManager getTextServicesManagerForUser() {
+ return getServiceManagerForUser("android", TextServicesManager.class);
+ }
+
+ @Nullable
+ final ClipboardManager getClipboardManagerForUser() {
+ return getServiceManagerForUser(getContext().getPackageName(), ClipboardManager.class);
+ }
+
+ @Nullable
+ final <T> T getServiceManagerForUser(String packageName, Class<T> managerClazz) {
if (mTextOperationUser == null) {
- return getContext().getSystemService(TextServicesManager.class);
+ return getContext().getSystemService(managerClazz);
}
try {
- return getContext().createPackageContextAsUser(
- "android", 0 /* flags */, mTextOperationUser)
- .getSystemService(TextServicesManager.class);
+ Context context = getContext().createPackageContextAsUser(
+ packageName, 0 /* flags */, mTextOperationUser);
+ return context.getSystemService(managerClazz);
} catch (PackageManager.NameNotFoundException e) {
return null;
}
@@ -12540,8 +12550,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
&& mEditor != null && mEditor.mKeyListener != null
&& getSelectionStart() >= 0
&& getSelectionEnd() >= 0
- && ((ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE))
- .hasPrimaryClip());
+ && getClipboardManagerForUser().hasPrimaryClip());
}
boolean canPasteAsPlainText() {
@@ -12549,9 +12558,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
return false;
}
- final ClipData clipData =
- ((ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE))
- .getPrimaryClip();
+ final ClipData clipData = getClipboardManagerForUser().getPrimaryClip();
final ClipDescription description = clipData.getDescription();
final boolean isPlainType = description.hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN);
final CharSequence text = clipData.getItemAt(0).getText();
@@ -12594,8 +12601,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
* Paste clipboard content between min and max positions.
*/
private void paste(int min, int max, boolean withFormatting) {
- ClipboardManager clipboard =
- (ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE);
+ ClipboardManager clipboard = getClipboardManagerForUser();
ClipData clip = clipboard.getPrimaryClip();
if (clip != null) {
boolean didFirst = false;
@@ -12638,8 +12644,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
@CheckResult
private boolean setPrimaryClip(ClipData clip) {
- ClipboardManager clipboard =
- (ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE);
+ ClipboardManager clipboard = getClipboardManagerForUser();
try {
clipboard.setPrimaryClip(clip);
} catch (Throwable t) {
diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java
index d28482ef82ab..af25ad56a2a7 100644
--- a/services/core/java/com/android/server/clipboard/ClipboardService.java
+++ b/services/core/java/com/android/server/clipboard/ClipboardService.java
@@ -16,11 +16,14 @@
package com.android.server.clipboard;
+import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
+
+import android.Manifest;
import android.annotation.Nullable;
-import android.app.ActivityManager;
+import android.annotation.UserIdInt;
+import android.app.ActivityManagerInternal;
import android.app.AppGlobals;
import android.app.AppOpsManager;
-import android.app.IActivityManager;
import android.app.IUriGrantsManager;
import android.app.KeyguardManager;
import android.app.UriGrantsManager;
@@ -145,6 +148,11 @@ class HostClipboardMonitor implements Runnable {
/**
* Implementation of the clipboard for copy and paste.
+ * <p>
+ * Caution: exception for clipboard data and isInternalSysWindowAppWithWindowFocus, any of data
+ * is accessed by userId or uid should be in * the try segment between
+ * Binder.clearCallingIdentity and Binder.restoreCallingIdentity.
+ * </p>
*/
public class ClipboardService extends SystemService {
@@ -152,7 +160,7 @@ public class ClipboardService extends SystemService {
private static final boolean IS_EMULATOR =
SystemProperties.getBoolean("ro.kernel.qemu", false);
- private final IActivityManager mAm;
+ private final ActivityManagerInternal mAmInternal;
private final IUriGrantsManager mUgm;
private final UriGrantsManagerInternal mUgmInternal;
private final WindowManagerInternal mWm;
@@ -173,7 +181,7 @@ public class ClipboardService extends SystemService {
public ClipboardService(Context context) {
super(context);
- mAm = ActivityManager.getService();
+ mAmInternal = LocalServices.getService(ActivityManagerInternal.class);
mUgm = UriGrantsManager.getService();
mUgmInternal = LocalServices.getService(UriGrantsManagerInternal.class);
mWm = LocalServices.getService(WindowManagerInternal.class);
@@ -244,6 +252,87 @@ public class ClipboardService extends SystemService {
}
}
+ /**
+ * To check if the application has granted the INTERNAL_SYSTEM_WINDOW permission and window
+ * focus.
+ * <p>
+ * All of applications granted INTERNAL_SYSTEM_WINDOW has the risk to leak clip information to
+ * the other user because INTERNAL_SYSTEM_WINDOW is signature level. i.e. platform key. Because
+ * some of applications have both of INTERNAL_SYSTEM_WINDOW and INTERACT_ACROSS_USERS_FULL at
+ * the same time, that means they show the same window to all of users.
+ * </p><p>
+ * Unfortunately, all of applications with INTERNAL_SYSTEM_WINDOW starts very early and then
+ * the real window show is belong to user 0 rather user X. The result of
+ * WindowManager.isUidFocused checking user X window is false.
+ * </p>
+ * @return true if the app granted INTERNAL_SYSTEM_WINDOW permission.
+ */
+ private boolean isInternalSysWindowAppWithWindowFocus(String callingPackage) {
+ // Shell can access the clipboard for testing purposes.
+ if (mPm.checkPermission(Manifest.permission.INTERNAL_SYSTEM_WINDOW,
+ callingPackage) == PackageManager.PERMISSION_GRANTED) {
+ if (mWm.isUidFocused(Binder.getCallingUid())) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * To get the validate current userId.
+ * <p>
+ * The intending userId needs to be validated by ActivityManagerInternal.handleIncomingUser.
+ * To check if the uid of the process have the permission to run as the userId.
+ * e.x. INTERACT_ACROSS_USERS_FULL or INTERACT_ACROSS_USERS permission granted.
+ * </p>
+ * <p>
+ * The application with the granted INTERNAL_SYSTEM_WINDOW permission should run as the output
+ * of ActivityManagerInternal.handleIncomingUser rather the userId of Binder.getCAllingUid().
+ * To use the userId of Binder.getCallingUid() is the root cause that leaks the information
+ * comes from user 0 to user X.
+ * </p>
+ *
+ * @param packageName the package name of the calling side
+ * @param userId the userId passed by the calling side
+ * @return return the intending userId that has been validated by ActivityManagerInternal.
+ */
+ @UserIdInt
+ private int getIntendingUserId(String packageName, @UserIdInt int userId) {
+ final int callingUid = Binder.getCallingUid();
+ final int callingUserId = UserHandle.getUserId(callingUid);
+ if (!UserManager.supportsMultipleUsers() || callingUserId == userId) {
+ return callingUserId;
+ }
+
+ int intendingUserId = callingUserId;
+ intendingUserId = mAmInternal.handleIncomingUser(Binder.getCallingPid(),
+ Binder.getCallingUid(), userId, false /* allow all */, ALLOW_FULL_ONLY,
+ "checkClipboardServiceCallingUser", packageName);
+
+ return intendingUserId;
+ }
+
+ /**
+ * To get the current running uid who is intend to run as.
+ * In ording to distinguish the nameing and reducing the confusing names, the client client
+ * side pass userId that is intend to run as,
+ * @return return IntentingUid = validated intenting userId +
+ * UserHandle.getAppId(Binder.getCallingUid())
+ */
+ private int getIntendingUid(String packageName, @UserIdInt int userId) {
+ return UserHandle.getUid(getIntendingUserId(packageName, userId),
+ UserHandle.getAppId(Binder.getCallingUid()));
+ }
+
+ /**
+ * To handle the difference between userId and intendingUserId, uid and intendingUid.
+ *
+ * userId means that comes from the calling side and should be validated by
+ * ActivityManagerInternal.handleIncomingUser.
+ * After validation of ActivityManagerInternal.handleIncomingUser, the userId is called
+ * 'intendingUserId' and the uid is called 'intendingUid'.
+ */
private class ClipboardImpl extends IClipboard.Stub {
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
@@ -260,92 +349,112 @@ public class ClipboardService extends SystemService {
}
@Override
- public void setPrimaryClip(ClipData clip, String callingPackage) {
+ public void setPrimaryClip(ClipData clip, String callingPackage, @UserIdInt int userId) {
synchronized (this) {
if (clip == null || clip.getItemCount() <= 0) {
throw new IllegalArgumentException("No items");
}
- final int callingUid = Binder.getCallingUid();
+ final int intendingUid = getIntendingUid(callingPackage, userId);
+ final int intendingUserId = UserHandle.getUserId(intendingUid);
if (!clipboardAccessAllowed(AppOpsManager.OP_WRITE_CLIPBOARD, callingPackage,
- callingUid)) {
+ intendingUid, intendingUserId)) {
return;
}
- checkDataOwnerLocked(clip, callingUid);
- setPrimaryClipInternal(clip, callingUid);
+ checkDataOwnerLocked(clip, intendingUid);
+ setPrimaryClipInternal(clip, intendingUid);
}
}
@Override
- public void clearPrimaryClip(String callingPackage) {
+ public void clearPrimaryClip(String callingPackage, @UserIdInt int userId) {
synchronized (this) {
- final int callingUid = Binder.getCallingUid();
+ final int intendingUid = getIntendingUid(callingPackage, userId);
+ final int intendingUserId = UserHandle.getUserId(intendingUid);
if (!clipboardAccessAllowed(AppOpsManager.OP_WRITE_CLIPBOARD, callingPackage,
- callingUid)) {
+ intendingUid, intendingUserId)) {
return;
}
- setPrimaryClipInternal(null, callingUid);
+ setPrimaryClipInternal(null, intendingUid);
}
}
@Override
- public ClipData getPrimaryClip(String pkg) {
+ public ClipData getPrimaryClip(String pkg, @UserIdInt int userId) {
synchronized (this) {
+ final int intendingUid = getIntendingUid(pkg, userId);
+ final int intendingUserId = UserHandle.getUserId(intendingUid);
if (!clipboardAccessAllowed(AppOpsManager.OP_READ_CLIPBOARD, pkg,
- Binder.getCallingUid()) || isDeviceLocked()) {
+ intendingUid, intendingUserId)
+ || isDeviceLocked(intendingUserId)) {
return null;
}
- addActiveOwnerLocked(Binder.getCallingUid(), pkg);
- return getClipboard().primaryClip;
+ addActiveOwnerLocked(intendingUid, pkg);
+ return getClipboard(intendingUserId).primaryClip;
}
}
@Override
- public ClipDescription getPrimaryClipDescription(String callingPackage) {
+ public ClipDescription getPrimaryClipDescription(String callingPackage,
+ @UserIdInt int userId) {
synchronized (this) {
+ final int intendingUid = getIntendingUid(callingPackage, userId);
+ final int intendingUserId = UserHandle.getUserId(intendingUid);
if (!clipboardAccessAllowed(AppOpsManager.OP_READ_CLIPBOARD, callingPackage,
- Binder.getCallingUid()) || isDeviceLocked()) {
+ intendingUid, intendingUserId)
+ || isDeviceLocked(intendingUserId)) {
return null;
}
- PerUserClipboard clipboard = getClipboard();
- return clipboard.primaryClip != null ? clipboard.primaryClip.getDescription() : null;
+ PerUserClipboard clipboard = getClipboard(intendingUserId);
+ return clipboard.primaryClip != null
+ ? clipboard.primaryClip.getDescription() : null;
}
}
@Override
- public boolean hasPrimaryClip(String callingPackage) {
+ public boolean hasPrimaryClip(String callingPackage, @UserIdInt int userId) {
synchronized (this) {
+ final int intendingUid = getIntendingUid(callingPackage, userId);
+ final int intendingUserId = UserHandle.getUserId(intendingUid);
if (!clipboardAccessAllowed(AppOpsManager.OP_READ_CLIPBOARD, callingPackage,
- Binder.getCallingUid()) || isDeviceLocked()) {
+ intendingUid, intendingUserId)
+ || isDeviceLocked(intendingUserId)) {
return false;
}
- return getClipboard().primaryClip != null;
+ return getClipboard(intendingUserId).primaryClip != null;
}
}
@Override
public void addPrimaryClipChangedListener(IOnPrimaryClipChangedListener listener,
- String callingPackage) {
+ String callingPackage, @UserIdInt int userId) {
synchronized (this) {
- getClipboard().primaryClipListeners.register(listener,
- new ListenerInfo(Binder.getCallingUid(), callingPackage));
+ final int intendingUid = getIntendingUid(callingPackage, userId);
+ final int intendingUserId = UserHandle.getUserId(intendingUid);
+ getClipboard(intendingUserId).primaryClipListeners.register(listener,
+ new ListenerInfo(intendingUid, callingPackage));
}
}
@Override
- public void removePrimaryClipChangedListener(IOnPrimaryClipChangedListener listener) {
+ public void removePrimaryClipChangedListener(IOnPrimaryClipChangedListener listener,
+ String callingPackage, @UserIdInt int userId) {
synchronized (this) {
- getClipboard().primaryClipListeners.unregister(listener);
+ final int intendingUserId = getIntendingUserId(callingPackage, userId);
+ getClipboard(intendingUserId).primaryClipListeners.unregister(listener);
}
}
@Override
- public boolean hasClipboardText(String callingPackage) {
+ public boolean hasClipboardText(String callingPackage, int userId) {
synchronized (this) {
+ final int intendingUid = getIntendingUid(callingPackage, userId);
+ final int intendingUserId = UserHandle.getUserId(intendingUid);
if (!clipboardAccessAllowed(AppOpsManager.OP_READ_CLIPBOARD, callingPackage,
- Binder.getCallingUid()) || isDeviceLocked()) {
+ intendingUid, intendingUserId)
+ || isDeviceLocked(intendingUserId)) {
return false;
}
- PerUserClipboard clipboard = getClipboard();
+ PerUserClipboard clipboard = getClipboard(intendingUserId);
if (clipboard.primaryClip != null) {
CharSequence text = clipboard.primaryClip.getItemAt(0).getText();
return text != null && text.length() > 0;
@@ -355,11 +464,7 @@ public class ClipboardService extends SystemService {
}
};
- private PerUserClipboard getClipboard() {
- return getClipboard(UserHandle.getCallingUserId());
- }
-
- private PerUserClipboard getClipboard(int userId) {
+ private PerUserClipboard getClipboard(@UserIdInt int userId) {
synchronized (mClipboards) {
PerUserClipboard puc = mClipboards.get(userId);
if (puc == null) {
@@ -370,7 +475,7 @@ public class ClipboardService extends SystemService {
}
}
- List<UserInfo> getRelatedProfiles(int userId) {
+ List<UserInfo> getRelatedProfiles(@UserIdInt int userId) {
final List<UserInfo> related;
final long origId = Binder.clearCallingIdentity();
try {
@@ -397,7 +502,7 @@ public class ClipboardService extends SystemService {
}
}
- void setPrimaryClipInternal(@Nullable ClipData clip, int callingUid) {
+ void setPrimaryClipInternal(@Nullable ClipData clip, int uid) {
// Push clipboard to host, if any
if (mHostClipboardMonitor != null) {
if (clip == null) {
@@ -412,8 +517,8 @@ public class ClipboardService extends SystemService {
}
// Update this user
- final int userId = UserHandle.getUserId(callingUid);
- setPrimaryClipInternal(getClipboard(userId), clip, callingUid);
+ final int userId = UserHandle.getUserId(uid);
+ setPrimaryClipInternal(getClipboard(userId), clip, uid);
// Update related users
List<UserInfo> related = getRelatedProfiles(userId);
@@ -426,11 +531,15 @@ public class ClipboardService extends SystemService {
// primary clip in related users to prevent pasting stale content.
if (!canCopy) {
clip = null;
+ } else if (clip == null) {
+ // do nothing for canCopy == true and clip == null case
+ // To prevent from NPE happen in 'new ClipData(clip)' when run
+ // android.content.cts.ClipboardManagerTest#testClearPrimaryClip
} else {
// We want to fix the uris of the related user's clip without changing the
// uris of the current user's clip.
// So, copy the ClipData, and then copy all the items, so that nothing
- // is shared in memmory.
+ // is shared in memory.
clip = new ClipData(clip);
for (int i = clip.getItemCount() - 1; i >= 0; i--) {
clip.setItemAt(i, new ClipData.Item(clip.getItemAt(i)));
@@ -443,7 +552,7 @@ public class ClipboardService extends SystemService {
final boolean canCopyIntoProfile = !hasRestriction(
UserManager.DISALLOW_SHARE_INTO_MANAGED_PROFILE, id);
if (canCopyIntoProfile) {
- setPrimaryClipInternal(getClipboard(id), clip, callingUid);
+ setPrimaryClipInternal(getClipboard(id), clip, uid);
}
}
}
@@ -452,7 +561,7 @@ public class ClipboardService extends SystemService {
}
void setPrimaryClipInternal(PerUserClipboard clipboard, @Nullable ClipData clip,
- int callingUid) {
+ int uid) {
revokeUris(clipboard);
clipboard.activePermissionOwners.clear();
if (clip == null && clipboard.primaryClip == null) {
@@ -460,7 +569,7 @@ public class ClipboardService extends SystemService {
}
clipboard.primaryClip = clip;
if (clip != null) {
- clipboard.primaryClipUid = callingUid;
+ clipboard.primaryClipUid = uid;
} else {
clipboard.primaryClipUid = android.os.Process.NOBODY_UID;
}
@@ -479,7 +588,7 @@ public class ClipboardService extends SystemService {
clipboard.primaryClipListeners.getBroadcastCookie(i);
if (clipboardAccessAllowed(AppOpsManager.OP_READ_CLIPBOARD, li.mPackageName,
- li.mUid)) {
+ li.mUid, UserHandle.getUserId(li.mUid))) {
clipboard.primaryClipListeners.getBroadcastItem(i)
.dispatchPrimaryClipChanged();
}
@@ -494,13 +603,12 @@ public class ClipboardService extends SystemService {
}
}
- private boolean isDeviceLocked() {
- int callingUserId = UserHandle.getCallingUserId();
+ private boolean isDeviceLocked(@UserIdInt int userId) {
final long token = Binder.clearCallingIdentity();
try {
final KeyguardManager keyguardManager = getContext().getSystemService(
KeyguardManager.class);
- return keyguardManager != null && keyguardManager.isDeviceLocked(callingUserId);
+ return keyguardManager != null && keyguardManager.isDeviceLocked(userId);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -585,7 +693,7 @@ public class ClipboardService extends SystemService {
} finally {
Binder.restoreCallingIdentity(oldIdentity);
}
- PerUserClipboard clipboard = getClipboard();
+ PerUserClipboard clipboard = getClipboard(UserHandle.getUserId(uid));
if (clipboard.primaryClip != null && !clipboard.activePermissionOwners.contains(pkg)) {
final int N = clipboard.primaryClip.getItemCount();
for (int i=0; i<N; i++) {
@@ -630,9 +738,10 @@ public class ClipboardService extends SystemService {
}
}
- private boolean clipboardAccessAllowed(int op, String callingPackage, int callingUid) {
+ private boolean clipboardAccessAllowed(int op, String callingPackage, int uid,
+ @UserIdInt int userId) {
// Check the AppOp.
- if (mAppOps.noteOp(op, callingUid, callingPackage) != AppOpsManager.MODE_ALLOWED) {
+ if (mAppOps.noteOp(op, uid, callingPackage) != AppOpsManager.MODE_ALLOWED) {
return false;
}
// Shell can access the clipboard for testing purposes.
@@ -641,7 +750,6 @@ public class ClipboardService extends SystemService {
return true;
}
// The default IME is always allowed to access the clipboard.
- int userId = UserHandle.getUserId(callingUid);
String defaultIme = Settings.Secure.getStringForUser(getContext().getContentResolver(),
Settings.Secure.DEFAULT_INPUT_METHOD, userId);
if (!TextUtils.isEmpty(defaultIme)) {
@@ -654,16 +762,31 @@ public class ClipboardService extends SystemService {
switch (op) {
case AppOpsManager.OP_READ_CLIPBOARD:
// Clipboard can only be read by applications with focus..
- boolean allowed = mWm.isUidFocused(callingUid);
+ // or the application have the INTERNAL_SYSTEM_WINDOW and INTERACT_ACROSS_USERS_FULL
+ // at the same time. e.x. SystemUI. It needs to check the window focus of
+ // Binder.getCallingUid(). Without checking, the user X can't copy any thing from
+ // INTERNAL_SYSTEM_WINDOW to the other applications.
+ boolean allowed = mWm.isUidFocused(uid)
+ || isInternalSysWindowAppWithWindowFocus(callingPackage);
if (!allowed && mContentCaptureInternal != null) {
// ...or the Content Capture Service
- allowed = mContentCaptureInternal.isContentCaptureServiceForUser(callingUid,
- userId);
+ // The uid parameter of mContentCaptureInternal.isContentCaptureServiceForUser
+ // is used to check if the uid has the permission BIND_CONTENT_CAPTURE_SERVICE.
+ // if the application has the permission, let it to access user's clipboard.
+ // To passed synthesized uid user#10_app#systemui may not tell the real uid.
+ // userId must pass intending userId. i.e. user#10.
+ allowed = mContentCaptureInternal.isContentCaptureServiceForUser(
+ Binder.getCallingUid(), userId);
}
if (!allowed && mAutofillInternal != null) {
// ...or the Augmented Autofill Service
- allowed = mAutofillInternal.isAugmentedAutofillServiceForUser(callingUid,
- userId);
+ // The uid parameter of mAutofillInternal.isAugmentedAutofillServiceForUser
+ // is used to check if the uid has the permission BIND_AUTOFILL_SERVICE.
+ // if the application has the permission, let it to access user's clipboard.
+ // To passed synthesized uid user#10_app#systemui may not tell the real uid.
+ // userId must pass intending userId. i.e. user#10.
+ allowed = mAutofillInternal.isAugmentedAutofillServiceForUser(
+ Binder.getCallingUid(), userId);
}
if (!allowed) {
Slog.e(TAG, "Denying clipboard access to " + callingPackage