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