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