From efcc1a23a1f731390ef8506b3536b9562d18ed78 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Mon, 25 Feb 2013 18:02:35 -0800 Subject: App ops: adding operations for reading/writing clipboard. Change-Id: Ic4cade153618fe86954754a3b3edde64a52a0a9c --- core/java/android/app/AppOpsManager.java | 10 +++- core/java/android/content/ClipboardManager.java | 12 ++--- core/java/android/content/IClipboard.aidl | 11 +++-- .../java/com/android/server/ClipboardService.java | 54 +++++++++++++++++++--- 4 files changed, 68 insertions(+), 19 deletions(-) diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index de69867..c9776f1 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -93,8 +93,10 @@ public class AppOpsManager { public static final int OP_CAMERA = 26; public static final int OP_RECORD_AUDIO = 27; public static final int OP_PLAY_AUDIO = 28; + public static final int OP_READ_CLIPBOARD = 29; + public static final int OP_WRITE_CLIPBOARD = 30; /** @hide */ - public static final int _NUM_OP = 29; + public static final int _NUM_OP = 31; /** * This maps each operation to the operation that serves as the @@ -134,6 +136,8 @@ public class AppOpsManager { OP_CAMERA, OP_RECORD_AUDIO, OP_PLAY_AUDIO, + OP_READ_CLIPBOARD, + OP_WRITE_CLIPBOARD, }; /** @@ -170,6 +174,8 @@ public class AppOpsManager { "CAMERA", "RECORD_AUDIO", "PLAY_AUDIO", + "READ_CLIPBOARD", + "WRITE_CLIPBOARD", }; /** @@ -206,6 +212,8 @@ public class AppOpsManager { android.Manifest.permission.CAMERA, android.Manifest.permission.RECORD_AUDIO, null, // no permission for playing audio + null, // no permission for reading clipboard + null, // no permission for writing clipboard }; /** diff --git a/core/java/android/content/ClipboardManager.java b/core/java/android/content/ClipboardManager.java index dfd1820..88a4229 100644 --- a/core/java/android/content/ClipboardManager.java +++ b/core/java/android/content/ClipboardManager.java @@ -118,7 +118,7 @@ public class ClipboardManager extends android.text.ClipboardManager { */ public void setPrimaryClip(ClipData clip) { try { - getService().setPrimaryClip(clip); + getService().setPrimaryClip(clip, mContext.getBasePackageName()); } catch (RemoteException e) { } } @@ -128,7 +128,7 @@ public class ClipboardManager extends android.text.ClipboardManager { */ public ClipData getPrimaryClip() { try { - return getService().getPrimaryClip(mContext.getPackageName()); + return getService().getPrimaryClip(mContext.getBasePackageName()); } catch (RemoteException e) { return null; } @@ -140,7 +140,7 @@ public class ClipboardManager extends android.text.ClipboardManager { */ public ClipDescription getPrimaryClipDescription() { try { - return getService().getPrimaryClipDescription(); + return getService().getPrimaryClipDescription(mContext.getBasePackageName()); } catch (RemoteException e) { return null; } @@ -151,7 +151,7 @@ public class ClipboardManager extends android.text.ClipboardManager { */ public boolean hasPrimaryClip() { try { - return getService().hasPrimaryClip(); + return getService().hasPrimaryClip(mContext.getBasePackageName()); } catch (RemoteException e) { return false; } @@ -162,7 +162,7 @@ public class ClipboardManager extends android.text.ClipboardManager { if (mPrimaryClipChangedListeners.size() == 0) { try { getService().addPrimaryClipChangedListener( - mPrimaryClipChangedServiceListener); + mPrimaryClipChangedServiceListener, mContext.getBasePackageName()); } catch (RemoteException e) { } } @@ -209,7 +209,7 @@ public class ClipboardManager extends android.text.ClipboardManager { */ public boolean hasText() { try { - return getService().hasClipboardText(); + return getService().hasClipboardText(mContext.getBasePackageName()); } catch (RemoteException e) { return false; } diff --git a/core/java/android/content/IClipboard.aidl b/core/java/android/content/IClipboard.aidl index 254901b..af0b8f0 100644 --- a/core/java/android/content/IClipboard.aidl +++ b/core/java/android/content/IClipboard.aidl @@ -26,15 +26,16 @@ import android.content.IOnPrimaryClipChangedListener; * {@hide} */ interface IClipboard { - void setPrimaryClip(in ClipData clip); + void setPrimaryClip(in ClipData clip, String callingPackage); ClipData getPrimaryClip(String pkg); - ClipDescription getPrimaryClipDescription(); - boolean hasPrimaryClip(); - void addPrimaryClipChangedListener(in IOnPrimaryClipChangedListener listener); + ClipDescription getPrimaryClipDescription(String callingPackage); + boolean hasPrimaryClip(String callingPackage); + void addPrimaryClipChangedListener(in IOnPrimaryClipChangedListener listener, + String callingPackage); void removePrimaryClipChangedListener(in IOnPrimaryClipChangedListener listener); /** * Returns true if the clipboard contains text; false otherwise. */ - boolean hasClipboardText(); + boolean hasClipboardText(String callingPackage); } diff --git a/services/java/com/android/server/ClipboardService.java b/services/java/com/android/server/ClipboardService.java index 74ec6e2..058857d 100644 --- a/services/java/com/android/server/ClipboardService.java +++ b/services/java/com/android/server/ClipboardService.java @@ -18,6 +18,7 @@ package com.android.server; import android.app.ActivityManagerNative; import android.app.AppGlobals; +import android.app.AppOpsManager; import android.app.IActivityManager; import android.content.BroadcastReceiver; import android.content.ClipData; @@ -55,8 +56,18 @@ public class ClipboardService extends IClipboard.Stub { private final Context mContext; private final IActivityManager mAm; private final PackageManager mPm; + private final AppOpsManager mAppOps; private final IBinder mPermissionOwner; + private class ListenerInfo { + final int mUid; + final String mPackageName; + ListenerInfo(int uid, String packageName) { + mUid = uid; + mPackageName = packageName; + } + } + private class PerUserClipboard { final int userId; @@ -82,6 +93,7 @@ public class ClipboardService extends IClipboard.Stub { mContext = context; mAm = ActivityManagerNative.getDefault(); mPm = context.getPackageManager(); + mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE); IBinder permOwner = null; try { permOwner = mAm.newUriPermissionOwner("clipboard"); @@ -137,11 +149,15 @@ public class ClipboardService extends IClipboard.Stub { } } - public void setPrimaryClip(ClipData clip) { + public void setPrimaryClip(ClipData clip, String callingPackage) { synchronized (this) { if (clip != null && clip.getItemCount() <= 0) { throw new IllegalArgumentException("No items"); } + if (mAppOps.noteOp(AppOpsManager.OP_WRITE_CLIPBOARD, Binder.getCallingUid(), + callingPackage) != AppOpsManager.MODE_ALLOWED) { + return; + } checkDataOwnerLocked(clip, Binder.getCallingUid()); clearActiveOwnersLocked(); PerUserClipboard clipboard = getClipboard(); @@ -149,7 +165,13 @@ public class ClipboardService extends IClipboard.Stub { final int n = clipboard.primaryClipListeners.beginBroadcast(); for (int i = 0; i < n; i++) { try { - clipboard.primaryClipListeners.getBroadcastItem(i).dispatchPrimaryClipChanged(); + ListenerInfo li = (ListenerInfo) + clipboard.primaryClipListeners.getBroadcastCookie(i); + if (mAppOps.checkOpNoThrow(AppOpsManager.OP_READ_CLIPBOARD, li.mUid, + li.mPackageName) == AppOpsManager.MODE_ALLOWED) { + clipboard.primaryClipListeners.getBroadcastItem(i) + .dispatchPrimaryClipChanged(); + } } catch (RemoteException e) { // The RemoteCallbackList will take care of removing @@ -162,27 +184,41 @@ public class ClipboardService extends IClipboard.Stub { public ClipData getPrimaryClip(String pkg) { synchronized (this) { + if (mAppOps.noteOp(AppOpsManager.OP_READ_CLIPBOARD, Binder.getCallingUid(), + pkg) != AppOpsManager.MODE_ALLOWED) { + return null; + } addActiveOwnerLocked(Binder.getCallingUid(), pkg); return getClipboard().primaryClip; } } - public ClipDescription getPrimaryClipDescription() { + public ClipDescription getPrimaryClipDescription(String callingPackage) { synchronized (this) { + if (mAppOps.checkOp(AppOpsManager.OP_READ_CLIPBOARD, Binder.getCallingUid(), + callingPackage) != AppOpsManager.MODE_ALLOWED) { + return null; + } PerUserClipboard clipboard = getClipboard(); return clipboard.primaryClip != null ? clipboard.primaryClip.getDescription() : null; } } - public boolean hasPrimaryClip() { + public boolean hasPrimaryClip(String callingPackage) { synchronized (this) { + if (mAppOps.checkOp(AppOpsManager.OP_READ_CLIPBOARD, Binder.getCallingUid(), + callingPackage) != AppOpsManager.MODE_ALLOWED) { + return false; + } return getClipboard().primaryClip != null; } } - public void addPrimaryClipChangedListener(IOnPrimaryClipChangedListener listener) { + public void addPrimaryClipChangedListener(IOnPrimaryClipChangedListener listener, + String callingPackage) { synchronized (this) { - getClipboard().primaryClipListeners.register(listener); + getClipboard().primaryClipListeners.register(listener, + new ListenerInfo(Binder.getCallingUid(), callingPackage)); } } @@ -192,8 +228,12 @@ public class ClipboardService extends IClipboard.Stub { } } - public boolean hasClipboardText() { + public boolean hasClipboardText(String callingPackage) { synchronized (this) { + if (mAppOps.checkOp(AppOpsManager.OP_READ_CLIPBOARD, Binder.getCallingUid(), + callingPackage) != AppOpsManager.MODE_ALLOWED) { + return false; + } PerUserClipboard clipboard = getClipboard(); if (clipboard.primaryClip != null) { CharSequence text = clipboard.primaryClip.getItemAt(0).getText(); -- cgit v1.1