FileDocCategorySizeDatePackage
ClipboardService.javaAPI DocAndroid 5.1 API15985Thu Mar 12 22:22:42 GMT 2015com.android.server.clipboard

ClipboardService

public class ClipboardService extends IClipboard.Stub
Implementation of the clipboard for copy and paste.

Fields Summary
private static final String
TAG
private final android.content.Context
mContext
private final android.app.IActivityManager
mAm
private final android.os.IUserManager
mUm
private final android.content.pm.PackageManager
mPm
private final android.app.AppOpsManager
mAppOps
private final android.os.IBinder
mPermissionOwner
private android.util.SparseArray
mClipboards
Constructors Summary
public ClipboardService(android.content.Context context)
Instantiates the clipboard.


            
       
        mContext = context;
        mAm = ActivityManagerNative.getDefault();
        mPm = context.getPackageManager();
        mUm = (IUserManager) ServiceManager.getService(Context.USER_SERVICE);
        mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
        IBinder permOwner = null;
        try {
            permOwner = mAm.newUriPermissionOwner("clipboard");
        } catch (RemoteException e) {
            Slog.w("clipboard", "AM dead", e);
        }
        mPermissionOwner = permOwner;

        // Remove the clipboard if a user is removed
        IntentFilter userFilter = new IntentFilter();
        userFilter.addAction(Intent.ACTION_USER_REMOVED);
        mContext.registerReceiver(new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                String action = intent.getAction();
                if (Intent.ACTION_USER_REMOVED.equals(action)) {
                    removeClipboard(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
                }
            }
        }, userFilter);
    
Methods Summary
private final voidaddActiveOwnerLocked(int uid, java.lang.String pkg)

        final IPackageManager pm = AppGlobals.getPackageManager();
        final int targetUserHandle = UserHandle.getCallingUserId();
        final long oldIdentity = Binder.clearCallingIdentity();
        try {
            PackageInfo pi = pm.getPackageInfo(pkg, 0, targetUserHandle);
            if (pi == null) {
                throw new IllegalArgumentException("Unknown package " + pkg);
            }
            if (!UserHandle.isSameApp(pi.applicationInfo.uid, uid)) {
                throw new SecurityException("Calling uid " + uid
                        + " does not own package " + pkg);
            }
        } catch (RemoteException e) {
            // Can't happen; the package manager is in the same process
        } finally {
            Binder.restoreCallingIdentity(oldIdentity);
        }
        PerUserClipboard clipboard = getClipboard();
        if (clipboard.primaryClip != null && !clipboard.activePermissionOwners.contains(pkg)) {
            final int N = clipboard.primaryClip.getItemCount();
            for (int i=0; i<N; i++) {
                grantItemLocked(clipboard.primaryClip.getItemAt(i), pkg, UserHandle.getUserId(uid));
            }
            clipboard.activePermissionOwners.add(pkg);
        }
    
public voidaddPrimaryClipChangedListener(android.content.IOnPrimaryClipChangedListener listener, java.lang.String callingPackage)

        synchronized (this) {
            getClipboard().primaryClipListeners.register(listener,
                    new ListenerInfo(Binder.getCallingUid(), callingPackage));
        }
    
private final voidcheckDataOwnerLocked(android.content.ClipData data, int uid)

        final int N = data.getItemCount();
        for (int i=0; i<N; i++) {
            checkItemOwnerLocked(data.getItemAt(i), uid);
        }
    
private final voidcheckItemOwnerLocked(ClipData.Item item, int uid)

        if (item.getUri() != null) {
            checkUriOwnerLocked(item.getUri(), uid);
        }
        Intent intent = item.getIntent();
        if (intent != null && intent.getData() != null) {
            checkUriOwnerLocked(intent.getData(), uid);
        }
    
private final voidcheckUriOwnerLocked(android.net.Uri uri, int uid)

        if (!"content".equals(uri.getScheme())) {
            return;
        }
        long ident = Binder.clearCallingIdentity();
        try {
            // This will throw SecurityException for us.
            mAm.checkGrantUriPermission(uid, null, ContentProvider.getUriWithoutUserId(uri),
                    Intent.FLAG_GRANT_READ_URI_PERMISSION,
                    ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(uid)));
        } catch (RemoteException e) {
        } finally {
            Binder.restoreCallingIdentity(ident);
        }
    
private com.android.server.clipboard.ClipboardService$PerUserClipboardgetClipboard()

        return getClipboard(UserHandle.getCallingUserId());
    
private com.android.server.clipboard.ClipboardService$PerUserClipboardgetClipboard(int userId)

        synchronized (mClipboards) {
            PerUserClipboard puc = mClipboards.get(userId);
            if (puc == null) {
                puc = new PerUserClipboard(userId);
                mClipboards.put(userId, puc);
            }
            return puc;
        }
    
public android.content.ClipDatagetPrimaryClip(java.lang.String pkg)

        synchronized (this) {
            if (mAppOps.noteOp(AppOpsManager.OP_READ_CLIPBOARD, Binder.getCallingUid(),
                    pkg) != AppOpsManager.MODE_ALLOWED) {
                return null;
            }
            addActiveOwnerLocked(Binder.getCallingUid(), pkg);
            return getClipboard().primaryClip;
        }
    
public android.content.ClipDescriptiongetPrimaryClipDescription(java.lang.String callingPackage)

        synchronized (this) {
            if (mAppOps.checkOp(AppOpsManager.OP_READ_CLIPBOARD, Binder.getCallingUid(),
                    callingPackage) != AppOpsManager.MODE_ALLOWED) {
                return null;
            }
            PerUserClipboard clipboard = getClipboard();
            return clipboard.primaryClip != null ? clipboard.primaryClip.getDescription() : null;
        }
    
java.util.ListgetRelatedProfiles(int userId)

        final List<UserInfo> related;
        final long origId = Binder.clearCallingIdentity();
        try {
            related = mUm.getProfiles(userId, true);
        } catch (RemoteException e) {
            Slog.e(TAG, "Remote Exception calling UserManager: " + e);
            return null;
        } finally{
            Binder.restoreCallingIdentity(origId);
        }
        return related;
    
private final voidgrantItemLocked(ClipData.Item item, java.lang.String pkg, int userId)

        if (item.getUri() != null) {
            grantUriLocked(item.getUri(), pkg, userId);
        }
        Intent intent = item.getIntent();
        if (intent != null && intent.getData() != null) {
            grantUriLocked(intent.getData(), pkg, userId);
        }
    
private final voidgrantUriLocked(android.net.Uri uri, java.lang.String pkg, int userId)

        long ident = Binder.clearCallingIdentity();
        try {
            int sourceUserId = ContentProvider.getUserIdFromUri(uri, userId);
            uri = ContentProvider.getUriWithoutUserId(uri);
            mAm.grantUriPermissionFromOwner(mPermissionOwner, Process.myUid(), pkg,
                    uri, Intent.FLAG_GRANT_READ_URI_PERMISSION, sourceUserId, userId);
        } catch (RemoteException e) {
        } finally {
            Binder.restoreCallingIdentity(ident);
        }
    
public booleanhasClipboardText(java.lang.String callingPackage)

        synchronized (this) {
            if (mAppOps.checkOp(AppOpsManager.OP_READ_CLIPBOARD, Binder.getCallingUid(),
                    callingPackage) != AppOpsManager.MODE_ALLOWED) {
                return false;
            }
            PerUserClipboard clipboard = getClipboard();
            if (clipboard.primaryClip != null) {
                CharSequence text = clipboard.primaryClip.getItemAt(0).getText();
                return text != null && text.length() > 0;
            }
            return false;
        }
    
public booleanhasPrimaryClip(java.lang.String callingPackage)

        synchronized (this) {
            if (mAppOps.checkOp(AppOpsManager.OP_READ_CLIPBOARD, Binder.getCallingUid(),
                    callingPackage) != AppOpsManager.MODE_ALLOWED) {
                return false;
            }
            return getClipboard().primaryClip != null;
        }
    
public booleanonTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags)

        try {
            return super.onTransact(code, data, reply, flags);
        } catch (RuntimeException e) {
            if (!(e instanceof SecurityException)) {
                Slog.wtf("clipboard", "Exception: ", e);
            }
            throw e;
        }
        
    
private voidremoveClipboard(int userId)

        synchronized (mClipboards) {
            mClipboards.remove(userId);
        }
    
public voidremovePrimaryClipChangedListener(android.content.IOnPrimaryClipChangedListener listener)

        synchronized (this) {
            getClipboard().primaryClipListeners.unregister(listener);
        }
    
private final voidrevokeItemLocked(ClipData.Item item)

        if (item.getUri() != null) {
            revokeUriLocked(item.getUri());
        }
        Intent intent = item.getIntent();
        if (intent != null && intent.getData() != null) {
            revokeUriLocked(intent.getData());
        }
    
private final voidrevokeUriLocked(android.net.Uri uri)

        int userId = ContentProvider.getUserIdFromUri(uri,
                UserHandle.getUserId(Binder.getCallingUid()));
        long ident = Binder.clearCallingIdentity();
        try {
            uri = ContentProvider.getUriWithoutUserId(uri);
            mAm.revokeUriPermissionFromOwner(mPermissionOwner, uri,
                    Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION,
                    userId);
        } catch (RemoteException e) {
        } finally {
            Binder.restoreCallingIdentity(ident);
        }
    
private final voidrevokeUris(com.android.server.clipboard.ClipboardService$PerUserClipboard clipboard)

        if (clipboard.primaryClip == null) {
            return;
        }
        final int N = clipboard.primaryClip.getItemCount();
        for (int i=0; i<N; i++) {
            revokeItemLocked(clipboard.primaryClip.getItemAt(i));
        }
    
public voidsetPrimaryClip(android.content.ClipData clip, java.lang.String callingPackage)

        synchronized (this) {
            if (clip != null && clip.getItemCount() <= 0) {
                throw new IllegalArgumentException("No items");
            }
            final int callingUid = Binder.getCallingUid();
            if (mAppOps.noteOp(AppOpsManager.OP_WRITE_CLIPBOARD, callingUid,
                    callingPackage) != AppOpsManager.MODE_ALLOWED) {
                return;
            }
            checkDataOwnerLocked(clip, callingUid);
            final int userId = UserHandle.getUserId(callingUid);
            PerUserClipboard clipboard = getClipboard(userId);
            revokeUris(clipboard);
            setPrimaryClipInternal(clipboard, clip);
            List<UserInfo> related = getRelatedProfiles(userId);
            if (related != null) {
                int size = related.size();
                if (size > 1) { // Related profiles list include the current profile.
                    boolean canCopy = false;
                    try {
                        canCopy = !mUm.getUserRestrictions(userId).getBoolean(
                                UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE);
                    } catch (RemoteException e) {
                        Slog.e(TAG, "Remote Exception calling UserManager: " + e);
                    }
                    // Copy clip data to related users if allowed. If disallowed, then remove
                    // primary clip in related users to prevent pasting stale content.
                    if (!canCopy) {
                        clip = null;
                    } else {
                        clip.fixUrisLight(userId);
                    }
                    for (int i = 0; i < size; i++) {
                        int id = related.get(i).id;
                        if (id != userId) {
                            setPrimaryClipInternal(getClipboard(id), clip);
                        }
                    }
                }
            }
        }
    
voidsetPrimaryClipInternal(com.android.server.clipboard.ClipboardService$PerUserClipboard clipboard, android.content.ClipData clip)

        clipboard.activePermissionOwners.clear();
        if (clip == null && clipboard.primaryClip == null) {
            return;
        }
        clipboard.primaryClip = clip;
        final long ident = Binder.clearCallingIdentity();
        final int n = clipboard.primaryClipListeners.beginBroadcast();
        try {
            for (int i = 0; i < n; i++) {
                try {
                    ListenerInfo li = (ListenerInfo)
                            clipboard.primaryClipListeners.getBroadcastCookie(i);
                    if (mAppOps.checkOpNoThrow(AppOpsManager.OP_READ_CLIPBOARD, li.mUid,
                            li.mPackageName) == AppOpsManager.MODE_ALLOWED) {
                        clipboard.primaryClipListeners.getBroadcastItem(i)
                                .dispatchPrimaryClipChanged();
                    }
                } catch (RemoteException e) {
                    // The RemoteCallbackList will take care of removing
                    // the dead object for us.
                }
            }
        } finally {
            clipboard.primaryClipListeners.finishBroadcast();
            Binder.restoreCallingIdentity(ident);
        }