Home | History | Annotate | Download | only in clipboard
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.server.clipboard;
     18 
     19 import android.annotation.Nullable;
     20 import android.app.ActivityManager;
     21 import android.app.AppGlobals;
     22 import android.app.AppOpsManager;
     23 import android.app.IActivityManager;
     24 import android.app.KeyguardManager;
     25 import android.content.ClipData;
     26 import android.content.ClipDescription;
     27 import android.content.ContentProvider;
     28 import android.content.ContentResolver;
     29 import android.content.Context;
     30 import android.content.IClipboard;
     31 import android.content.IOnPrimaryClipChangedListener;
     32 import android.content.Intent;
     33 import android.content.pm.IPackageManager;
     34 import android.content.pm.PackageInfo;
     35 import android.content.pm.PackageManager;
     36 import android.content.pm.UserInfo;
     37 import android.net.Uri;
     38 import android.os.Binder;
     39 import android.os.IBinder;
     40 import android.os.IUserManager;
     41 import android.os.Parcel;
     42 import android.os.RemoteCallbackList;
     43 import android.os.RemoteException;
     44 import android.os.ServiceManager;
     45 import android.os.SystemProperties;
     46 import android.os.UserHandle;
     47 import android.os.UserManager;
     48 import android.util.Slog;
     49 import android.util.SparseArray;
     50 
     51 import com.android.server.SystemService;
     52 
     53 import java.io.IOException;
     54 import java.io.RandomAccessFile;
     55 import java.util.HashSet;
     56 import java.util.List;
     57 
     58 // The following class is Android Emulator specific. It is used to read and
     59 // write contents of the host system's clipboard.
     60 class HostClipboardMonitor implements Runnable {
     61     public interface HostClipboardCallback {
     62         void onHostClipboardUpdated(String contents);
     63     }
     64 
     65     private RandomAccessFile mPipe = null;
     66     private HostClipboardCallback mHostClipboardCallback;
     67     private static final String PIPE_NAME = "pipe:clipboard";
     68     private static final String PIPE_DEVICE = "/dev/qemu_pipe";
     69 
     70     private void openPipe() {
     71         try {
     72             // String.getBytes doesn't include the null terminator,
     73             // but the QEMU pipe device requires the pipe service name
     74             // to be null-terminated.
     75             byte[] b = new byte[PIPE_NAME.length() + 1];
     76             b[PIPE_NAME.length()] = 0;
     77             System.arraycopy(
     78                 PIPE_NAME.getBytes(),
     79                 0,
     80                 b,
     81                 0,
     82                 PIPE_NAME.length());
     83             mPipe = new RandomAccessFile(PIPE_DEVICE, "rw");
     84             mPipe.write(b);
     85         } catch (IOException e) {
     86             try {
     87                 if (mPipe != null) mPipe.close();
     88             } catch (IOException ee) {}
     89             mPipe = null;
     90         }
     91     }
     92 
     93     public HostClipboardMonitor(HostClipboardCallback cb) {
     94         mHostClipboardCallback = cb;
     95     }
     96 
     97     @Override
     98     public void run() {
     99         while(!Thread.interrupted()) {
    100             try {
    101                 // There's no guarantee that QEMU pipes will be ready at the moment
    102                 // this method is invoked. We simply try to get the pipe open and
    103                 // retry on failure indefinitely.
    104                 while (mPipe == null) {
    105                     openPipe();
    106                     Thread.sleep(100);
    107                 }
    108                 int size = mPipe.readInt();
    109                 size = Integer.reverseBytes(size);
    110                 byte[] receivedData = new byte[size];
    111                 mPipe.readFully(receivedData);
    112                 mHostClipboardCallback.onHostClipboardUpdated(
    113                     new String(receivedData));
    114             } catch (IOException e) {
    115                 try {
    116                     mPipe.close();
    117                 } catch (IOException ee) {}
    118                 mPipe = null;
    119             } catch (InterruptedException e) {}
    120         }
    121     }
    122 
    123     public void setHostClipboard(String content) {
    124         try {
    125             if (mPipe != null) {
    126                 mPipe.writeInt(Integer.reverseBytes(content.getBytes().length));
    127                 mPipe.write(content.getBytes());
    128             }
    129         } catch(IOException e) {
    130             Slog.e("HostClipboardMonitor",
    131                    "Failed to set host clipboard " + e.getMessage());
    132         }
    133     }
    134 }
    135 
    136 /**
    137  * Implementation of the clipboard for copy and paste.
    138  */
    139 public class ClipboardService extends SystemService {
    140 
    141     private static final String TAG = "ClipboardService";
    142     private static final boolean IS_EMULATOR =
    143         SystemProperties.getBoolean("ro.kernel.qemu", false);
    144 
    145     private final IActivityManager mAm;
    146     private final IUserManager mUm;
    147     private final PackageManager mPm;
    148     private final AppOpsManager mAppOps;
    149     private final IBinder mPermissionOwner;
    150     private HostClipboardMonitor mHostClipboardMonitor = null;
    151     private Thread mHostMonitorThread = null;
    152 
    153     private final SparseArray<PerUserClipboard> mClipboards = new SparseArray<>();
    154 
    155     /**
    156      * Instantiates the clipboard.
    157      */
    158     public ClipboardService(Context context) {
    159         super(context);
    160 
    161         mAm = ActivityManager.getService();
    162         mPm = getContext().getPackageManager();
    163         mUm = (IUserManager) ServiceManager.getService(Context.USER_SERVICE);
    164         mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
    165         IBinder permOwner = null;
    166         try {
    167             permOwner = mAm.newUriPermissionOwner("clipboard");
    168         } catch (RemoteException e) {
    169             Slog.w("clipboard", "AM dead", e);
    170         }
    171         mPermissionOwner = permOwner;
    172         if (IS_EMULATOR) {
    173             mHostClipboardMonitor = new HostClipboardMonitor(
    174                 new HostClipboardMonitor.HostClipboardCallback() {
    175                     @Override
    176                     public void onHostClipboardUpdated(String contents){
    177                         ClipData clip =
    178                             new ClipData("host clipboard",
    179                                          new String[]{"text/plain"},
    180                                          new ClipData.Item(contents));
    181                         synchronized(mClipboards) {
    182                             setPrimaryClipInternal(getClipboard(0), clip,
    183                                     android.os.Process.SYSTEM_UID);
    184                         }
    185                     }
    186                 });
    187             mHostMonitorThread = new Thread(mHostClipboardMonitor);
    188             mHostMonitorThread.start();
    189         }
    190     }
    191 
    192     @Override
    193     public void onStart() {
    194         publishBinderService(Context.CLIPBOARD_SERVICE, new ClipboardImpl());
    195     }
    196 
    197     @Override
    198     public void onCleanupUser(int userId) {
    199         synchronized (mClipboards) {
    200             mClipboards.remove(userId);
    201         }
    202     }
    203 
    204     private class ListenerInfo {
    205         final int mUid;
    206         final String mPackageName;
    207         ListenerInfo(int uid, String packageName) {
    208             mUid = uid;
    209             mPackageName = packageName;
    210         }
    211     }
    212 
    213     private class PerUserClipboard {
    214         final int userId;
    215 
    216         final RemoteCallbackList<IOnPrimaryClipChangedListener> primaryClipListeners
    217                 = new RemoteCallbackList<IOnPrimaryClipChangedListener>();
    218 
    219         /** Current primary clip. */
    220         ClipData primaryClip;
    221         /** UID that set {@link #primaryClip}. */
    222         int primaryClipUid = android.os.Process.NOBODY_UID;
    223 
    224         final HashSet<String> activePermissionOwners
    225                 = new HashSet<String>();
    226 
    227         PerUserClipboard(int userId) {
    228             this.userId = userId;
    229         }
    230     }
    231 
    232     private class ClipboardImpl extends IClipboard.Stub {
    233         @Override
    234         public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
    235                 throws RemoteException {
    236             try {
    237                 return super.onTransact(code, data, reply, flags);
    238             } catch (RuntimeException e) {
    239                 if (!(e instanceof SecurityException)) {
    240                     Slog.wtf("clipboard", "Exception: ", e);
    241                 }
    242                 throw e;
    243             }
    244 
    245         }
    246 
    247         @Override
    248         public void setPrimaryClip(ClipData clip, String callingPackage) {
    249             synchronized (this) {
    250                 if (clip == null || clip.getItemCount() <= 0) {
    251                     throw new IllegalArgumentException("No items");
    252                 }
    253                 final int callingUid = Binder.getCallingUid();
    254                 if (!clipboardAccessAllowed(AppOpsManager.OP_WRITE_CLIPBOARD, callingPackage,
    255                             callingUid)) {
    256                     return;
    257                 }
    258                 checkDataOwnerLocked(clip, callingUid);
    259                 setPrimaryClipInternal(clip, callingUid);
    260             }
    261         }
    262 
    263         @Override
    264         public void clearPrimaryClip(String callingPackage) {
    265             synchronized (this) {
    266                 final int callingUid = Binder.getCallingUid();
    267                 if (!clipboardAccessAllowed(AppOpsManager.OP_WRITE_CLIPBOARD, callingPackage,
    268                         callingUid)) {
    269                     return;
    270                 }
    271                 setPrimaryClipInternal(null, callingUid);
    272             }
    273         }
    274 
    275         @Override
    276         public ClipData getPrimaryClip(String pkg) {
    277             synchronized (this) {
    278                 if (!clipboardAccessAllowed(AppOpsManager.OP_READ_CLIPBOARD, pkg,
    279                             Binder.getCallingUid()) || isDeviceLocked()) {
    280                     return null;
    281                 }
    282                 addActiveOwnerLocked(Binder.getCallingUid(), pkg);
    283                 return getClipboard().primaryClip;
    284             }
    285         }
    286 
    287         @Override
    288         public ClipDescription getPrimaryClipDescription(String callingPackage) {
    289             synchronized (this) {
    290                 if (!clipboardAccessAllowed(AppOpsManager.OP_READ_CLIPBOARD, callingPackage,
    291                             Binder.getCallingUid()) || isDeviceLocked()) {
    292                     return null;
    293                 }
    294                 PerUserClipboard clipboard = getClipboard();
    295                 return clipboard.primaryClip != null ? clipboard.primaryClip.getDescription() : null;
    296             }
    297         }
    298 
    299         @Override
    300         public boolean hasPrimaryClip(String callingPackage) {
    301             synchronized (this) {
    302                 if (!clipboardAccessAllowed(AppOpsManager.OP_READ_CLIPBOARD, callingPackage,
    303                             Binder.getCallingUid()) || isDeviceLocked()) {
    304                     return false;
    305                 }
    306                 return getClipboard().primaryClip != null;
    307             }
    308         }
    309 
    310         @Override
    311         public void addPrimaryClipChangedListener(IOnPrimaryClipChangedListener listener,
    312                 String callingPackage) {
    313             synchronized (this) {
    314                 getClipboard().primaryClipListeners.register(listener,
    315                         new ListenerInfo(Binder.getCallingUid(), callingPackage));
    316             }
    317         }
    318 
    319         @Override
    320         public void removePrimaryClipChangedListener(IOnPrimaryClipChangedListener listener) {
    321             synchronized (this) {
    322                 getClipboard().primaryClipListeners.unregister(listener);
    323             }
    324         }
    325 
    326         @Override
    327         public boolean hasClipboardText(String callingPackage) {
    328             synchronized (this) {
    329                 if (!clipboardAccessAllowed(AppOpsManager.OP_READ_CLIPBOARD, callingPackage,
    330                             Binder.getCallingUid()) || isDeviceLocked()) {
    331                     return false;
    332                 }
    333                 PerUserClipboard clipboard = getClipboard();
    334                 if (clipboard.primaryClip != null) {
    335                     CharSequence text = clipboard.primaryClip.getItemAt(0).getText();
    336                     return text != null && text.length() > 0;
    337                 }
    338                 return false;
    339             }
    340         }
    341     };
    342 
    343     private PerUserClipboard getClipboard() {
    344         return getClipboard(UserHandle.getCallingUserId());
    345     }
    346 
    347     private PerUserClipboard getClipboard(int userId) {
    348         synchronized (mClipboards) {
    349             PerUserClipboard puc = mClipboards.get(userId);
    350             if (puc == null) {
    351                 puc = new PerUserClipboard(userId);
    352                 mClipboards.put(userId, puc);
    353             }
    354             return puc;
    355         }
    356     }
    357 
    358     List<UserInfo> getRelatedProfiles(int userId) {
    359         final List<UserInfo> related;
    360         final long origId = Binder.clearCallingIdentity();
    361         try {
    362             related = mUm.getProfiles(userId, true);
    363         } catch (RemoteException e) {
    364             Slog.e(TAG, "Remote Exception calling UserManager: " + e);
    365             return null;
    366         } finally{
    367             Binder.restoreCallingIdentity(origId);
    368         }
    369         return related;
    370     }
    371 
    372     /** Check if the user has the given restriction set. Default to true if error occured during
    373      * calling UserManager, so it fails safe.
    374      */
    375     private boolean hasRestriction(String restriction, int userId) {
    376         try {
    377             return mUm.hasUserRestriction(restriction, userId);
    378         } catch (RemoteException e) {
    379             Slog.e(TAG, "Remote Exception calling UserManager.getUserRestrictions: ", e);
    380             // Fails safe
    381             return true;
    382         }
    383     }
    384 
    385     void setPrimaryClipInternal(@Nullable ClipData clip, int callingUid) {
    386         // Push clipboard to host, if any
    387         if (mHostClipboardMonitor != null) {
    388             if (clip == null) {
    389                 // Someone really wants the clipboard cleared, so push empty
    390                 mHostClipboardMonitor.setHostClipboard("");
    391             } else if (clip.getItemCount() > 0) {
    392                 final CharSequence text = clip.getItemAt(0).getText();
    393                 if (text != null) {
    394                     mHostClipboardMonitor.setHostClipboard(text.toString());
    395                 }
    396             }
    397         }
    398 
    399         // Update this user
    400         final int userId = UserHandle.getUserId(callingUid);
    401         setPrimaryClipInternal(getClipboard(userId), clip, callingUid);
    402 
    403         // Update related users
    404         List<UserInfo> related = getRelatedProfiles(userId);
    405         if (related != null) {
    406             int size = related.size();
    407             if (size > 1) { // Related profiles list include the current profile.
    408                 final boolean canCopy = !hasRestriction(
    409                         UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE, userId);
    410                 // Copy clip data to related users if allowed. If disallowed, then remove
    411                 // primary clip in related users to prevent pasting stale content.
    412                 if (!canCopy) {
    413                     clip = null;
    414                 } else {
    415                     // We want to fix the uris of the related user's clip without changing the
    416                     // uris of the current user's clip.
    417                     // So, copy the ClipData, and then copy all the items, so that nothing
    418                     // is shared in memmory.
    419                     clip = new ClipData(clip);
    420                     for (int i = clip.getItemCount() - 1; i >= 0; i--) {
    421                         clip.setItemAt(i, new ClipData.Item(clip.getItemAt(i)));
    422                     }
    423                     clip.fixUrisLight(userId);
    424                 }
    425                 for (int i = 0; i < size; i++) {
    426                     int id = related.get(i).id;
    427                     if (id != userId) {
    428                         final boolean canCopyIntoProfile = !hasRestriction(
    429                                 UserManager.DISALLOW_SHARE_INTO_MANAGED_PROFILE, id);
    430                         if (canCopyIntoProfile) {
    431                             setPrimaryClipInternal(getClipboard(id), clip, callingUid);
    432                         }
    433                     }
    434                 }
    435             }
    436         }
    437     }
    438 
    439     void setPrimaryClipInternal(PerUserClipboard clipboard, @Nullable ClipData clip,
    440             int callingUid) {
    441         revokeUris(clipboard);
    442         clipboard.activePermissionOwners.clear();
    443         if (clip == null && clipboard.primaryClip == null) {
    444             return;
    445         }
    446         clipboard.primaryClip = clip;
    447         if (clip != null) {
    448             clipboard.primaryClipUid = callingUid;
    449         } else {
    450             clipboard.primaryClipUid = android.os.Process.NOBODY_UID;
    451         }
    452         if (clip != null) {
    453             final ClipDescription description = clip.getDescription();
    454             if (description != null) {
    455                 description.setTimestamp(System.currentTimeMillis());
    456             }
    457         }
    458         final long ident = Binder.clearCallingIdentity();
    459         final int n = clipboard.primaryClipListeners.beginBroadcast();
    460         try {
    461             for (int i = 0; i < n; i++) {
    462                 try {
    463                     ListenerInfo li = (ListenerInfo)
    464                             clipboard.primaryClipListeners.getBroadcastCookie(i);
    465 
    466                     if (clipboardAccessAllowed(AppOpsManager.OP_READ_CLIPBOARD, li.mPackageName,
    467                                 li.mUid)) {
    468                         clipboard.primaryClipListeners.getBroadcastItem(i)
    469                                 .dispatchPrimaryClipChanged();
    470                     }
    471                 } catch (RemoteException e) {
    472                     // The RemoteCallbackList will take care of removing
    473                     // the dead object for us.
    474                 }
    475             }
    476         } finally {
    477             clipboard.primaryClipListeners.finishBroadcast();
    478             Binder.restoreCallingIdentity(ident);
    479         }
    480     }
    481 
    482     private boolean isDeviceLocked() {
    483         int callingUserId = UserHandle.getCallingUserId();
    484         final long token = Binder.clearCallingIdentity();
    485         try {
    486             final KeyguardManager keyguardManager = getContext().getSystemService(
    487                     KeyguardManager.class);
    488             return keyguardManager != null && keyguardManager.isDeviceLocked(callingUserId);
    489         } finally {
    490             Binder.restoreCallingIdentity(token);
    491         }
    492     }
    493 
    494     private final void checkUriOwnerLocked(Uri uri, int sourceUid) {
    495         if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) return;
    496 
    497         final long ident = Binder.clearCallingIdentity();
    498         try {
    499             // This will throw SecurityException if caller can't grant
    500             mAm.checkGrantUriPermission(sourceUid, null,
    501                     ContentProvider.getUriWithoutUserId(uri),
    502                     Intent.FLAG_GRANT_READ_URI_PERMISSION,
    503                     ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(sourceUid)));
    504         } catch (RemoteException ignored) {
    505             // Ignored because we're in same process
    506         } finally {
    507             Binder.restoreCallingIdentity(ident);
    508         }
    509     }
    510 
    511     private final void checkItemOwnerLocked(ClipData.Item item, int uid) {
    512         if (item.getUri() != null) {
    513             checkUriOwnerLocked(item.getUri(), uid);
    514         }
    515         Intent intent = item.getIntent();
    516         if (intent != null && intent.getData() != null) {
    517             checkUriOwnerLocked(intent.getData(), uid);
    518         }
    519     }
    520 
    521     private final void checkDataOwnerLocked(ClipData data, int uid) {
    522         final int N = data.getItemCount();
    523         for (int i=0; i<N; i++) {
    524             checkItemOwnerLocked(data.getItemAt(i), uid);
    525         }
    526     }
    527 
    528     private final void grantUriLocked(Uri uri, int sourceUid, String targetPkg,
    529             int targetUserId) {
    530         if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) return;
    531 
    532         final long ident = Binder.clearCallingIdentity();
    533         try {
    534             mAm.grantUriPermissionFromOwner(mPermissionOwner, sourceUid, targetPkg,
    535                     ContentProvider.getUriWithoutUserId(uri),
    536                     Intent.FLAG_GRANT_READ_URI_PERMISSION,
    537                     ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(sourceUid)),
    538                     targetUserId);
    539         } catch (RemoteException ignored) {
    540             // Ignored because we're in same process
    541         } finally {
    542             Binder.restoreCallingIdentity(ident);
    543         }
    544     }
    545 
    546     private final void grantItemLocked(ClipData.Item item, int sourceUid, String targetPkg,
    547             int targetUserId) {
    548         if (item.getUri() != null) {
    549             grantUriLocked(item.getUri(), sourceUid, targetPkg, targetUserId);
    550         }
    551         Intent intent = item.getIntent();
    552         if (intent != null && intent.getData() != null) {
    553             grantUriLocked(intent.getData(), sourceUid, targetPkg, targetUserId);
    554         }
    555     }
    556 
    557     private final void addActiveOwnerLocked(int uid, String pkg) {
    558         final IPackageManager pm = AppGlobals.getPackageManager();
    559         final int targetUserHandle = UserHandle.getCallingUserId();
    560         final long oldIdentity = Binder.clearCallingIdentity();
    561         try {
    562             PackageInfo pi = pm.getPackageInfo(pkg, 0, targetUserHandle);
    563             if (pi == null) {
    564                 throw new IllegalArgumentException("Unknown package " + pkg);
    565             }
    566             if (!UserHandle.isSameApp(pi.applicationInfo.uid, uid)) {
    567                 throw new SecurityException("Calling uid " + uid
    568                         + " does not own package " + pkg);
    569             }
    570         } catch (RemoteException e) {
    571             // Can't happen; the package manager is in the same process
    572         } finally {
    573             Binder.restoreCallingIdentity(oldIdentity);
    574         }
    575         PerUserClipboard clipboard = getClipboard();
    576         if (clipboard.primaryClip != null && !clipboard.activePermissionOwners.contains(pkg)) {
    577             final int N = clipboard.primaryClip.getItemCount();
    578             for (int i=0; i<N; i++) {
    579                 grantItemLocked(clipboard.primaryClip.getItemAt(i), clipboard.primaryClipUid, pkg,
    580                         UserHandle.getUserId(uid));
    581             }
    582             clipboard.activePermissionOwners.add(pkg);
    583         }
    584     }
    585 
    586     private final void revokeUriLocked(Uri uri, int sourceUid) {
    587         if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) return;
    588 
    589         final long ident = Binder.clearCallingIdentity();
    590         try {
    591             mAm.revokeUriPermissionFromOwner(mPermissionOwner,
    592                     ContentProvider.getUriWithoutUserId(uri),
    593                     Intent.FLAG_GRANT_READ_URI_PERMISSION,
    594                     ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(sourceUid)));
    595         } catch (RemoteException ignored) {
    596             // Ignored because we're in same process
    597         } finally {
    598             Binder.restoreCallingIdentity(ident);
    599         }
    600     }
    601 
    602     private final void revokeItemLocked(ClipData.Item item, int sourceUid) {
    603         if (item.getUri() != null) {
    604             revokeUriLocked(item.getUri(), sourceUid);
    605         }
    606         Intent intent = item.getIntent();
    607         if (intent != null && intent.getData() != null) {
    608             revokeUriLocked(intent.getData(), sourceUid);
    609         }
    610     }
    611 
    612     private final void revokeUris(PerUserClipboard clipboard) {
    613         if (clipboard.primaryClip == null) {
    614             return;
    615         }
    616         final int N = clipboard.primaryClip.getItemCount();
    617         for (int i=0; i<N; i++) {
    618             revokeItemLocked(clipboard.primaryClip.getItemAt(i), clipboard.primaryClipUid);
    619         }
    620     }
    621 
    622     private boolean clipboardAccessAllowed(int op, String callingPackage, int callingUid) {
    623         // Check the AppOp.
    624         if (mAppOps.noteOp(op, callingUid, callingPackage) != AppOpsManager.MODE_ALLOWED) {
    625             return false;
    626         }
    627         try {
    628             // Installed apps can access the clipboard at any time.
    629             if (!AppGlobals.getPackageManager().isInstantApp(callingPackage,
    630                         UserHandle.getUserId(callingUid))) {
    631                 return true;
    632             }
    633             // Instant apps can only access the clipboard if they are in the foreground.
    634             return mAm.isAppForeground(callingUid);
    635         } catch (RemoteException e) {
    636             Slog.e("clipboard", "Failed to get Instant App status for package " + callingPackage,
    637                     e);
    638             return false;
    639         }
    640     }
    641 }
    642