blob: db72c5e4cbab617d24aa7e00b68e6a8e1056ca50 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Amith Yamasani30f8eb42013-11-06 14:54:50 -080017package com.android.server.clipboard;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080018
Sudheer Shankadc589ac2016-11-10 15:30:17 -080019import android.app.ActivityManager;
Christopher Tatead9833a2012-09-14 13:34:17 -070020import android.app.AppGlobals;
Dianne Hackbornefcc1a22013-02-25 18:02:35 -080021import android.app.AppOpsManager;
Dianne Hackborn90f4aaf2010-09-27 14:58:44 -070022import android.app.IActivityManager;
Dianne Hackborn1040dc42010-08-26 22:11:06 -070023import android.content.ClipData;
24import android.content.ClipDescription;
Nicolas Prevotd85fc722014-04-16 19:52:08 +010025import android.content.ContentProvider;
Dianne Hackborn9f531192010-08-04 17:48:03 -070026import android.content.IClipboard;
27import android.content.IOnPrimaryClipChangedListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028import android.content.Context;
Dianne Hackborn90f4aaf2010-09-27 14:58:44 -070029import android.content.Intent;
Christopher Tatead9833a2012-09-14 13:34:17 -070030import android.content.pm.IPackageManager;
Dianne Hackborn90f4aaf2010-09-27 14:58:44 -070031import android.content.pm.PackageInfo;
32import android.content.pm.PackageManager;
Nicolas Prevotf1939902014-06-25 09:29:02 +010033import android.content.pm.UserInfo;
Dianne Hackborn90f4aaf2010-09-27 14:58:44 -070034import android.net.Uri;
35import android.os.Binder;
36import android.os.IBinder;
Nicolas Prevotf1939902014-06-25 09:29:02 +010037import android.os.IUserManager;
Dianne Hackborn90f4aaf2010-09-27 14:58:44 -070038import android.os.Parcel;
39import android.os.Process;
Dianne Hackborn9f531192010-08-04 17:48:03 -070040import android.os.RemoteCallbackList;
41import android.os.RemoteException;
Nicolas Prevotf1939902014-06-25 09:29:02 +010042import android.os.ServiceManager;
Grigory Dzhavadyan63408e642016-11-03 21:39:26 +000043import android.os.SystemProperties;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070044import android.os.UserHandle;
Nicolas Prevotf1939902014-06-25 09:29:02 +010045import android.os.UserManager;
Dianne Hackborn90f4aaf2010-09-27 14:58:44 -070046import android.util.Slog;
Amith Yamasanie9e26cc2012-04-20 19:01:50 -070047import android.util.SparseArray;
Dianne Hackborn90f4aaf2010-09-27 14:58:44 -070048
Sudheer Shankaad70bc62016-09-29 12:58:04 -070049import com.android.server.SystemService;
50
Dianne Hackborn90f4aaf2010-09-27 14:58:44 -070051import java.util.HashSet;
Nicolas Prevotf1939902014-06-25 09:29:02 +010052import java.util.List;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053
Grigory Dzhavadyan63408e642016-11-03 21:39:26 +000054import java.lang.Thread;
55import java.lang.Runnable;
56import java.lang.InterruptedException;
57import java.io.IOException;
58import java.io.RandomAccessFile;
59
60// The following class is Android Emulator specific. It is used to read and
61// write contents of the host system's clipboard.
62class HostClipboardMonitor implements Runnable {
63 public interface HostClipboardCallback {
64 void onHostClipboardUpdated(String contents);
65 }
66
67 private RandomAccessFile mPipe = null;
68 private HostClipboardCallback mHostClipboardCallback;
69 private static final String PIPE_NAME = "pipe:clipboard";
70 private static final String PIPE_DEVICE = "/dev/qemu_pipe";
71
72 private void openPipe() {
73 try {
74 // String.getBytes doesn't include the null terminator,
75 // but the QEMU pipe device requires the pipe service name
76 // to be null-terminated.
77 byte[] b = new byte[PIPE_NAME.length() + 1];
78 b[PIPE_NAME.length()] = 0;
79 System.arraycopy(
80 PIPE_NAME.getBytes(),
81 0,
82 b,
83 0,
84 PIPE_NAME.length());
85 mPipe = new RandomAccessFile(PIPE_DEVICE, "rw");
86 mPipe.write(b);
87 } catch (IOException e) {
88 try {
89 if (mPipe != null) mPipe.close();
90 } catch (IOException ee) {}
91 mPipe = null;
92 }
93 }
94
95 public HostClipboardMonitor(HostClipboardCallback cb) {
96 mHostClipboardCallback = cb;
97 }
98
99 @Override
100 public void run() {
101 while(!Thread.interrupted()) {
102 try {
103 // There's no guarantee that QEMU pipes will be ready at the moment
104 // this method is invoked. We simply try to get the pipe open and
105 // retry on failure indefinitely.
106 while (mPipe == null) {
107 openPipe();
108 Thread.sleep(100);
109 }
110 int size = mPipe.readInt();
111 size = Integer.reverseBytes(size);
112 byte[] receivedData = new byte[size];
113 mPipe.readFully(receivedData);
114 mHostClipboardCallback.onHostClipboardUpdated(
115 new String(receivedData));
116 } catch (IOException e) {
117 try {
118 mPipe.close();
119 } catch (IOException ee) {}
120 mPipe = null;
121 } catch (InterruptedException e) {}
122 }
123 }
124
125 public void setHostClipboard(String content) {
126 try {
127 if (mPipe != null) {
128 mPipe.writeInt(Integer.reverseBytes(content.getBytes().length));
129 mPipe.write(content.getBytes());
130 }
131 } catch(IOException e) {
132 Slog.e("HostClipboardMonitor",
133 "Failed to set host clipboard " + e.getMessage());
134 }
135 }
136}
137
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800138/**
139 * Implementation of the clipboard for copy and paste.
140 */
Sudheer Shankaad70bc62016-09-29 12:58:04 -0700141public class ClipboardService extends SystemService {
Amith Yamasanie9e26cc2012-04-20 19:01:50 -0700142
143 private static final String TAG = "ClipboardService";
Grigory Dzhavadyan63408e642016-11-03 21:39:26 +0000144 private static final boolean IS_EMULATOR =
145 SystemProperties.getBoolean("ro.kernel.qemu", false);
Amith Yamasanie9e26cc2012-04-20 19:01:50 -0700146
Dianne Hackborn90f4aaf2010-09-27 14:58:44 -0700147 private final IActivityManager mAm;
Nicolas Prevotf1939902014-06-25 09:29:02 +0100148 private final IUserManager mUm;
Dianne Hackborn90f4aaf2010-09-27 14:58:44 -0700149 private final PackageManager mPm;
Dianne Hackbornefcc1a22013-02-25 18:02:35 -0800150 private final AppOpsManager mAppOps;
Dianne Hackborn90f4aaf2010-09-27 14:58:44 -0700151 private final IBinder mPermissionOwner;
Grigory Dzhavadyan63408e642016-11-03 21:39:26 +0000152 private HostClipboardMonitor mHostClipboardMonitor = null;
153 private Thread mHostMonitorThread = null;
Dianne Hackborn90f4aaf2010-09-27 14:58:44 -0700154
Sudheer Shankaad70bc62016-09-29 12:58:04 -0700155 private final SparseArray<PerUserClipboard> mClipboards = new SparseArray<>();
156
157 /**
158 * Instantiates the clipboard.
159 */
160 public ClipboardService(Context context) {
161 super(context);
162
Sudheer Shankadc589ac2016-11-10 15:30:17 -0800163 mAm = ActivityManager.getService();
Sudheer Shankaad70bc62016-09-29 12:58:04 -0700164 mPm = getContext().getPackageManager();
165 mUm = (IUserManager) ServiceManager.getService(Context.USER_SERVICE);
166 mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
167 IBinder permOwner = null;
168 try {
169 permOwner = mAm.newUriPermissionOwner("clipboard");
170 } catch (RemoteException e) {
171 Slog.w("clipboard", "AM dead", e);
172 }
173 mPermissionOwner = permOwner;
Grigory Dzhavadyan63408e642016-11-03 21:39:26 +0000174 if (IS_EMULATOR) {
175 mHostClipboardMonitor = new HostClipboardMonitor(
176 new HostClipboardMonitor.HostClipboardCallback() {
177 @Override
178 public void onHostClipboardUpdated(String contents){
179 ClipData clip =
180 new ClipData("host clipboard",
181 new String[]{"text/plain"},
182 new ClipData.Item(contents));
183 synchronized(mClipboards) {
184 setPrimaryClipInternal(getClipboard(0), clip);
185 }
186 }
187 });
188 mHostMonitorThread = new Thread(mHostClipboardMonitor);
189 mHostMonitorThread.start();
190 }
Sudheer Shankaad70bc62016-09-29 12:58:04 -0700191 }
192
193 @Override
194 public void onStart() {
195 publishBinderService(Context.CLIPBOARD_SERVICE, new ClipboardImpl());
196 }
197
198 @Override
199 public void onCleanupUser(int userId) {
200 synchronized (mClipboards) {
201 mClipboards.remove(userId);
202 }
203 }
204
Dianne Hackbornefcc1a22013-02-25 18:02:35 -0800205 private class ListenerInfo {
206 final int mUid;
207 final String mPackageName;
208 ListenerInfo(int uid, String packageName) {
209 mUid = uid;
210 mPackageName = packageName;
211 }
212 }
213
Amith Yamasanie9e26cc2012-04-20 19:01:50 -0700214 private class PerUserClipboard {
215 final int userId;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800216
Amith Yamasanie9e26cc2012-04-20 19:01:50 -0700217 final RemoteCallbackList<IOnPrimaryClipChangedListener> primaryClipListeners
218 = new RemoteCallbackList<IOnPrimaryClipChangedListener>();
Dianne Hackborn90f4aaf2010-09-27 14:58:44 -0700219
Amith Yamasanie9e26cc2012-04-20 19:01:50 -0700220 ClipData primaryClip;
221
222 final HashSet<String> activePermissionOwners
223 = new HashSet<String>();
224
225 PerUserClipboard(int userId) {
226 this.userId = userId;
227 }
228 }
229
Sudheer Shankaad70bc62016-09-29 12:58:04 -0700230 private class ClipboardImpl extends IClipboard.Stub {
231 @Override
232 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
233 throws RemoteException {
234 try {
235 return super.onTransact(code, data, reply, flags);
236 } catch (RuntimeException e) {
237 if (!(e instanceof SecurityException)) {
238 Slog.wtf("clipboard", "Exception: ", e);
239 }
240 throw e;
241 }
Dianne Hackborn90f4aaf2010-09-27 14:58:44 -0700242
Dianne Hackborn90f4aaf2010-09-27 14:58:44 -0700243 }
Amith Yamasanie9e26cc2012-04-20 19:01:50 -0700244
Sudheer Shankaad70bc62016-09-29 12:58:04 -0700245 @Override
246 public void setPrimaryClip(ClipData clip, String callingPackage) {
247 synchronized (this) {
248 if (clip != null && clip.getItemCount() <= 0) {
249 throw new IllegalArgumentException("No items");
250 }
Grigory Dzhavadyan63408e642016-11-03 21:39:26 +0000251 if (clip.getItemAt(0).getText() != null &&
252 mHostClipboardMonitor != null) {
253 mHostClipboardMonitor.setHostClipboard(
254 clip.getItemAt(0).getText().toString());
255 }
Sudheer Shankaad70bc62016-09-29 12:58:04 -0700256 final int callingUid = Binder.getCallingUid();
Chad Brubaker34ffba62017-03-02 15:56:43 -0800257 if (!clipboardAccessAllowed(AppOpsManager.OP_WRITE_CLIPBOARD, callingPackage,
258 callingUid)) {
Sudheer Shankaad70bc62016-09-29 12:58:04 -0700259 return;
260 }
261 checkDataOwnerLocked(clip, callingUid);
262 final int userId = UserHandle.getUserId(callingUid);
263 PerUserClipboard clipboard = getClipboard(userId);
264 revokeUris(clipboard);
265 setPrimaryClipInternal(clipboard, clip);
266 List<UserInfo> related = getRelatedProfiles(userId);
267 if (related != null) {
268 int size = related.size();
269 if (size > 1) { // Related profiles list include the current profile.
270 boolean canCopy = false;
271 try {
272 canCopy = !mUm.getUserRestrictions(userId).getBoolean(
273 UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE);
274 } catch (RemoteException e) {
275 Slog.e(TAG, "Remote Exception calling UserManager: " + e);
276 }
277 // Copy clip data to related users if allowed. If disallowed, then remove
278 // primary clip in related users to prevent pasting stale content.
279 if (!canCopy) {
280 clip = null;
281 } else {
282 // We want to fix the uris of the related user's clip without changing the
283 // uris of the current user's clip.
284 // So, copy the ClipData, and then copy all the items, so that nothing
285 // is shared in memmory.
286 clip = new ClipData(clip);
287 for (int i = clip.getItemCount() - 1; i >= 0; i--) {
288 clip.setItemAt(i, new ClipData.Item(clip.getItemAt(i)));
289 }
290 clip.fixUrisLight(userId);
291 }
292 for (int i = 0; i < size; i++) {
293 int id = related.get(i).id;
294 if (id != userId) {
295 setPrimaryClipInternal(getClipboard(id), clip);
296 }
297 }
298 }
Amith Yamasanie9e26cc2012-04-20 19:01:50 -0700299 }
300 }
Dianne Hackborn90f4aaf2010-09-27 14:58:44 -0700301 }
Sudheer Shankaad70bc62016-09-29 12:58:04 -0700302
303 @Override
304 public ClipData getPrimaryClip(String pkg) {
305 synchronized (this) {
Chad Brubaker34ffba62017-03-02 15:56:43 -0800306 if (!clipboardAccessAllowed(AppOpsManager.OP_READ_CLIPBOARD, pkg,
307 Binder.getCallingUid())) {
Sudheer Shankaad70bc62016-09-29 12:58:04 -0700308 return null;
309 }
310 addActiveOwnerLocked(Binder.getCallingUid(), pkg);
311 return getClipboard().primaryClip;
312 }
313 }
314
315 @Override
316 public ClipDescription getPrimaryClipDescription(String callingPackage) {
317 synchronized (this) {
Chad Brubaker34ffba62017-03-02 15:56:43 -0800318 if (!clipboardAccessAllowed(AppOpsManager.OP_READ_CLIPBOARD, callingPackage,
319 Binder.getCallingUid())) {
Sudheer Shankaad70bc62016-09-29 12:58:04 -0700320 return null;
321 }
322 PerUserClipboard clipboard = getClipboard();
323 return clipboard.primaryClip != null ? clipboard.primaryClip.getDescription() : null;
324 }
325 }
326
327 @Override
328 public boolean hasPrimaryClip(String callingPackage) {
329 synchronized (this) {
Chad Brubaker34ffba62017-03-02 15:56:43 -0800330 if (!clipboardAccessAllowed(AppOpsManager.OP_READ_CLIPBOARD, callingPackage,
331 Binder.getCallingUid())) {
Sudheer Shankaad70bc62016-09-29 12:58:04 -0700332 return false;
333 }
334 return getClipboard().primaryClip != null;
335 }
336 }
337
338 @Override
339 public void addPrimaryClipChangedListener(IOnPrimaryClipChangedListener listener,
340 String callingPackage) {
341 synchronized (this) {
342 getClipboard().primaryClipListeners.register(listener,
343 new ListenerInfo(Binder.getCallingUid(), callingPackage));
344 }
345 }
346
347 @Override
348 public void removePrimaryClipChangedListener(IOnPrimaryClipChangedListener listener) {
349 synchronized (this) {
350 getClipboard().primaryClipListeners.unregister(listener);
351 }
352 }
353
354 @Override
355 public boolean hasClipboardText(String callingPackage) {
356 synchronized (this) {
Chad Brubaker34ffba62017-03-02 15:56:43 -0800357 if (!clipboardAccessAllowed(AppOpsManager.OP_READ_CLIPBOARD, callingPackage,
358 Binder.getCallingUid())) {
Sudheer Shankaad70bc62016-09-29 12:58:04 -0700359 return false;
360 }
361 PerUserClipboard clipboard = getClipboard();
362 if (clipboard.primaryClip != null) {
363 CharSequence text = clipboard.primaryClip.getItemAt(0).getText();
364 return text != null && text.length() > 0;
365 }
366 return false;
367 }
368 }
369 };
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800370
Amith Yamasanie9e26cc2012-04-20 19:01:50 -0700371 private PerUserClipboard getClipboard() {
Dianne Hackbornf02b60a2012-08-16 10:48:27 -0700372 return getClipboard(UserHandle.getCallingUserId());
Amith Yamasanie9e26cc2012-04-20 19:01:50 -0700373 }
374
375 private PerUserClipboard getClipboard(int userId) {
376 synchronized (mClipboards) {
Amith Yamasanie9e26cc2012-04-20 19:01:50 -0700377 PerUserClipboard puc = mClipboards.get(userId);
378 if (puc == null) {
379 puc = new PerUserClipboard(userId);
380 mClipboards.put(userId, puc);
381 }
382 return puc;
383 }
384 }
385
Nicolas Prevotf1939902014-06-25 09:29:02 +0100386 List<UserInfo> getRelatedProfiles(int userId) {
387 final List<UserInfo> related;
388 final long origId = Binder.clearCallingIdentity();
389 try {
390 related = mUm.getProfiles(userId, true);
391 } catch (RemoteException e) {
392 Slog.e(TAG, "Remote Exception calling UserManager: " + e);
393 return null;
394 } finally{
395 Binder.restoreCallingIdentity(origId);
396 }
397 return related;
398 }
399
400 void setPrimaryClipInternal(PerUserClipboard clipboard, ClipData clip) {
401 clipboard.activePermissionOwners.clear();
402 if (clip == null && clipboard.primaryClip == null) {
403 return;
404 }
405 clipboard.primaryClip = clip;
Sudheer Shankafe4d1e82017-02-09 13:09:15 -0800406 if (clip != null) {
407 final ClipDescription description = clip.getDescription();
408 if (description != null) {
Sudheer Shankac8201912017-04-20 11:30:48 -0700409 description.setTimestamp(System.currentTimeMillis());
Sudheer Shankafe4d1e82017-02-09 13:09:15 -0800410 }
Sudheer Shanka09971be2017-01-18 13:37:02 -0800411 }
Nicolas Prevotf1939902014-06-25 09:29:02 +0100412 final long ident = Binder.clearCallingIdentity();
413 final int n = clipboard.primaryClipListeners.beginBroadcast();
414 try {
415 for (int i = 0; i < n; i++) {
416 try {
417 ListenerInfo li = (ListenerInfo)
418 clipboard.primaryClipListeners.getBroadcastCookie(i);
Chad Brubaker34ffba62017-03-02 15:56:43 -0800419
420 if (clipboardAccessAllowed(AppOpsManager.OP_READ_CLIPBOARD, li.mPackageName,
421 li.mUid)) {
Nicolas Prevotf1939902014-06-25 09:29:02 +0100422 clipboard.primaryClipListeners.getBroadcastItem(i)
423 .dispatchPrimaryClipChanged();
424 }
425 } catch (RemoteException e) {
426 // The RemoteCallbackList will take care of removing
427 // the dead object for us.
428 }
429 }
430 } finally {
431 clipboard.primaryClipListeners.finishBroadcast();
432 Binder.restoreCallingIdentity(ident);
433 }
434 }
Dianne Hackborn90f4aaf2010-09-27 14:58:44 -0700435
436 private final void checkUriOwnerLocked(Uri uri, int uid) {
437 if (!"content".equals(uri.getScheme())) {
438 return;
439 }
440 long ident = Binder.clearCallingIdentity();
Dianne Hackborn90f4aaf2010-09-27 14:58:44 -0700441 try {
442 // This will throw SecurityException for us.
Nicolas Prevotd85fc722014-04-16 19:52:08 +0100443 mAm.checkGrantUriPermission(uid, null, ContentProvider.getUriWithoutUserId(uri),
Nicolas Prevotf1939902014-06-25 09:29:02 +0100444 Intent.FLAG_GRANT_READ_URI_PERMISSION,
445 ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(uid)));
Dianne Hackborn90f4aaf2010-09-27 14:58:44 -0700446 } catch (RemoteException e) {
447 } finally {
448 Binder.restoreCallingIdentity(ident);
449 }
450 }
451
452 private final void checkItemOwnerLocked(ClipData.Item item, int uid) {
453 if (item.getUri() != null) {
454 checkUriOwnerLocked(item.getUri(), uid);
455 }
456 Intent intent = item.getIntent();
457 if (intent != null && intent.getData() != null) {
458 checkUriOwnerLocked(intent.getData(), uid);
459 }
460 }
461
462 private final void checkDataOwnerLocked(ClipData data, int uid) {
463 final int N = data.getItemCount();
464 for (int i=0; i<N; i++) {
Dianne Hackborn327fbd22011-01-17 14:38:50 -0800465 checkItemOwnerLocked(data.getItemAt(i), uid);
Dianne Hackborn90f4aaf2010-09-27 14:58:44 -0700466 }
467 }
468
Nicolas Prevotf1939902014-06-25 09:29:02 +0100469 private final void grantUriLocked(Uri uri, String pkg, int userId) {
Dianne Hackborn90f4aaf2010-09-27 14:58:44 -0700470 long ident = Binder.clearCallingIdentity();
471 try {
Nicolas Prevotf1939902014-06-25 09:29:02 +0100472 int sourceUserId = ContentProvider.getUserIdFromUri(uri, userId);
473 uri = ContentProvider.getUriWithoutUserId(uri);
Nicolas Prevotd85fc722014-04-16 19:52:08 +0100474 mAm.grantUriPermissionFromOwner(mPermissionOwner, Process.myUid(), pkg,
Nicolas Prevotf1939902014-06-25 09:29:02 +0100475 uri, Intent.FLAG_GRANT_READ_URI_PERMISSION, sourceUserId, userId);
Dianne Hackborn90f4aaf2010-09-27 14:58:44 -0700476 } catch (RemoteException e) {
477 } finally {
478 Binder.restoreCallingIdentity(ident);
479 }
480 }
481
Nicolas Prevotf1939902014-06-25 09:29:02 +0100482 private final void grantItemLocked(ClipData.Item item, String pkg, int userId) {
Dianne Hackborn90f4aaf2010-09-27 14:58:44 -0700483 if (item.getUri() != null) {
Nicolas Prevotf1939902014-06-25 09:29:02 +0100484 grantUriLocked(item.getUri(), pkg, userId);
Dianne Hackborn90f4aaf2010-09-27 14:58:44 -0700485 }
486 Intent intent = item.getIntent();
487 if (intent != null && intent.getData() != null) {
Nicolas Prevotf1939902014-06-25 09:29:02 +0100488 grantUriLocked(intent.getData(), pkg, userId);
Dianne Hackborn90f4aaf2010-09-27 14:58:44 -0700489 }
490 }
491
492 private final void addActiveOwnerLocked(int uid, String pkg) {
Christopher Tatead9833a2012-09-14 13:34:17 -0700493 final IPackageManager pm = AppGlobals.getPackageManager();
494 final int targetUserHandle = UserHandle.getCallingUserId();
495 final long oldIdentity = Binder.clearCallingIdentity();
Dianne Hackborn90f4aaf2010-09-27 14:58:44 -0700496 try {
Christopher Tatead9833a2012-09-14 13:34:17 -0700497 PackageInfo pi = pm.getPackageInfo(pkg, 0, targetUserHandle);
498 if (pi == null) {
499 throw new IllegalArgumentException("Unknown package " + pkg);
500 }
Dianne Hackbornf02b60a2012-08-16 10:48:27 -0700501 if (!UserHandle.isSameApp(pi.applicationInfo.uid, uid)) {
Dianne Hackborn90f4aaf2010-09-27 14:58:44 -0700502 throw new SecurityException("Calling uid " + uid
503 + " does not own package " + pkg);
504 }
Christopher Tatead9833a2012-09-14 13:34:17 -0700505 } catch (RemoteException e) {
506 // Can't happen; the package manager is in the same process
507 } finally {
508 Binder.restoreCallingIdentity(oldIdentity);
Dianne Hackborn90f4aaf2010-09-27 14:58:44 -0700509 }
Amith Yamasanie9e26cc2012-04-20 19:01:50 -0700510 PerUserClipboard clipboard = getClipboard();
511 if (clipboard.primaryClip != null && !clipboard.activePermissionOwners.contains(pkg)) {
512 final int N = clipboard.primaryClip.getItemCount();
Dianne Hackborn90f4aaf2010-09-27 14:58:44 -0700513 for (int i=0; i<N; i++) {
Nicolas Prevotf1939902014-06-25 09:29:02 +0100514 grantItemLocked(clipboard.primaryClip.getItemAt(i), pkg, UserHandle.getUserId(uid));
Dianne Hackborn90f4aaf2010-09-27 14:58:44 -0700515 }
Amith Yamasanie9e26cc2012-04-20 19:01:50 -0700516 clipboard.activePermissionOwners.add(pkg);
Dianne Hackborn90f4aaf2010-09-27 14:58:44 -0700517 }
518 }
519
520 private final void revokeUriLocked(Uri uri) {
Nicolas Prevotf1939902014-06-25 09:29:02 +0100521 int userId = ContentProvider.getUserIdFromUri(uri,
522 UserHandle.getUserId(Binder.getCallingUid()));
Dianne Hackborn90f4aaf2010-09-27 14:58:44 -0700523 long ident = Binder.clearCallingIdentity();
524 try {
Nicolas Prevotf1939902014-06-25 09:29:02 +0100525 uri = ContentProvider.getUriWithoutUserId(uri);
526 mAm.revokeUriPermissionFromOwner(mPermissionOwner, uri,
Nicolas Prevotd85fc722014-04-16 19:52:08 +0100527 Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION,
Nicolas Prevotf1939902014-06-25 09:29:02 +0100528 userId);
Dianne Hackborn90f4aaf2010-09-27 14:58:44 -0700529 } catch (RemoteException e) {
530 } finally {
531 Binder.restoreCallingIdentity(ident);
532 }
533 }
534
535 private final void revokeItemLocked(ClipData.Item item) {
536 if (item.getUri() != null) {
537 revokeUriLocked(item.getUri());
538 }
539 Intent intent = item.getIntent();
540 if (intent != null && intent.getData() != null) {
541 revokeUriLocked(intent.getData());
542 }
543 }
544
Nicolas Prevotf1939902014-06-25 09:29:02 +0100545 private final void revokeUris(PerUserClipboard clipboard) {
Amith Yamasanie9e26cc2012-04-20 19:01:50 -0700546 if (clipboard.primaryClip == null) {
Dianne Hackborn90f4aaf2010-09-27 14:58:44 -0700547 return;
548 }
Amith Yamasanie9e26cc2012-04-20 19:01:50 -0700549 final int N = clipboard.primaryClip.getItemCount();
Dianne Hackborn90f4aaf2010-09-27 14:58:44 -0700550 for (int i=0; i<N; i++) {
Amith Yamasanie9e26cc2012-04-20 19:01:50 -0700551 revokeItemLocked(clipboard.primaryClip.getItemAt(i));
Dianne Hackborn90f4aaf2010-09-27 14:58:44 -0700552 }
553 }
Chad Brubaker34ffba62017-03-02 15:56:43 -0800554
555 private boolean clipboardAccessAllowed(int op, String callingPackage, int callingUid) {
556 // Check the AppOp.
557 if (mAppOps.checkOp(op, callingUid, callingPackage) != AppOpsManager.MODE_ALLOWED) {
558 return false;
559 }
560 try {
561 // Installed apps can access the clipboard at any time.
562 if (!AppGlobals.getPackageManager().isInstantApp(callingPackage,
563 UserHandle.getUserId(callingUid))) {
564 return true;
565 }
566 // Instant apps can only access the clipboard if they are in the foreground.
567 return mAm.isAppForeground(callingUid);
568 } catch (RemoteException e) {
569 Slog.e("clipboard", "Failed to get Instant App status for package " + callingPackage,
570 e);
571 return false;
572 }
573 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800574}