19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* 29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project 39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License. 69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at 79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and 149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License. 159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage com.android.server; 189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1990f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackbornimport android.app.ActivityManagerNative; 20ad9833a77ff4deb5352c67800c2ee62ed6e51356Christopher Tateimport android.app.AppGlobals; 21efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackbornimport android.app.AppOpsManager; 2290f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackbornimport android.app.IActivityManager; 23e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasaniimport android.content.BroadcastReceiver; 241040dc465cbf5ca8f834a87c949e476abefa3f76Dianne Hackbornimport android.content.ClipData; 251040dc465cbf5ca8f834a87c949e476abefa3f76Dianne Hackbornimport android.content.ClipDescription; 269f53119b72e6da865bcd53173d3dacd1eba01aeeDianne Hackbornimport android.content.IClipboard; 279f53119b72e6da865bcd53173d3dacd1eba01aeeDianne Hackbornimport android.content.IOnPrimaryClipChangedListener; 289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context; 2990f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackbornimport android.content.Intent; 30e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasaniimport android.content.IntentFilter; 31ad9833a77ff4deb5352c67800c2ee62ed6e51356Christopher Tateimport android.content.pm.IPackageManager; 3290f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackbornimport android.content.pm.PackageInfo; 3390f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackbornimport android.content.pm.PackageManager; 3490f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackbornimport android.content.pm.PackageManager.NameNotFoundException; 3590f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackbornimport android.net.Uri; 3690f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackbornimport android.os.Binder; 3790f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackbornimport android.os.IBinder; 3890f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackbornimport android.os.Parcel; 3990f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackbornimport android.os.Process; 409f53119b72e6da865bcd53173d3dacd1eba01aeeDianne Hackbornimport android.os.RemoteCallbackList; 419f53119b72e6da865bcd53173d3dacd1eba01aeeDianne Hackbornimport android.os.RemoteException; 42f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackbornimport android.os.UserHandle; 4390f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackbornimport android.util.Pair; 4490f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackbornimport android.util.Slog; 45e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasaniimport android.util.SparseArray; 4690f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn 4790f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackbornimport java.util.HashSet; 489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Implementation of the clipboard for copy and paste. 519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class ClipboardService extends IClipboard.Stub { 53e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani 54e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani private static final String TAG = "ClipboardService"; 55e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani 5690f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn private final Context mContext; 5790f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn private final IActivityManager mAm; 5890f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn private final PackageManager mPm; 59efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn private final AppOpsManager mAppOps; 6090f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn private final IBinder mPermissionOwner; 6190f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn 62efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn private class ListenerInfo { 63efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn final int mUid; 64efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn final String mPackageName; 65efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn ListenerInfo(int uid, String packageName) { 66efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn mUid = uid; 67efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn mPackageName = packageName; 68efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn } 69efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn } 70efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn 71e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani private class PerUserClipboard { 72e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani final int userId; 73e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani 74e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani final RemoteCallbackList<IOnPrimaryClipChangedListener> primaryClipListeners 75e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani = new RemoteCallbackList<IOnPrimaryClipChangedListener>(); 76e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani 77e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani ClipData primaryClip; 78e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani 79e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani final HashSet<String> activePermissionOwners 80e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani = new HashSet<String>(); 819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 82e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani PerUserClipboard(int userId) { 83e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani this.userId = userId; 84e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani } 85e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani } 8690f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn 87e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani private SparseArray<PerUserClipboard> mClipboards = new SparseArray<PerUserClipboard>(); 8890f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn 899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Instantiates the clipboard. 919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 9290f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn public ClipboardService(Context context) { 9390f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn mContext = context; 9490f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn mAm = ActivityManagerNative.getDefault(); 9590f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn mPm = context.getPackageManager(); 96efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE); 9790f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn IBinder permOwner = null; 9890f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn try { 9990f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn permOwner = mAm.newUriPermissionOwner("clipboard"); 10090f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } catch (RemoteException e) { 10190f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn Slog.w("clipboard", "AM dead", e); 10290f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 10390f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn mPermissionOwner = permOwner; 104e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani 105e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani // Remove the clipboard if a user is removed 106e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani IntentFilter userFilter = new IntentFilter(); 107e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani userFilter.addAction(Intent.ACTION_USER_REMOVED); 108e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani mContext.registerReceiver(new BroadcastReceiver() { 109e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani @Override 110e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani public void onReceive(Context context, Intent intent) { 111e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani String action = intent.getAction(); 112e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani if (Intent.ACTION_USER_REMOVED.equals(action)) { 1132a00329c6d55c6cd9166e01963d7410e95d80d21Amith Yamasani removeClipboard(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0)); 114e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani } 115e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani } 116e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani }, userFilter); 11790f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 11890f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn 11990f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn @Override 12090f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn public boolean onTransact(int code, Parcel data, Parcel reply, int flags) 12190f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn throws RemoteException { 12290f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn try { 12390f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn return super.onTransact(code, data, reply, flags); 12490f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } catch (RuntimeException e) { 125164371fb759bad6854570af0fca60d9a01e17235Dianne Hackborn if (!(e instanceof SecurityException)) { 126164371fb759bad6854570af0fca60d9a01e17235Dianne Hackborn Slog.wtf("clipboard", "Exception: ", e); 127164371fb759bad6854570af0fca60d9a01e17235Dianne Hackborn } 12890f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn throw e; 12990f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 13090f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn 13190f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 133e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani private PerUserClipboard getClipboard() { 134f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackborn return getClipboard(UserHandle.getCallingUserId()); 135e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani } 136e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani 137e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani private PerUserClipboard getClipboard(int userId) { 138e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani synchronized (mClipboards) { 139e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani PerUserClipboard puc = mClipboards.get(userId); 140e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani if (puc == null) { 141e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani puc = new PerUserClipboard(userId); 142e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani mClipboards.put(userId, puc); 143e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani } 144e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani return puc; 145e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani } 146e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani } 147e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani 148e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani private void removeClipboard(int userId) { 149e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani synchronized (mClipboards) { 150e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani mClipboards.remove(userId); 151e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani } 152e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani } 153e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani 154efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn public void setPrimaryClip(ClipData clip, String callingPackage) { 1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project synchronized (this) { 1569f53119b72e6da865bcd53173d3dacd1eba01aeeDianne Hackborn if (clip != null && clip.getItemCount() <= 0) { 1579f53119b72e6da865bcd53173d3dacd1eba01aeeDianne Hackborn throw new IllegalArgumentException("No items"); 1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 159f0989840a00e53751241d0c97bf0e5a1866f6d4cDianne Hackborn final int callingUid = Binder.getCallingUid(); 160f0989840a00e53751241d0c97bf0e5a1866f6d4cDianne Hackborn if (mAppOps.noteOp(AppOpsManager.OP_WRITE_CLIPBOARD, callingUid, 161efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn callingPackage) != AppOpsManager.MODE_ALLOWED) { 162efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn return; 163efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn } 164f0989840a00e53751241d0c97bf0e5a1866f6d4cDianne Hackborn checkDataOwnerLocked(clip, callingUid); 16590f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn clearActiveOwnersLocked(); 166e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani PerUserClipboard clipboard = getClipboard(); 167e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani clipboard.primaryClip = clip; 168f0989840a00e53751241d0c97bf0e5a1866f6d4cDianne Hackborn final long ident = Binder.clearCallingIdentity(); 169e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani final int n = clipboard.primaryClipListeners.beginBroadcast(); 170f0989840a00e53751241d0c97bf0e5a1866f6d4cDianne Hackborn try { 171f0989840a00e53751241d0c97bf0e5a1866f6d4cDianne Hackborn for (int i = 0; i < n; i++) { 172f0989840a00e53751241d0c97bf0e5a1866f6d4cDianne Hackborn try { 173f0989840a00e53751241d0c97bf0e5a1866f6d4cDianne Hackborn ListenerInfo li = (ListenerInfo) 174f0989840a00e53751241d0c97bf0e5a1866f6d4cDianne Hackborn clipboard.primaryClipListeners.getBroadcastCookie(i); 175f0989840a00e53751241d0c97bf0e5a1866f6d4cDianne Hackborn if (mAppOps.checkOpNoThrow(AppOpsManager.OP_READ_CLIPBOARD, li.mUid, 176f0989840a00e53751241d0c97bf0e5a1866f6d4cDianne Hackborn li.mPackageName) == AppOpsManager.MODE_ALLOWED) { 177f0989840a00e53751241d0c97bf0e5a1866f6d4cDianne Hackborn clipboard.primaryClipListeners.getBroadcastItem(i) 178f0989840a00e53751241d0c97bf0e5a1866f6d4cDianne Hackborn .dispatchPrimaryClipChanged(); 179f0989840a00e53751241d0c97bf0e5a1866f6d4cDianne Hackborn } 180f0989840a00e53751241d0c97bf0e5a1866f6d4cDianne Hackborn } catch (RemoteException e) { 181f0989840a00e53751241d0c97bf0e5a1866f6d4cDianne Hackborn // The RemoteCallbackList will take care of removing 182f0989840a00e53751241d0c97bf0e5a1866f6d4cDianne Hackborn // the dead object for us. 183efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn } 1849f53119b72e6da865bcd53173d3dacd1eba01aeeDianne Hackborn } 185f0989840a00e53751241d0c97bf0e5a1866f6d4cDianne Hackborn } finally { 186f0989840a00e53751241d0c97bf0e5a1866f6d4cDianne Hackborn clipboard.primaryClipListeners.finishBroadcast(); 187f0989840a00e53751241d0c97bf0e5a1866f6d4cDianne Hackborn Binder.restoreCallingIdentity(ident); 1889f53119b72e6da865bcd53173d3dacd1eba01aeeDianne Hackborn } 1899f53119b72e6da865bcd53173d3dacd1eba01aeeDianne Hackborn } 1909f53119b72e6da865bcd53173d3dacd1eba01aeeDianne Hackborn } 1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 19290f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn public ClipData getPrimaryClip(String pkg) { 1939f53119b72e6da865bcd53173d3dacd1eba01aeeDianne Hackborn synchronized (this) { 194efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn if (mAppOps.noteOp(AppOpsManager.OP_READ_CLIPBOARD, Binder.getCallingUid(), 195efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn pkg) != AppOpsManager.MODE_ALLOWED) { 196efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn return null; 197efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn } 19890f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn addActiveOwnerLocked(Binder.getCallingUid(), pkg); 199e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani return getClipboard().primaryClip; 2009f53119b72e6da865bcd53173d3dacd1eba01aeeDianne Hackborn } 2019f53119b72e6da865bcd53173d3dacd1eba01aeeDianne Hackborn } 2029f53119b72e6da865bcd53173d3dacd1eba01aeeDianne Hackborn 203efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn public ClipDescription getPrimaryClipDescription(String callingPackage) { 2041040dc465cbf5ca8f834a87c949e476abefa3f76Dianne Hackborn synchronized (this) { 205efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn if (mAppOps.checkOp(AppOpsManager.OP_READ_CLIPBOARD, Binder.getCallingUid(), 206efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn callingPackage) != AppOpsManager.MODE_ALLOWED) { 207efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn return null; 208efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn } 209e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani PerUserClipboard clipboard = getClipboard(); 210e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani return clipboard.primaryClip != null ? clipboard.primaryClip.getDescription() : null; 2111040dc465cbf5ca8f834a87c949e476abefa3f76Dianne Hackborn } 2121040dc465cbf5ca8f834a87c949e476abefa3f76Dianne Hackborn } 2131040dc465cbf5ca8f834a87c949e476abefa3f76Dianne Hackborn 214efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn public boolean hasPrimaryClip(String callingPackage) { 2159f53119b72e6da865bcd53173d3dacd1eba01aeeDianne Hackborn synchronized (this) { 216efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn if (mAppOps.checkOp(AppOpsManager.OP_READ_CLIPBOARD, Binder.getCallingUid(), 217efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn callingPackage) != AppOpsManager.MODE_ALLOWED) { 218efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn return false; 219efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn } 220e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani return getClipboard().primaryClip != null; 2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 224efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn public void addPrimaryClipChangedListener(IOnPrimaryClipChangedListener listener, 225efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn String callingPackage) { 2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project synchronized (this) { 227efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn getClipboard().primaryClipListeners.register(listener, 228efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn new ListenerInfo(Binder.getCallingUid(), callingPackage)); 2299f53119b72e6da865bcd53173d3dacd1eba01aeeDianne Hackborn } 2309f53119b72e6da865bcd53173d3dacd1eba01aeeDianne Hackborn } 2319f53119b72e6da865bcd53173d3dacd1eba01aeeDianne Hackborn 2329f53119b72e6da865bcd53173d3dacd1eba01aeeDianne Hackborn public void removePrimaryClipChangedListener(IOnPrimaryClipChangedListener listener) { 2339f53119b72e6da865bcd53173d3dacd1eba01aeeDianne Hackborn synchronized (this) { 234e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani getClipboard().primaryClipListeners.unregister(listener); 2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 238efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn public boolean hasClipboardText(String callingPackage) { 2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project synchronized (this) { 240efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn if (mAppOps.checkOp(AppOpsManager.OP_READ_CLIPBOARD, Binder.getCallingUid(), 241efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn callingPackage) != AppOpsManager.MODE_ALLOWED) { 242efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn return false; 243efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn } 244e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani PerUserClipboard clipboard = getClipboard(); 245e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani if (clipboard.primaryClip != null) { 246e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani CharSequence text = clipboard.primaryClip.getItemAt(0).getText(); 2479f53119b72e6da865bcd53173d3dacd1eba01aeeDianne Hackborn return text != null && text.length() > 0; 2489f53119b72e6da865bcd53173d3dacd1eba01aeeDianne Hackborn } 2499f53119b72e6da865bcd53173d3dacd1eba01aeeDianne Hackborn return false; 2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 25290f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn 25390f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn private final void checkUriOwnerLocked(Uri uri, int uid) { 25490f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn if (!"content".equals(uri.getScheme())) { 25590f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn return; 25690f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 25790f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn long ident = Binder.clearCallingIdentity(); 25890f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn try { 25990f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn // This will throw SecurityException for us. 26090f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn mAm.checkGrantUriPermission(uid, null, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION); 26190f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } catch (RemoteException e) { 26290f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } finally { 26390f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn Binder.restoreCallingIdentity(ident); 26490f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 26590f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 26690f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn 26790f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn private final void checkItemOwnerLocked(ClipData.Item item, int uid) { 26890f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn if (item.getUri() != null) { 26990f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn checkUriOwnerLocked(item.getUri(), uid); 27090f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 27190f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn Intent intent = item.getIntent(); 27290f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn if (intent != null && intent.getData() != null) { 27390f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn checkUriOwnerLocked(intent.getData(), uid); 27490f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 27590f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 27690f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn 27790f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn private final void checkDataOwnerLocked(ClipData data, int uid) { 27890f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn final int N = data.getItemCount(); 27990f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn for (int i=0; i<N; i++) { 280327fbd2c8fa294b919475feb4c74a74ee1981e02Dianne Hackborn checkItemOwnerLocked(data.getItemAt(i), uid); 28190f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 28290f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 28390f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn 28490f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn private final void grantUriLocked(Uri uri, String pkg) { 28590f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn long ident = Binder.clearCallingIdentity(); 28690f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn try { 28790f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn mAm.grantUriPermissionFromOwner(mPermissionOwner, Process.myUid(), pkg, uri, 28890f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn Intent.FLAG_GRANT_READ_URI_PERMISSION); 28990f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } catch (RemoteException e) { 29090f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } finally { 29190f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn Binder.restoreCallingIdentity(ident); 29290f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 29390f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 29490f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn 29590f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn private final void grantItemLocked(ClipData.Item item, String pkg) { 29690f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn if (item.getUri() != null) { 29790f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn grantUriLocked(item.getUri(), pkg); 29890f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 29990f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn Intent intent = item.getIntent(); 30090f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn if (intent != null && intent.getData() != null) { 30190f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn grantUriLocked(intent.getData(), pkg); 30290f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 30390f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 30490f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn 30590f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn private final void addActiveOwnerLocked(int uid, String pkg) { 306ad9833a77ff4deb5352c67800c2ee62ed6e51356Christopher Tate final IPackageManager pm = AppGlobals.getPackageManager(); 307ad9833a77ff4deb5352c67800c2ee62ed6e51356Christopher Tate final int targetUserHandle = UserHandle.getCallingUserId(); 308ad9833a77ff4deb5352c67800c2ee62ed6e51356Christopher Tate final long oldIdentity = Binder.clearCallingIdentity(); 30990f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn try { 310ad9833a77ff4deb5352c67800c2ee62ed6e51356Christopher Tate PackageInfo pi = pm.getPackageInfo(pkg, 0, targetUserHandle); 311ad9833a77ff4deb5352c67800c2ee62ed6e51356Christopher Tate if (pi == null) { 312ad9833a77ff4deb5352c67800c2ee62ed6e51356Christopher Tate throw new IllegalArgumentException("Unknown package " + pkg); 313ad9833a77ff4deb5352c67800c2ee62ed6e51356Christopher Tate } 314f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackborn if (!UserHandle.isSameApp(pi.applicationInfo.uid, uid)) { 31590f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn throw new SecurityException("Calling uid " + uid 31690f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn + " does not own package " + pkg); 31790f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 318ad9833a77ff4deb5352c67800c2ee62ed6e51356Christopher Tate } catch (RemoteException e) { 319ad9833a77ff4deb5352c67800c2ee62ed6e51356Christopher Tate // Can't happen; the package manager is in the same process 320ad9833a77ff4deb5352c67800c2ee62ed6e51356Christopher Tate } finally { 321ad9833a77ff4deb5352c67800c2ee62ed6e51356Christopher Tate Binder.restoreCallingIdentity(oldIdentity); 32290f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 323e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani PerUserClipboard clipboard = getClipboard(); 324e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani if (clipboard.primaryClip != null && !clipboard.activePermissionOwners.contains(pkg)) { 325e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani final int N = clipboard.primaryClip.getItemCount(); 32690f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn for (int i=0; i<N; i++) { 327e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani grantItemLocked(clipboard.primaryClip.getItemAt(i), pkg); 32890f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 329e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani clipboard.activePermissionOwners.add(pkg); 33090f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 33190f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 33290f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn 33390f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn private final void revokeUriLocked(Uri uri) { 33490f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn long ident = Binder.clearCallingIdentity(); 33590f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn try { 33690f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn mAm.revokeUriPermissionFromOwner(mPermissionOwner, uri, 33790f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn Intent.FLAG_GRANT_READ_URI_PERMISSION 33890f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); 33990f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } catch (RemoteException e) { 34090f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } finally { 34190f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn Binder.restoreCallingIdentity(ident); 34290f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 34390f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 34490f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn 34590f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn private final void revokeItemLocked(ClipData.Item item) { 34690f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn if (item.getUri() != null) { 34790f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn revokeUriLocked(item.getUri()); 34890f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 34990f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn Intent intent = item.getIntent(); 35090f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn if (intent != null && intent.getData() != null) { 35190f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn revokeUriLocked(intent.getData()); 35290f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 35390f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 35490f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn 35590f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn private final void clearActiveOwnersLocked() { 356e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani PerUserClipboard clipboard = getClipboard(); 357e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani clipboard.activePermissionOwners.clear(); 358e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani if (clipboard.primaryClip == null) { 35990f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn return; 36090f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 361e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani final int N = clipboard.primaryClip.getItemCount(); 36290f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn for (int i=0; i<N; i++) { 363e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani revokeItemLocked(clipboard.primaryClip.getItemAt(i)); 36490f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 36590f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 367