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 1730f8eb472e44228069c2ffb8bd0b43213edbf04eAmith Yamasanipackage com.android.server.clipboard; 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; 26d85fc72fb810858f7502e7e7f1bad53e1bf03eddNicolas Prevotimport android.content.ContentProvider; 279f53119b72e6da865bcd53173d3dacd1eba01aeeDianne Hackbornimport android.content.IClipboard; 289f53119b72e6da865bcd53173d3dacd1eba01aeeDianne Hackbornimport android.content.IOnPrimaryClipChangedListener; 299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context; 3090f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackbornimport android.content.Intent; 31e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasaniimport android.content.IntentFilter; 32ad9833a77ff4deb5352c67800c2ee62ed6e51356Christopher Tateimport android.content.pm.IPackageManager; 3390f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackbornimport android.content.pm.PackageInfo; 3490f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackbornimport android.content.pm.PackageManager; 35f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevotimport android.content.pm.UserInfo; 3690f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackbornimport android.net.Uri; 3790f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackbornimport android.os.Binder; 3890f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackbornimport android.os.IBinder; 39f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevotimport android.os.IUserManager; 4090f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackbornimport android.os.Parcel; 4190f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackbornimport android.os.Process; 429f53119b72e6da865bcd53173d3dacd1eba01aeeDianne Hackbornimport android.os.RemoteCallbackList; 439f53119b72e6da865bcd53173d3dacd1eba01aeeDianne Hackbornimport android.os.RemoteException; 44f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevotimport android.os.ServiceManager; 45f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackbornimport android.os.UserHandle; 46f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevotimport android.os.UserManager; 4790f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackbornimport android.util.Slog; 48e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasaniimport android.util.SparseArray; 4990f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn 5090f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackbornimport java.util.HashSet; 51f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevotimport java.util.List; 529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Implementation of the clipboard for copy and paste. 559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class ClipboardService extends IClipboard.Stub { 57e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani 58e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani private static final String TAG = "ClipboardService"; 59e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani 6090f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn private final Context mContext; 6190f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn private final IActivityManager mAm; 62f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot private final IUserManager mUm; 6390f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn private final PackageManager mPm; 64efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn private final AppOpsManager mAppOps; 6590f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn private final IBinder mPermissionOwner; 6690f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn 67efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn private class ListenerInfo { 68efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn final int mUid; 69efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn final String mPackageName; 70efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn ListenerInfo(int uid, String packageName) { 71efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn mUid = uid; 72efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn mPackageName = packageName; 73efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn } 74efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn } 75efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn 76e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani private class PerUserClipboard { 77e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani final int userId; 78e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani 79e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani final RemoteCallbackList<IOnPrimaryClipChangedListener> primaryClipListeners 80e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani = new RemoteCallbackList<IOnPrimaryClipChangedListener>(); 81e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani 82e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani ClipData primaryClip; 83e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani 84e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani final HashSet<String> activePermissionOwners 85e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani = new HashSet<String>(); 869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 87e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani PerUserClipboard(int userId) { 88e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani this.userId = userId; 89e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani } 90e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani } 9190f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn 92e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani private SparseArray<PerUserClipboard> mClipboards = new SparseArray<PerUserClipboard>(); 9390f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn 949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Instantiates the clipboard. 969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 9790f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn public ClipboardService(Context context) { 9890f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn mContext = context; 9990f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn mAm = ActivityManagerNative.getDefault(); 10090f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn mPm = context.getPackageManager(); 101f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot mUm = (IUserManager) ServiceManager.getService(Context.USER_SERVICE); 102efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE); 10390f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn IBinder permOwner = null; 10490f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn try { 10590f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn permOwner = mAm.newUriPermissionOwner("clipboard"); 10690f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } catch (RemoteException e) { 10790f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn Slog.w("clipboard", "AM dead", e); 10890f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 10990f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn mPermissionOwner = permOwner; 110e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani 111e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani // Remove the clipboard if a user is removed 112e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani IntentFilter userFilter = new IntentFilter(); 113e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani userFilter.addAction(Intent.ACTION_USER_REMOVED); 114e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani mContext.registerReceiver(new BroadcastReceiver() { 115e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani @Override 116e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani public void onReceive(Context context, Intent intent) { 117e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani String action = intent.getAction(); 118e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani if (Intent.ACTION_USER_REMOVED.equals(action)) { 1192a00329c6d55c6cd9166e01963d7410e95d80d21Amith Yamasani removeClipboard(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0)); 120e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani } 121e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani } 122e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani }, userFilter); 12390f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 12490f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn 12590f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn @Override 12690f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn public boolean onTransact(int code, Parcel data, Parcel reply, int flags) 12790f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn throws RemoteException { 12890f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn try { 12990f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn return super.onTransact(code, data, reply, flags); 13090f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } catch (RuntimeException e) { 131164371fb759bad6854570af0fca60d9a01e17235Dianne Hackborn if (!(e instanceof SecurityException)) { 132164371fb759bad6854570af0fca60d9a01e17235Dianne Hackborn Slog.wtf("clipboard", "Exception: ", e); 133164371fb759bad6854570af0fca60d9a01e17235Dianne Hackborn } 13490f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn throw e; 13590f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 13690f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn 13790f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 139e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani private PerUserClipboard getClipboard() { 140f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackborn return getClipboard(UserHandle.getCallingUserId()); 141e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani } 142e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani 143e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani private PerUserClipboard getClipboard(int userId) { 144e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani synchronized (mClipboards) { 145e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani PerUserClipboard puc = mClipboards.get(userId); 146e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani if (puc == null) { 147e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani puc = new PerUserClipboard(userId); 148e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani mClipboards.put(userId, puc); 149e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani } 150e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani return puc; 151e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani } 152e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani } 153e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani 154e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani private void removeClipboard(int userId) { 155e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani synchronized (mClipboards) { 156e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani mClipboards.remove(userId); 157e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani } 158e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani } 159e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani 160efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn public void setPrimaryClip(ClipData clip, String callingPackage) { 1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project synchronized (this) { 1629f53119b72e6da865bcd53173d3dacd1eba01aeeDianne Hackborn if (clip != null && clip.getItemCount() <= 0) { 1639f53119b72e6da865bcd53173d3dacd1eba01aeeDianne Hackborn throw new IllegalArgumentException("No items"); 1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 165f0989840a00e53751241d0c97bf0e5a1866f6d4cDianne Hackborn final int callingUid = Binder.getCallingUid(); 166f0989840a00e53751241d0c97bf0e5a1866f6d4cDianne Hackborn if (mAppOps.noteOp(AppOpsManager.OP_WRITE_CLIPBOARD, callingUid, 167efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn callingPackage) != AppOpsManager.MODE_ALLOWED) { 168efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn return; 169efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn } 170f0989840a00e53751241d0c97bf0e5a1866f6d4cDianne Hackborn checkDataOwnerLocked(clip, callingUid); 171f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot final int userId = UserHandle.getUserId(callingUid); 172f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot PerUserClipboard clipboard = getClipboard(userId); 173f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot revokeUris(clipboard); 174f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot setPrimaryClipInternal(clipboard, clip); 175f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot List<UserInfo> related = getRelatedProfiles(userId); 176f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot if (related != null) { 177f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot int size = related.size(); 178f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot if (size > 1) { // Related profiles list include the current profile. 179f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot boolean canCopy = false; 180f0989840a00e53751241d0c97bf0e5a1866f6d4cDianne Hackborn try { 181f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot canCopy = !mUm.getUserRestrictions(userId).getBoolean( 182f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE); 183f0989840a00e53751241d0c97bf0e5a1866f6d4cDianne Hackborn } catch (RemoteException e) { 184f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot Slog.e(TAG, "Remote Exception calling UserManager: " + e); 185f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot } 186f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot // Copy clip data to related users if allowed. If disallowed, then remove 187f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot // primary clip in related users to prevent pasting stale content. 188f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot if (!canCopy) { 189f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot clip = null; 190f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot } else { 191f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot clip.fixUrisLight(userId); 192f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot } 193f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot for (int i = 0; i < size; i++) { 194f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot int id = related.get(i).id; 195f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot if (id != userId) { 196f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot setPrimaryClipInternal(getClipboard(id), clip); 197f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot } 198f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot } 199f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot } 200f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot } 201f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot } 202f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot } 203f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot 204f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot List<UserInfo> getRelatedProfiles(int userId) { 205f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot final List<UserInfo> related; 206f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot final long origId = Binder.clearCallingIdentity(); 207f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot try { 208f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot related = mUm.getProfiles(userId, true); 209f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot } catch (RemoteException e) { 210f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot Slog.e(TAG, "Remote Exception calling UserManager: " + e); 211f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot return null; 212f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot } finally{ 213f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot Binder.restoreCallingIdentity(origId); 214f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot } 215f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot return related; 216f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot } 217f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot 218f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot void setPrimaryClipInternal(PerUserClipboard clipboard, ClipData clip) { 219f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot clipboard.activePermissionOwners.clear(); 220f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot if (clip == null && clipboard.primaryClip == null) { 221f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot return; 222f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot } 223f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot clipboard.primaryClip = clip; 224f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot final long ident = Binder.clearCallingIdentity(); 225f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot final int n = clipboard.primaryClipListeners.beginBroadcast(); 226f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot try { 227f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot for (int i = 0; i < n; i++) { 228f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot try { 229f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot ListenerInfo li = (ListenerInfo) 230f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot clipboard.primaryClipListeners.getBroadcastCookie(i); 231f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot if (mAppOps.checkOpNoThrow(AppOpsManager.OP_READ_CLIPBOARD, li.mUid, 232f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot li.mPackageName) == AppOpsManager.MODE_ALLOWED) { 233f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot clipboard.primaryClipListeners.getBroadcastItem(i) 234f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot .dispatchPrimaryClipChanged(); 235efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn } 236f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot } catch (RemoteException e) { 237f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot // The RemoteCallbackList will take care of removing 238f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot // the dead object for us. 2399f53119b72e6da865bcd53173d3dacd1eba01aeeDianne Hackborn } 2409f53119b72e6da865bcd53173d3dacd1eba01aeeDianne Hackborn } 241f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot } finally { 242f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot clipboard.primaryClipListeners.finishBroadcast(); 243f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot Binder.restoreCallingIdentity(ident); 2449f53119b72e6da865bcd53173d3dacd1eba01aeeDianne Hackborn } 2459f53119b72e6da865bcd53173d3dacd1eba01aeeDianne Hackborn } 2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 24790f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn public ClipData getPrimaryClip(String pkg) { 2489f53119b72e6da865bcd53173d3dacd1eba01aeeDianne Hackborn synchronized (this) { 249efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn if (mAppOps.noteOp(AppOpsManager.OP_READ_CLIPBOARD, Binder.getCallingUid(), 250efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn pkg) != AppOpsManager.MODE_ALLOWED) { 251efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn return null; 252efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn } 25390f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn addActiveOwnerLocked(Binder.getCallingUid(), pkg); 254e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani return getClipboard().primaryClip; 2559f53119b72e6da865bcd53173d3dacd1eba01aeeDianne Hackborn } 2569f53119b72e6da865bcd53173d3dacd1eba01aeeDianne Hackborn } 2579f53119b72e6da865bcd53173d3dacd1eba01aeeDianne Hackborn 258efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn public ClipDescription getPrimaryClipDescription(String callingPackage) { 2591040dc465cbf5ca8f834a87c949e476abefa3f76Dianne Hackborn synchronized (this) { 260efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn if (mAppOps.checkOp(AppOpsManager.OP_READ_CLIPBOARD, Binder.getCallingUid(), 261efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn callingPackage) != AppOpsManager.MODE_ALLOWED) { 262efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn return null; 263efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn } 264e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani PerUserClipboard clipboard = getClipboard(); 265e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani return clipboard.primaryClip != null ? clipboard.primaryClip.getDescription() : null; 2661040dc465cbf5ca8f834a87c949e476abefa3f76Dianne Hackborn } 2671040dc465cbf5ca8f834a87c949e476abefa3f76Dianne Hackborn } 2681040dc465cbf5ca8f834a87c949e476abefa3f76Dianne Hackborn 269efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn public boolean hasPrimaryClip(String callingPackage) { 2709f53119b72e6da865bcd53173d3dacd1eba01aeeDianne Hackborn synchronized (this) { 271efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn if (mAppOps.checkOp(AppOpsManager.OP_READ_CLIPBOARD, Binder.getCallingUid(), 272efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn callingPackage) != AppOpsManager.MODE_ALLOWED) { 273efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn return false; 274efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn } 275e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani return getClipboard().primaryClip != null; 2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 279efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn public void addPrimaryClipChangedListener(IOnPrimaryClipChangedListener listener, 280efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn String callingPackage) { 2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project synchronized (this) { 282efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn getClipboard().primaryClipListeners.register(listener, 283efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn new ListenerInfo(Binder.getCallingUid(), callingPackage)); 2849f53119b72e6da865bcd53173d3dacd1eba01aeeDianne Hackborn } 2859f53119b72e6da865bcd53173d3dacd1eba01aeeDianne Hackborn } 2869f53119b72e6da865bcd53173d3dacd1eba01aeeDianne Hackborn 2879f53119b72e6da865bcd53173d3dacd1eba01aeeDianne Hackborn public void removePrimaryClipChangedListener(IOnPrimaryClipChangedListener listener) { 2889f53119b72e6da865bcd53173d3dacd1eba01aeeDianne Hackborn synchronized (this) { 289e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani getClipboard().primaryClipListeners.unregister(listener); 2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 293efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn public boolean hasClipboardText(String callingPackage) { 2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project synchronized (this) { 295efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn if (mAppOps.checkOp(AppOpsManager.OP_READ_CLIPBOARD, Binder.getCallingUid(), 296efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn callingPackage) != AppOpsManager.MODE_ALLOWED) { 297efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn return false; 298efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn } 299e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani PerUserClipboard clipboard = getClipboard(); 300e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani if (clipboard.primaryClip != null) { 301e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani CharSequence text = clipboard.primaryClip.getItemAt(0).getText(); 3029f53119b72e6da865bcd53173d3dacd1eba01aeeDianne Hackborn return text != null && text.length() > 0; 3039f53119b72e6da865bcd53173d3dacd1eba01aeeDianne Hackborn } 3049f53119b72e6da865bcd53173d3dacd1eba01aeeDianne Hackborn return false; 3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 30790f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn 30890f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn private final void checkUriOwnerLocked(Uri uri, int uid) { 30990f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn if (!"content".equals(uri.getScheme())) { 31090f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn return; 31190f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 31290f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn long ident = Binder.clearCallingIdentity(); 31390f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn try { 31490f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn // This will throw SecurityException for us. 315d85fc72fb810858f7502e7e7f1bad53e1bf03eddNicolas Prevot mAm.checkGrantUriPermission(uid, null, ContentProvider.getUriWithoutUserId(uri), 316f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot Intent.FLAG_GRANT_READ_URI_PERMISSION, 317f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(uid))); 31890f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } catch (RemoteException e) { 31990f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } finally { 32090f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn Binder.restoreCallingIdentity(ident); 32190f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 32290f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 32390f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn 32490f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn private final void checkItemOwnerLocked(ClipData.Item item, int uid) { 32590f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn if (item.getUri() != null) { 32690f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn checkUriOwnerLocked(item.getUri(), uid); 32790f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 32890f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn Intent intent = item.getIntent(); 32990f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn if (intent != null && intent.getData() != null) { 33090f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn checkUriOwnerLocked(intent.getData(), uid); 33190f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 33290f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 33390f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn 33490f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn private final void checkDataOwnerLocked(ClipData data, int uid) { 33590f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn final int N = data.getItemCount(); 33690f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn for (int i=0; i<N; i++) { 337327fbd2c8fa294b919475feb4c74a74ee1981e02Dianne Hackborn checkItemOwnerLocked(data.getItemAt(i), uid); 33890f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 33990f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 34090f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn 341f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot private final void grantUriLocked(Uri uri, String pkg, int userId) { 34290f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn long ident = Binder.clearCallingIdentity(); 34390f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn try { 344f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot int sourceUserId = ContentProvider.getUserIdFromUri(uri, userId); 345f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot uri = ContentProvider.getUriWithoutUserId(uri); 346d85fc72fb810858f7502e7e7f1bad53e1bf03eddNicolas Prevot mAm.grantUriPermissionFromOwner(mPermissionOwner, Process.myUid(), pkg, 347f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot uri, Intent.FLAG_GRANT_READ_URI_PERMISSION, sourceUserId, userId); 34890f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } catch (RemoteException e) { 34990f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } finally { 35090f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn Binder.restoreCallingIdentity(ident); 35190f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 35290f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 35390f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn 354f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot private final void grantItemLocked(ClipData.Item item, String pkg, int userId) { 35590f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn if (item.getUri() != null) { 356f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot grantUriLocked(item.getUri(), pkg, userId); 35790f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 35890f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn Intent intent = item.getIntent(); 35990f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn if (intent != null && intent.getData() != null) { 360f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot grantUriLocked(intent.getData(), pkg, userId); 36190f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 36290f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 36390f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn 36490f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn private final void addActiveOwnerLocked(int uid, String pkg) { 365ad9833a77ff4deb5352c67800c2ee62ed6e51356Christopher Tate final IPackageManager pm = AppGlobals.getPackageManager(); 366ad9833a77ff4deb5352c67800c2ee62ed6e51356Christopher Tate final int targetUserHandle = UserHandle.getCallingUserId(); 367ad9833a77ff4deb5352c67800c2ee62ed6e51356Christopher Tate final long oldIdentity = Binder.clearCallingIdentity(); 36890f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn try { 369ad9833a77ff4deb5352c67800c2ee62ed6e51356Christopher Tate PackageInfo pi = pm.getPackageInfo(pkg, 0, targetUserHandle); 370ad9833a77ff4deb5352c67800c2ee62ed6e51356Christopher Tate if (pi == null) { 371ad9833a77ff4deb5352c67800c2ee62ed6e51356Christopher Tate throw new IllegalArgumentException("Unknown package " + pkg); 372ad9833a77ff4deb5352c67800c2ee62ed6e51356Christopher Tate } 373f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackborn if (!UserHandle.isSameApp(pi.applicationInfo.uid, uid)) { 37490f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn throw new SecurityException("Calling uid " + uid 37590f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn + " does not own package " + pkg); 37690f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 377ad9833a77ff4deb5352c67800c2ee62ed6e51356Christopher Tate } catch (RemoteException e) { 378ad9833a77ff4deb5352c67800c2ee62ed6e51356Christopher Tate // Can't happen; the package manager is in the same process 379ad9833a77ff4deb5352c67800c2ee62ed6e51356Christopher Tate } finally { 380ad9833a77ff4deb5352c67800c2ee62ed6e51356Christopher Tate Binder.restoreCallingIdentity(oldIdentity); 38190f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 382e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani PerUserClipboard clipboard = getClipboard(); 383e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani if (clipboard.primaryClip != null && !clipboard.activePermissionOwners.contains(pkg)) { 384e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani final int N = clipboard.primaryClip.getItemCount(); 38590f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn for (int i=0; i<N; i++) { 386f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot grantItemLocked(clipboard.primaryClip.getItemAt(i), pkg, UserHandle.getUserId(uid)); 38790f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 388e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani clipboard.activePermissionOwners.add(pkg); 38990f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 39090f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 39190f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn 39290f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn private final void revokeUriLocked(Uri uri) { 393f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot int userId = ContentProvider.getUserIdFromUri(uri, 394f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot UserHandle.getUserId(Binder.getCallingUid())); 39590f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn long ident = Binder.clearCallingIdentity(); 39690f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn try { 397f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot uri = ContentProvider.getUriWithoutUserId(uri); 398f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot mAm.revokeUriPermissionFromOwner(mPermissionOwner, uri, 399d85fc72fb810858f7502e7e7f1bad53e1bf03eddNicolas Prevot Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION, 400f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot userId); 40190f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } catch (RemoteException e) { 40290f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } finally { 40390f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn Binder.restoreCallingIdentity(ident); 40490f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 40590f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 40690f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn 40790f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn private final void revokeItemLocked(ClipData.Item item) { 40890f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn if (item.getUri() != null) { 40990f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn revokeUriLocked(item.getUri()); 41090f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 41190f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn Intent intent = item.getIntent(); 41290f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn if (intent != null && intent.getData() != null) { 41390f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn revokeUriLocked(intent.getData()); 41490f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 41590f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 41690f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn 417f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot private final void revokeUris(PerUserClipboard clipboard) { 418e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani if (clipboard.primaryClip == null) { 41990f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn return; 42090f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 421e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani final int N = clipboard.primaryClip.getItemCount(); 42290f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn for (int i=0; i<N; i++) { 423e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani revokeItemLocked(clipboard.primaryClip.getItemAt(i)); 42490f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 42590f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 427