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 19dc589ac82b5fe2063f4cfd94c8ae26d43d5420a0Sudheer Shankaimport android.app.ActivityManager; 20ad9833a77ff4deb5352c67800c2ee62ed6e51356Christopher Tateimport android.app.AppGlobals; 21efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackbornimport android.app.AppOpsManager; 2290f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackbornimport android.app.IActivityManager; 231040dc465cbf5ca8f834a87c949e476abefa3f76Dianne Hackbornimport android.content.ClipData; 241040dc465cbf5ca8f834a87c949e476abefa3f76Dianne Hackbornimport android.content.ClipDescription; 25d85fc72fb810858f7502e7e7f1bad53e1bf03eddNicolas Prevotimport android.content.ContentProvider; 269f53119b72e6da865bcd53173d3dacd1eba01aeeDianne Hackbornimport android.content.IClipboard; 279f53119b72e6da865bcd53173d3dacd1eba01aeeDianne Hackbornimport android.content.IOnPrimaryClipChangedListener; 289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context; 2990f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackbornimport android.content.Intent; 30ad9833a77ff4deb5352c67800c2ee62ed6e51356Christopher Tateimport android.content.pm.IPackageManager; 3190f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackbornimport android.content.pm.PackageInfo; 3290f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackbornimport android.content.pm.PackageManager; 33f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevotimport android.content.pm.UserInfo; 3490f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackbornimport android.net.Uri; 3590f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackbornimport android.os.Binder; 3690f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackbornimport android.os.IBinder; 37f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevotimport android.os.IUserManager; 3890f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackbornimport android.os.Parcel; 3990f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackbornimport android.os.Process; 409f53119b72e6da865bcd53173d3dacd1eba01aeeDianne Hackbornimport android.os.RemoteCallbackList; 419f53119b72e6da865bcd53173d3dacd1eba01aeeDianne Hackbornimport android.os.RemoteException; 42f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevotimport android.os.ServiceManager; 4363408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyanimport android.os.SystemProperties; 44f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackbornimport android.os.UserHandle; 45f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevotimport android.os.UserManager; 4690f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackbornimport android.util.Slog; 47e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasaniimport android.util.SparseArray; 4890f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn 49ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shankaimport com.android.server.SystemService; 50ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka 5190f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackbornimport java.util.HashSet; 52f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevotimport java.util.List; 539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5463408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyanimport java.lang.Thread; 5563408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyanimport java.lang.Runnable; 5663408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyanimport java.lang.InterruptedException; 5763408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyanimport java.io.IOException; 5863408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyanimport java.io.RandomAccessFile; 5963408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan 6063408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan// The following class is Android Emulator specific. It is used to read and 6163408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan// write contents of the host system's clipboard. 6263408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyanclass HostClipboardMonitor implements Runnable { 6363408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan public interface HostClipboardCallback { 6463408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan void onHostClipboardUpdated(String contents); 6563408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan } 6663408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan 6763408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan private RandomAccessFile mPipe = null; 6863408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan private HostClipboardCallback mHostClipboardCallback; 6963408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan private static final String PIPE_NAME = "pipe:clipboard"; 7063408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan private static final String PIPE_DEVICE = "/dev/qemu_pipe"; 7163408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan 7263408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan private void openPipe() { 7363408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan try { 7463408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan // String.getBytes doesn't include the null terminator, 7563408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan // but the QEMU pipe device requires the pipe service name 7663408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan // to be null-terminated. 7763408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan byte[] b = new byte[PIPE_NAME.length() + 1]; 7863408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan b[PIPE_NAME.length()] = 0; 7963408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan System.arraycopy( 8063408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan PIPE_NAME.getBytes(), 8163408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan 0, 8263408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan b, 8363408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan 0, 8463408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan PIPE_NAME.length()); 8563408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan mPipe = new RandomAccessFile(PIPE_DEVICE, "rw"); 8663408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan mPipe.write(b); 8763408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan } catch (IOException e) { 8863408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan try { 8963408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan if (mPipe != null) mPipe.close(); 9063408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan } catch (IOException ee) {} 9163408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan mPipe = null; 9263408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan } 9363408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan } 9463408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan 9563408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan public HostClipboardMonitor(HostClipboardCallback cb) { 9663408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan mHostClipboardCallback = cb; 9763408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan } 9863408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan 9963408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan @Override 10063408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan public void run() { 10163408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan while(!Thread.interrupted()) { 10263408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan try { 10363408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan // There's no guarantee that QEMU pipes will be ready at the moment 10463408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan // this method is invoked. We simply try to get the pipe open and 10563408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan // retry on failure indefinitely. 10663408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan while (mPipe == null) { 10763408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan openPipe(); 10863408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan Thread.sleep(100); 10963408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan } 11063408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan int size = mPipe.readInt(); 11163408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan size = Integer.reverseBytes(size); 11263408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan byte[] receivedData = new byte[size]; 11363408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan mPipe.readFully(receivedData); 11463408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan mHostClipboardCallback.onHostClipboardUpdated( 11563408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan new String(receivedData)); 11663408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan } catch (IOException e) { 11763408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan try { 11863408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan mPipe.close(); 11963408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan } catch (IOException ee) {} 12063408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan mPipe = null; 12163408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan } catch (InterruptedException e) {} 12263408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan } 12363408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan } 12463408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan 12563408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan public void setHostClipboard(String content) { 12663408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan try { 12763408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan if (mPipe != null) { 12863408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan mPipe.writeInt(Integer.reverseBytes(content.getBytes().length)); 12963408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan mPipe.write(content.getBytes()); 13063408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan } 13163408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan } catch(IOException e) { 13263408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan Slog.e("HostClipboardMonitor", 13363408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan "Failed to set host clipboard " + e.getMessage()); 13463408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan } 13563408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan } 13663408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan} 13763408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan 1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Implementation of the clipboard for copy and paste. 1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 141ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shankapublic class ClipboardService extends SystemService { 142e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani 143e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani private static final String TAG = "ClipboardService"; 14463408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan private static final boolean IS_EMULATOR = 14563408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan SystemProperties.getBoolean("ro.kernel.qemu", false); 146e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani 14790f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn private final IActivityManager mAm; 148f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot private final IUserManager mUm; 14990f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn private final PackageManager mPm; 150efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn private final AppOpsManager mAppOps; 15190f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn private final IBinder mPermissionOwner; 15263408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan private HostClipboardMonitor mHostClipboardMonitor = null; 15363408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan private Thread mHostMonitorThread = null; 15490f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn 155ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka private final SparseArray<PerUserClipboard> mClipboards = new SparseArray<>(); 156ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka 157ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka /** 158ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka * Instantiates the clipboard. 159ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka */ 160ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka public ClipboardService(Context context) { 161ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka super(context); 162ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka 163dc589ac82b5fe2063f4cfd94c8ae26d43d5420a0Sudheer Shanka mAm = ActivityManager.getService(); 164ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka mPm = getContext().getPackageManager(); 165ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka mUm = (IUserManager) ServiceManager.getService(Context.USER_SERVICE); 166ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE); 167ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka IBinder permOwner = null; 168ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka try { 169ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka permOwner = mAm.newUriPermissionOwner("clipboard"); 170ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka } catch (RemoteException e) { 171ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka Slog.w("clipboard", "AM dead", e); 172ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka } 173ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka mPermissionOwner = permOwner; 17463408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan if (IS_EMULATOR) { 17563408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan mHostClipboardMonitor = new HostClipboardMonitor( 17663408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan new HostClipboardMonitor.HostClipboardCallback() { 17763408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan @Override 17863408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan public void onHostClipboardUpdated(String contents){ 17963408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan ClipData clip = 18063408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan new ClipData("host clipboard", 18163408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan new String[]{"text/plain"}, 18263408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan new ClipData.Item(contents)); 18363408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan synchronized(mClipboards) { 18463408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan setPrimaryClipInternal(getClipboard(0), clip); 18563408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan } 18663408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan } 18763408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan }); 18863408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan mHostMonitorThread = new Thread(mHostClipboardMonitor); 18963408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan mHostMonitorThread.start(); 19063408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan } 191ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka } 192ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka 193ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka @Override 194ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka public void onStart() { 195ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka publishBinderService(Context.CLIPBOARD_SERVICE, new ClipboardImpl()); 196ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka } 197ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka 198ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka @Override 199ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka public void onCleanupUser(int userId) { 200ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka synchronized (mClipboards) { 201ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka mClipboards.remove(userId); 202ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka } 203ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka } 204ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka 205efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn private class ListenerInfo { 206efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn final int mUid; 207efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn final String mPackageName; 208efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn ListenerInfo(int uid, String packageName) { 209efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn mUid = uid; 210efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn mPackageName = packageName; 211efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn } 212efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn } 213efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn 214e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani private class PerUserClipboard { 215e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani final int userId; 216e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani 217e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani final RemoteCallbackList<IOnPrimaryClipChangedListener> primaryClipListeners 218e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani = new RemoteCallbackList<IOnPrimaryClipChangedListener>(); 219e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani 220e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani ClipData primaryClip; 221e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani 222e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani final HashSet<String> activePermissionOwners 223e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani = new HashSet<String>(); 2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 225e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani PerUserClipboard(int userId) { 226e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani this.userId = userId; 227e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani } 228e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani } 22990f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn 230ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka private class ClipboardImpl extends IClipboard.Stub { 231ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka @Override 232ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka public boolean onTransact(int code, Parcel data, Parcel reply, int flags) 233ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka throws RemoteException { 234ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka try { 235ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka return super.onTransact(code, data, reply, flags); 236ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka } catch (RuntimeException e) { 237ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka if (!(e instanceof SecurityException)) { 238ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka Slog.wtf("clipboard", "Exception: ", e); 239ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka } 240ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka throw e; 241ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka } 24290f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn 24390f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 244e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani 245ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka @Override 246ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka public void setPrimaryClip(ClipData clip, String callingPackage) { 247ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka synchronized (this) { 248ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka if (clip != null && clip.getItemCount() <= 0) { 249ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka throw new IllegalArgumentException("No items"); 250ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka } 25163408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan if (clip.getItemAt(0).getText() != null && 25263408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan mHostClipboardMonitor != null) { 25363408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan mHostClipboardMonitor.setHostClipboard( 25463408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan clip.getItemAt(0).getText().toString()); 25563408e643af0ae53ed6d7928e4f4e24624338d0aGrigory Dzhavadyan } 256ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka final int callingUid = Binder.getCallingUid(); 25734ffba62b351abf4710a9e64ed345658d2069c37Chad Brubaker if (!clipboardAccessAllowed(AppOpsManager.OP_WRITE_CLIPBOARD, callingPackage, 25834ffba62b351abf4710a9e64ed345658d2069c37Chad Brubaker callingUid)) { 259ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka return; 260ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka } 261ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka checkDataOwnerLocked(clip, callingUid); 262ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka final int userId = UserHandle.getUserId(callingUid); 263ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka PerUserClipboard clipboard = getClipboard(userId); 264ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka revokeUris(clipboard); 265ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka setPrimaryClipInternal(clipboard, clip); 266ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka List<UserInfo> related = getRelatedProfiles(userId); 267ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka if (related != null) { 268ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka int size = related.size(); 269ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka if (size > 1) { // Related profiles list include the current profile. 270ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka boolean canCopy = false; 271ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka try { 272ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka canCopy = !mUm.getUserRestrictions(userId).getBoolean( 273ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE); 274ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka } catch (RemoteException e) { 275ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka Slog.e(TAG, "Remote Exception calling UserManager: " + e); 276ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka } 277ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka // Copy clip data to related users if allowed. If disallowed, then remove 278ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka // primary clip in related users to prevent pasting stale content. 279ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka if (!canCopy) { 280ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka clip = null; 281ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka } else { 282ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka // We want to fix the uris of the related user's clip without changing the 283ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka // uris of the current user's clip. 284ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka // So, copy the ClipData, and then copy all the items, so that nothing 285ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka // is shared in memmory. 286ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka clip = new ClipData(clip); 287ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka for (int i = clip.getItemCount() - 1; i >= 0; i--) { 288ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka clip.setItemAt(i, new ClipData.Item(clip.getItemAt(i))); 289ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka } 290ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka clip.fixUrisLight(userId); 291ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka } 292ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka for (int i = 0; i < size; i++) { 293ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka int id = related.get(i).id; 294ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka if (id != userId) { 295ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka setPrimaryClipInternal(getClipboard(id), clip); 296ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka } 297ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka } 298ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka } 299ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka } 300ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka } 301ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka } 302ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka 303ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka @Override 304ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka public ClipData getPrimaryClip(String pkg) { 305ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka synchronized (this) { 30634ffba62b351abf4710a9e64ed345658d2069c37Chad Brubaker if (!clipboardAccessAllowed(AppOpsManager.OP_READ_CLIPBOARD, pkg, 30734ffba62b351abf4710a9e64ed345658d2069c37Chad Brubaker Binder.getCallingUid())) { 308ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka return null; 309e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani } 310ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka addActiveOwnerLocked(Binder.getCallingUid(), pkg); 311ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka return getClipboard().primaryClip; 312e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani } 313ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka } 31490f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn 315ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka @Override 316ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka public ClipDescription getPrimaryClipDescription(String callingPackage) { 317ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka synchronized (this) { 31834ffba62b351abf4710a9e64ed345658d2069c37Chad Brubaker if (!clipboardAccessAllowed(AppOpsManager.OP_READ_CLIPBOARD, callingPackage, 31934ffba62b351abf4710a9e64ed345658d2069c37Chad Brubaker Binder.getCallingUid())) { 320ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka return null; 321ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka } 322ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka PerUserClipboard clipboard = getClipboard(); 323ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka return clipboard.primaryClip != null ? clipboard.primaryClip.getDescription() : null; 324164371fb759bad6854570af0fca60d9a01e17235Dianne Hackborn } 32590f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 326ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka 327ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka @Override 328ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka public boolean hasPrimaryClip(String callingPackage) { 329ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka synchronized (this) { 33034ffba62b351abf4710a9e64ed345658d2069c37Chad Brubaker if (!clipboardAccessAllowed(AppOpsManager.OP_READ_CLIPBOARD, callingPackage, 33134ffba62b351abf4710a9e64ed345658d2069c37Chad Brubaker Binder.getCallingUid())) { 332ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka return false; 333ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka } 334ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka return getClipboard().primaryClip != null; 335ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka } 336ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka } 337ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka 338ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka @Override 339ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka public void addPrimaryClipChangedListener(IOnPrimaryClipChangedListener listener, 340ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka String callingPackage) { 341ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka synchronized (this) { 342ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka getClipboard().primaryClipListeners.register(listener, 343ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka new ListenerInfo(Binder.getCallingUid(), callingPackage)); 344ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka } 345ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka } 346ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka 347ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka @Override 348ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka public void removePrimaryClipChangedListener(IOnPrimaryClipChangedListener listener) { 349ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka synchronized (this) { 350ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka getClipboard().primaryClipListeners.unregister(listener); 351ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka } 352ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka } 353ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka 354ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka @Override 355ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka public boolean hasClipboardText(String callingPackage) { 356ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka synchronized (this) { 35734ffba62b351abf4710a9e64ed345658d2069c37Chad Brubaker if (!clipboardAccessAllowed(AppOpsManager.OP_READ_CLIPBOARD, callingPackage, 35834ffba62b351abf4710a9e64ed345658d2069c37Chad Brubaker Binder.getCallingUid())) { 359ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka return false; 360ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka } 361ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka PerUserClipboard clipboard = getClipboard(); 362ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka if (clipboard.primaryClip != null) { 363ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka CharSequence text = clipboard.primaryClip.getItemAt(0).getText(); 364ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka return text != null && text.length() > 0; 365ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka } 366ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka return false; 367ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka } 368ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka } 369ad70bc6c310f54d4810e67b49e7881c1f33a1d83Sudheer Shanka }; 3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 371e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani private PerUserClipboard getClipboard() { 372f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackborn return getClipboard(UserHandle.getCallingUserId()); 373e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani } 374e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani 375e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani private PerUserClipboard getClipboard(int userId) { 376e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani synchronized (mClipboards) { 377e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani PerUserClipboard puc = mClipboards.get(userId); 378e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani if (puc == null) { 379e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani puc = new PerUserClipboard(userId); 380e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani mClipboards.put(userId, puc); 381e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani } 382e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani return puc; 383e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani } 384e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani } 385e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani 386f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot List<UserInfo> getRelatedProfiles(int userId) { 387f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot final List<UserInfo> related; 388f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot final long origId = Binder.clearCallingIdentity(); 389f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot try { 390f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot related = mUm.getProfiles(userId, true); 391f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot } catch (RemoteException e) { 392f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot Slog.e(TAG, "Remote Exception calling UserManager: " + e); 393f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot return null; 394f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot } finally{ 395f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot Binder.restoreCallingIdentity(origId); 396f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot } 397f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot return related; 398f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot } 399f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot 400f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot void setPrimaryClipInternal(PerUserClipboard clipboard, ClipData clip) { 401f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot clipboard.activePermissionOwners.clear(); 402f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot if (clip == null && clipboard.primaryClip == null) { 403f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot return; 404f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot } 405f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot clipboard.primaryClip = clip; 406fe4d1e87ab4d0ae4649f3a127804c4f66d7ef8abSudheer Shanka if (clip != null) { 407fe4d1e87ab4d0ae4649f3a127804c4f66d7ef8abSudheer Shanka final ClipDescription description = clip.getDescription(); 408fe4d1e87ab4d0ae4649f3a127804c4f66d7ef8abSudheer Shanka if (description != null) { 409c8201910613a374e9c075c64dca2a0fe377250d0Sudheer Shanka description.setTimestamp(System.currentTimeMillis()); 410fe4d1e87ab4d0ae4649f3a127804c4f66d7ef8abSudheer Shanka } 41109971befd7e5eb506eca65afd61bd9248b78c723Sudheer Shanka } 412f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot final long ident = Binder.clearCallingIdentity(); 413f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot final int n = clipboard.primaryClipListeners.beginBroadcast(); 414f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot try { 415f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot for (int i = 0; i < n; i++) { 416f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot try { 417f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot ListenerInfo li = (ListenerInfo) 418f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot clipboard.primaryClipListeners.getBroadcastCookie(i); 41934ffba62b351abf4710a9e64ed345658d2069c37Chad Brubaker 42034ffba62b351abf4710a9e64ed345658d2069c37Chad Brubaker if (clipboardAccessAllowed(AppOpsManager.OP_READ_CLIPBOARD, li.mPackageName, 42134ffba62b351abf4710a9e64ed345658d2069c37Chad Brubaker li.mUid)) { 422f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot clipboard.primaryClipListeners.getBroadcastItem(i) 423f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot .dispatchPrimaryClipChanged(); 424efcc1a23a1f731390ef8506b3536b9562d18ed78Dianne Hackborn } 425f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot } catch (RemoteException e) { 426f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot // The RemoteCallbackList will take care of removing 427f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot // the dead object for us. 4289f53119b72e6da865bcd53173d3dacd1eba01aeeDianne Hackborn } 4299f53119b72e6da865bcd53173d3dacd1eba01aeeDianne Hackborn } 430f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot } finally { 431f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot clipboard.primaryClipListeners.finishBroadcast(); 432f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot Binder.restoreCallingIdentity(ident); 4339f53119b72e6da865bcd53173d3dacd1eba01aeeDianne Hackborn } 4349f53119b72e6da865bcd53173d3dacd1eba01aeeDianne Hackborn } 43590f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn 43690f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn private final void checkUriOwnerLocked(Uri uri, int uid) { 43790f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn if (!"content".equals(uri.getScheme())) { 43890f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn return; 43990f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 44090f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn long ident = Binder.clearCallingIdentity(); 44190f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn try { 44290f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn // This will throw SecurityException for us. 443d85fc72fb810858f7502e7e7f1bad53e1bf03eddNicolas Prevot mAm.checkGrantUriPermission(uid, null, ContentProvider.getUriWithoutUserId(uri), 444f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot Intent.FLAG_GRANT_READ_URI_PERMISSION, 445f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(uid))); 44690f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } catch (RemoteException e) { 44790f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } finally { 44890f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn Binder.restoreCallingIdentity(ident); 44990f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 45090f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 45190f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn 45290f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn private final void checkItemOwnerLocked(ClipData.Item item, int uid) { 45390f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn if (item.getUri() != null) { 45490f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn checkUriOwnerLocked(item.getUri(), uid); 45590f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 45690f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn Intent intent = item.getIntent(); 45790f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn if (intent != null && intent.getData() != null) { 45890f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn checkUriOwnerLocked(intent.getData(), uid); 45990f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 46090f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 46190f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn 46290f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn private final void checkDataOwnerLocked(ClipData data, int uid) { 46390f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn final int N = data.getItemCount(); 46490f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn for (int i=0; i<N; i++) { 465327fbd2c8fa294b919475feb4c74a74ee1981e02Dianne Hackborn checkItemOwnerLocked(data.getItemAt(i), uid); 46690f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 46790f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 46890f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn 469f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot private final void grantUriLocked(Uri uri, String pkg, int userId) { 47090f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn long ident = Binder.clearCallingIdentity(); 47190f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn try { 472f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot int sourceUserId = ContentProvider.getUserIdFromUri(uri, userId); 473f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot uri = ContentProvider.getUriWithoutUserId(uri); 474d85fc72fb810858f7502e7e7f1bad53e1bf03eddNicolas Prevot mAm.grantUriPermissionFromOwner(mPermissionOwner, Process.myUid(), pkg, 475f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot uri, Intent.FLAG_GRANT_READ_URI_PERMISSION, sourceUserId, userId); 47690f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } catch (RemoteException e) { 47790f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } finally { 47890f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn Binder.restoreCallingIdentity(ident); 47990f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 48090f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 48190f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn 482f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot private final void grantItemLocked(ClipData.Item item, String pkg, int userId) { 48390f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn if (item.getUri() != null) { 484f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot grantUriLocked(item.getUri(), pkg, userId); 48590f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 48690f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn Intent intent = item.getIntent(); 48790f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn if (intent != null && intent.getData() != null) { 488f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot grantUriLocked(intent.getData(), pkg, userId); 48990f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 49090f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 49190f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn 49290f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn private final void addActiveOwnerLocked(int uid, String pkg) { 493ad9833a77ff4deb5352c67800c2ee62ed6e51356Christopher Tate final IPackageManager pm = AppGlobals.getPackageManager(); 494ad9833a77ff4deb5352c67800c2ee62ed6e51356Christopher Tate final int targetUserHandle = UserHandle.getCallingUserId(); 495ad9833a77ff4deb5352c67800c2ee62ed6e51356Christopher Tate final long oldIdentity = Binder.clearCallingIdentity(); 49690f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn try { 497ad9833a77ff4deb5352c67800c2ee62ed6e51356Christopher Tate PackageInfo pi = pm.getPackageInfo(pkg, 0, targetUserHandle); 498ad9833a77ff4deb5352c67800c2ee62ed6e51356Christopher Tate if (pi == null) { 499ad9833a77ff4deb5352c67800c2ee62ed6e51356Christopher Tate throw new IllegalArgumentException("Unknown package " + pkg); 500ad9833a77ff4deb5352c67800c2ee62ed6e51356Christopher Tate } 501f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackborn if (!UserHandle.isSameApp(pi.applicationInfo.uid, uid)) { 50290f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn throw new SecurityException("Calling uid " + uid 50390f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn + " does not own package " + pkg); 50490f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 505ad9833a77ff4deb5352c67800c2ee62ed6e51356Christopher Tate } catch (RemoteException e) { 506ad9833a77ff4deb5352c67800c2ee62ed6e51356Christopher Tate // Can't happen; the package manager is in the same process 507ad9833a77ff4deb5352c67800c2ee62ed6e51356Christopher Tate } finally { 508ad9833a77ff4deb5352c67800c2ee62ed6e51356Christopher Tate Binder.restoreCallingIdentity(oldIdentity); 50990f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 510e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani PerUserClipboard clipboard = getClipboard(); 511e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani if (clipboard.primaryClip != null && !clipboard.activePermissionOwners.contains(pkg)) { 512e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani final int N = clipboard.primaryClip.getItemCount(); 51390f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn for (int i=0; i<N; i++) { 514f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot grantItemLocked(clipboard.primaryClip.getItemAt(i), pkg, UserHandle.getUserId(uid)); 51590f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 516e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani clipboard.activePermissionOwners.add(pkg); 51790f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 51890f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 51990f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn 52090f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn private final void revokeUriLocked(Uri uri) { 521f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot int userId = ContentProvider.getUserIdFromUri(uri, 522f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot UserHandle.getUserId(Binder.getCallingUid())); 52390f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn long ident = Binder.clearCallingIdentity(); 52490f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn try { 525f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot uri = ContentProvider.getUriWithoutUserId(uri); 526f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot mAm.revokeUriPermissionFromOwner(mPermissionOwner, uri, 527d85fc72fb810858f7502e7e7f1bad53e1bf03eddNicolas Prevot Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION, 528f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot userId); 52990f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } catch (RemoteException e) { 53090f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } finally { 53190f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn Binder.restoreCallingIdentity(ident); 53290f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 53390f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 53490f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn 53590f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn private final void revokeItemLocked(ClipData.Item item) { 53690f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn if (item.getUri() != null) { 53790f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn revokeUriLocked(item.getUri()); 53890f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 53990f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn Intent intent = item.getIntent(); 54090f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn if (intent != null && intent.getData() != null) { 54190f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn revokeUriLocked(intent.getData()); 54290f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 54390f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 54490f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn 545f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot private final void revokeUris(PerUserClipboard clipboard) { 546e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani if (clipboard.primaryClip == null) { 54790f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn return; 54890f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 549e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani final int N = clipboard.primaryClip.getItemCount(); 55090f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn for (int i=0; i<N; i++) { 551e9e26cc727a1490db5eb0e572a40913f624529feAmith Yamasani revokeItemLocked(clipboard.primaryClip.getItemAt(i)); 55290f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 55390f4aafa336d9f2f07281ead3c846d323a710015Dianne Hackborn } 55434ffba62b351abf4710a9e64ed345658d2069c37Chad Brubaker 55534ffba62b351abf4710a9e64ed345658d2069c37Chad Brubaker private boolean clipboardAccessAllowed(int op, String callingPackage, int callingUid) { 55634ffba62b351abf4710a9e64ed345658d2069c37Chad Brubaker // Check the AppOp. 55734ffba62b351abf4710a9e64ed345658d2069c37Chad Brubaker if (mAppOps.checkOp(op, callingUid, callingPackage) != AppOpsManager.MODE_ALLOWED) { 55834ffba62b351abf4710a9e64ed345658d2069c37Chad Brubaker return false; 55934ffba62b351abf4710a9e64ed345658d2069c37Chad Brubaker } 56034ffba62b351abf4710a9e64ed345658d2069c37Chad Brubaker try { 56134ffba62b351abf4710a9e64ed345658d2069c37Chad Brubaker // Installed apps can access the clipboard at any time. 56234ffba62b351abf4710a9e64ed345658d2069c37Chad Brubaker if (!AppGlobals.getPackageManager().isInstantApp(callingPackage, 56334ffba62b351abf4710a9e64ed345658d2069c37Chad Brubaker UserHandle.getUserId(callingUid))) { 56434ffba62b351abf4710a9e64ed345658d2069c37Chad Brubaker return true; 56534ffba62b351abf4710a9e64ed345658d2069c37Chad Brubaker } 56634ffba62b351abf4710a9e64ed345658d2069c37Chad Brubaker // Instant apps can only access the clipboard if they are in the foreground. 56734ffba62b351abf4710a9e64ed345658d2069c37Chad Brubaker return mAm.isAppForeground(callingUid); 56834ffba62b351abf4710a9e64ed345658d2069c37Chad Brubaker } catch (RemoteException e) { 56934ffba62b351abf4710a9e64ed345658d2069c37Chad Brubaker Slog.e("clipboard", "Failed to get Instant App status for package " + callingPackage, 57034ffba62b351abf4710a9e64ed345658d2069c37Chad Brubaker e); 57134ffba62b351abf4710a9e64ed345658d2069c37Chad Brubaker return false; 57234ffba62b351abf4710a9e64ed345658d2069c37Chad Brubaker } 57334ffba62b351abf4710a9e64ed345658d2069c37Chad Brubaker } 5749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 575