Fix sysui's security issue of cross-user copy/paste

Background:
The applications with the granted INTERNAL_SYSTEM_WINDOW and
INTERACT_ACROSS_USERS_FULL means that it could show the same
window for all of users. i.e. to use user 0 presents all of
UI things to all of users.

INTERNAL_SYSTEM_WINDOW usually comes with INTERACT_ACROSS_USERS_FULL
because it will serve all of users to know the information that
comes from framework and system server.

Solution:
Because SystemUI never restarts after the user changing,
ClipboardService can't tell if the callingUid has the the same userId
with the current user or not.  The solution is to use the permission
check. Especially, INTERACT_ACROSS_USERS_FULL and
INTERNAL_SYSTEM_WINDOW. To check INTERACT_ACROSS_USERS_FULL by using
ActivityManagerInternal.handleIncomingUser.

Caution:
The application with INTERNAL_SYSTEM_WINDOW usually use user 0
to show the window. But, the current user is user 10, WindowManager
know the focus windows is belong to user 0 rather user 10. That's
why user 10 can't copy the the text from systemui directly reply to
the other applications.

Readability:
ClipboardService use callingUid everywhere but actaully it is not
appropriated to fix this kind of bug. This patch refactor the naming
to produce two name. i.e. intendingUid and intentdingUserId that are
validated by ActivityManagerInternal.handleIncomingUser.

Test: manual test
Test: atest android.widget.cts.TextViewTest
Test: atest CtsTextTestCases
Test: atest CtsContentTestCases

Bug: 123232892
Bug: 117768051
Change-Id: Ie3daecd1e8fc2f7fdf37baeb5979da9f2e0b3937
diff --git a/core/java/android/content/ClipboardManager.java b/core/java/android/content/ClipboardManager.java
index 8760efe..dc1c700 100644
--- a/core/java/android/content/ClipboardManager.java
+++ b/core/java/android/content/ClipboardManager.java
@@ -103,7 +103,7 @@
         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 void clearPrimaryClip() {
         try {
-            mService.clearPrimaryClip(mContext.getOpPackageName());
+            mService.clearPrimaryClip(mContext.getOpPackageName(), mContext.getUserId());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -132,7 +132,7 @@
      */
     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 @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 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 @@
             if (mPrimaryClipChangedListeners.isEmpty()) {
                 try {
                     mService.addPrimaryClipChangedListener(
-                            mPrimaryClipChangedServiceListener, mContext.getOpPackageName());
+                            mPrimaryClipChangedServiceListener, mContext.getOpPackageName(),
+                            mContext.getUserId());
                 } catch (RemoteException e) {
                     throw e.rethrowFromSystemServer();
                 }
@@ -189,7 +191,8 @@
             if (mPrimaryClipChangedListeners.isEmpty()) {
                 try {
                     mService.removePrimaryClipChangedListener(
-                            mPrimaryClipChangedServiceListener);
+                            mPrimaryClipChangedServiceListener, mContext.getOpPackageName(),
+                            mContext.getUserId());
                 } catch (RemoteException e) {
                     throw e.rethrowFromSystemServer();
                 }
@@ -226,7 +229,7 @@
     @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 135a436..0d5a460 100644
--- a/core/java/android/content/IClipboard.aidl
+++ b/core/java/android/content/IClipboard.aidl
@@ -26,17 +26,18 @@
  * {@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 17c56c3..a9e183a 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -11244,13 +11244,23 @@
 
     @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 @@
                 && mEditor != null && mEditor.mKeyListener != null
                 && getSelectionStart() >= 0
                 && getSelectionEnd() >= 0
-                && ((ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE))
-                        .hasPrimaryClip());
+                && getClipboardManagerForUser().hasPrimaryClip());
     }
 
     boolean canPasteAsPlainText() {
@@ -12549,9 +12558,7 @@
             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 @@
      * 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 @@
 
     @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 d28482e..af25ad5 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 @@
 
 /**
  * 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 @@
     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 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 @@
         }
     }
 
+    /**
+     * 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 @@
         }
 
         @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 @@
         }
     };
 
-    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 @@
         }
     }
 
-    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 @@
         }
     }
 
-    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 @@
         }
 
         // 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 @@
                 // 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 @@
                         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 @@
     }
 
     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 @@
         }
         clipboard.primaryClip = clip;
         if (clip != null) {
-            clipboard.primaryClipUid = callingUid;
+            clipboard.primaryClipUid = uid;
         } else {
             clipboard.primaryClipUid = android.os.Process.NOBODY_UID;
         }
@@ -479,7 +588,7 @@
                             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 @@
         }
     }
 
-    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 @@
         } 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 @@
         }
     }
 
-    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 @@
             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 @@
         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