Merge "Fix sysui's security issue of cross-user copy/paste" into qt-dev am: 743288a029
am: 01fc17e00a
Change-Id: Ia08381c82abd12c3359d4ec8cf2bd9b1ed9b7c5f
This commit is contained in:
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user