2 * Copyright (C) 2012 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 import android.Manifest;
20 import com.android.internal.app.IAppOpsService;
21 import com.android.internal.app.IAppOpsCallback;
23 import java.util.ArrayList;
24 import java.util.HashMap;
25 import java.util.List;
27 import android.content.Context;
28 import android.os.Parcel;
29 import android.os.Parcelable;
30 import android.os.Process;
31 import android.os.RemoteException;
34 * API for interacting with "application operation" tracking. Allows you to:
36 * - Note when operations are happening, and find out if they are allowed for the current caller.
37 * - Disallow specific apps from doing specific operations.
38 * - Collect all of the current information about operations that have been executed or are not
40 * - Monitor for changes in whether an operation is allowed.
42 * Each operation is identified by a single integer; these integers are a fixed set of
43 * operations, enumerated by the OP_* constants.
45 * When checking operations, the result is a "mode" integer indicating the current setting
46 * for the operation under that caller: MODE_ALLOWED, MODE_IGNORED (don't execute the operation but
47 * fake its behavior enough so that the caller doesn't crash), MODE_ERRORED (through a
48 * SecurityException back to the caller; the normal operation calls will do this for you).
52 public class AppOpsManager {
53 final Context mContext;
54 final IAppOpsService mService;
55 final HashMap<Callback, IAppOpsCallback> mModeWatchers
56 = new HashMap<Callback, IAppOpsCallback>();
58 public static final int MODE_ALLOWED = 0;
59 public static final int MODE_IGNORED = 1;
60 public static final int MODE_ERRORED = 2;
62 // when adding one of these:
63 // - increment _NUM_OP
64 // - add rows to sOpToSwitch, sOpNames, sOpPerms
65 // - add descriptive strings to Settings/res/values/arrays.xml
66 public static final int OP_NONE = -1;
67 public static final int OP_COARSE_LOCATION = 0;
68 public static final int OP_FINE_LOCATION = 1;
69 public static final int OP_GPS = 2;
70 public static final int OP_VIBRATE = 3;
71 public static final int OP_READ_CONTACTS = 4;
72 public static final int OP_WRITE_CONTACTS = 5;
73 public static final int OP_READ_CALL_LOG = 6;
74 public static final int OP_WRITE_CALL_LOG = 7;
75 public static final int OP_READ_CALENDAR = 8;
76 public static final int OP_WRITE_CALENDAR = 9;
77 public static final int OP_WIFI_SCAN = 10;
78 public static final int OP_POST_NOTIFICATION = 11;
79 public static final int OP_NEIGHBORING_CELLS = 12;
80 public static final int OP_CALL_PHONE = 13;
81 public static final int OP_READ_SMS = 14;
82 public static final int OP_WRITE_SMS = 15;
83 public static final int OP_RECEIVE_SMS = 16;
84 public static final int OP_RECEIVE_EMERGECY_SMS = 17;
85 public static final int OP_RECEIVE_MMS = 18;
86 public static final int OP_RECEIVE_WAP_PUSH = 19;
87 public static final int OP_SEND_SMS = 20;
88 public static final int OP_READ_ICC_SMS = 21;
89 public static final int OP_WRITE_ICC_SMS = 22;
90 public static final int OP_WRITE_SETTINGS = 23;
91 public static final int OP_SYSTEM_ALERT_WINDOW = 24;
92 public static final int OP_ACCESS_NOTIFICATIONS = 25;
93 public static final int OP_CAMERA = 26;
94 public static final int OP_RECORD_AUDIO = 27;
95 public static final int OP_PLAY_AUDIO = 28;
96 public static final int OP_READ_CLIPBOARD = 29;
97 public static final int OP_WRITE_CLIPBOARD = 30;
99 public static final int _NUM_OP = 31;
102 * This maps each operation to the operation that serves as the
103 * switch to determine whether it is allowed. Generally this is
104 * a 1:1 mapping, but for some things (like location) that have
105 * multiple low-level operations being tracked that should be
106 * presented to hte user as one switch then this can be used to
107 * make them all controlled by the same single operation.
109 private static int[] sOpToSwitch = new int[] {
121 OP_POST_NOTIFICATION,
134 OP_SYSTEM_ALERT_WINDOW,
135 OP_ACCESS_NOTIFICATIONS,
144 * This provides a simple name for each operation to be used
147 private static String[] sOpNames = new String[] {
165 "RECEIVE_EMERGECY_SMS",
172 "SYSTEM_ALERT_WINDOW",
173 "ACCESS_NOTIFICATIONS",
182 * This optionally maps a permission to an operation. If there
183 * is no permission associated with an operation, it is null.
185 private static String[] sOpPerms = new String[] {
186 android.Manifest.permission.ACCESS_COARSE_LOCATION,
187 android.Manifest.permission.ACCESS_FINE_LOCATION,
189 android.Manifest.permission.VIBRATE,
190 android.Manifest.permission.READ_CONTACTS,
191 android.Manifest.permission.WRITE_CONTACTS,
192 android.Manifest.permission.READ_CALL_LOG,
193 android.Manifest.permission.WRITE_CALL_LOG,
194 android.Manifest.permission.READ_CALENDAR,
195 android.Manifest.permission.WRITE_CALENDAR,
196 null, // no permission required for notifications
197 android.Manifest.permission.ACCESS_WIFI_STATE,
198 null, // neighboring cells shares the coarse location perm
199 android.Manifest.permission.CALL_PHONE,
200 android.Manifest.permission.READ_SMS,
201 android.Manifest.permission.WRITE_SMS,
202 android.Manifest.permission.RECEIVE_SMS,
203 android.Manifest.permission.RECEIVE_EMERGENCY_BROADCAST,
204 android.Manifest.permission.RECEIVE_MMS,
205 android.Manifest.permission.RECEIVE_WAP_PUSH,
206 android.Manifest.permission.SEND_SMS,
207 android.Manifest.permission.READ_SMS,
208 android.Manifest.permission.WRITE_SMS,
209 android.Manifest.permission.WRITE_SETTINGS,
210 android.Manifest.permission.SYSTEM_ALERT_WINDOW,
211 android.Manifest.permission.ACCESS_NOTIFICATIONS,
212 android.Manifest.permission.CAMERA,
213 android.Manifest.permission.RECORD_AUDIO,
214 null, // no permission for playing audio
215 null, // no permission for reading clipboard
216 null, // no permission for writing clipboard
220 * Retrieve the op switch that controls the given operation.
222 public static int opToSwitch(int op) {
223 return sOpToSwitch[op];
227 * Retrieve a non-localized name for the operation, for debugging output.
229 public static String opToName(int op) {
230 if (op == OP_NONE) return "NONE";
231 return op < sOpNames.length ? sOpNames[op] : ("Unknown(" + op + ")");
235 * Retrieve the permission associated with an operation, or null if there is not one.
237 public static String opToPermission(int op) {
242 * Class holding all of the operation information associated with an app.
244 public static class PackageOps implements Parcelable {
245 private final String mPackageName;
246 private final int mUid;
247 private final List<OpEntry> mEntries;
249 public PackageOps(String packageName, int uid, List<OpEntry> entries) {
250 mPackageName = packageName;
255 public String getPackageName() {
259 public int getUid() {
263 public List<OpEntry> getOps() {
268 public int describeContents() {
273 public void writeToParcel(Parcel dest, int flags) {
274 dest.writeString(mPackageName);
276 dest.writeInt(mEntries.size());
277 for (int i=0; i<mEntries.size(); i++) {
278 mEntries.get(i).writeToParcel(dest, flags);
282 PackageOps(Parcel source) {
283 mPackageName = source.readString();
284 mUid = source.readInt();
285 mEntries = new ArrayList<OpEntry>();
286 final int N = source.readInt();
287 for (int i=0; i<N; i++) {
288 mEntries.add(OpEntry.CREATOR.createFromParcel(source));
292 public static final Creator<PackageOps> CREATOR = new Creator<PackageOps>() {
293 @Override public PackageOps createFromParcel(Parcel source) {
294 return new PackageOps(source);
297 @Override public PackageOps[] newArray(int size) {
298 return new PackageOps[size];
304 * Class holding the information about one unique operation of an application.
306 public static class OpEntry implements Parcelable {
307 private final int mOp;
308 private final int mMode;
309 private final long mTime;
310 private final long mRejectTime;
311 private final int mDuration;
313 public OpEntry(int op, int mode, long time, long rejectTime, int duration) {
317 mRejectTime = rejectTime;
318 mDuration = duration;
325 public int getMode() {
329 public long getTime() {
333 public long getRejectTime() {
337 public boolean isRunning() {
338 return mDuration == -1;
341 public int getDuration() {
342 return mDuration == -1 ? (int)(System.currentTimeMillis()-mTime) : mDuration;
346 public int describeContents() {
351 public void writeToParcel(Parcel dest, int flags) {
353 dest.writeInt(mMode);
354 dest.writeLong(mTime);
355 dest.writeLong(mRejectTime);
356 dest.writeInt(mDuration);
359 OpEntry(Parcel source) {
360 mOp = source.readInt();
361 mMode = source.readInt();
362 mTime = source.readLong();
363 mRejectTime = source.readLong();
364 mDuration = source.readInt();
367 public static final Creator<OpEntry> CREATOR = new Creator<OpEntry>() {
368 @Override public OpEntry createFromParcel(Parcel source) {
369 return new OpEntry(source);
372 @Override public OpEntry[] newArray(int size) {
373 return new OpEntry[size];
379 * Callback for notification of changes to operation state.
381 public interface Callback {
382 public void opChanged(int op, String packageName);
385 public AppOpsManager(Context context, IAppOpsService service) {
391 * Retrieve current operation state for all applications.
393 * @param ops The set of operations you are interested in, or null if you want all of them.
395 public List<AppOpsManager.PackageOps> getPackagesForOps(int[] ops) {
397 return mService.getPackagesForOps(ops);
398 } catch (RemoteException e) {
404 * Retrieve current operation state for one application.
406 * @param uid The uid of the application of interest.
407 * @param packageName The name of the application of interest.
408 * @param ops The set of operations you are interested in, or null if you want all of them.
410 public List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName, int[] ops) {
412 return mService.getOpsForPackage(uid, packageName, ops);
413 } catch (RemoteException e) {
418 public void setMode(int code, int uid, String packageName, int mode) {
420 mService.setMode(code, uid, packageName, mode);
421 } catch (RemoteException e) {
425 public void startWatchingMode(int op, String packageName, final Callback callback) {
426 synchronized (mModeWatchers) {
427 IAppOpsCallback cb = mModeWatchers.get(callback);
429 cb = new IAppOpsCallback.Stub() {
430 public void opChanged(int op, String packageName) {
431 callback.opChanged(op, packageName);
434 mModeWatchers.put(callback, cb);
437 mService.startWatchingMode(op, packageName, cb);
438 } catch (RemoteException e) {
443 public void stopWatchingMode(Callback callback) {
444 synchronized (mModeWatchers) {
445 IAppOpsCallback cb = mModeWatchers.get(callback);
448 mService.stopWatchingMode(cb);
449 } catch (RemoteException e) {
455 public int checkOp(int op, int uid, String packageName) {
457 int mode = mService.checkOperation(op, uid, packageName);
458 if (mode == MODE_ERRORED) {
459 throw new SecurityException("Operation not allowed");
462 } catch (RemoteException e) {
467 public int checkOpNoThrow(int op, int uid, String packageName) {
469 return mService.checkOperation(op, uid, packageName);
470 } catch (RemoteException e) {
475 public int noteOp(int op, int uid, String packageName) {
477 int mode = mService.noteOperation(op, uid, packageName);
478 if (mode == MODE_ERRORED) {
479 throw new SecurityException("Operation not allowed");
482 } catch (RemoteException e) {
487 public int noteOpNoThrow(int op, int uid, String packageName) {
489 return mService.noteOperation(op, uid, packageName);
490 } catch (RemoteException e) {
495 public int noteOp(int op) {
496 return noteOp(op, Process.myUid(), mContext.getBasePackageName());
499 public int startOp(int op, int uid, String packageName) {
501 int mode = mService.startOperation(op, uid, packageName);
502 if (mode == MODE_ERRORED) {
503 throw new SecurityException("Operation not allowed");
506 } catch (RemoteException e) {
511 public int startOpNoThrow(int op, int uid, String packageName) {
513 return mService.startOperation(op, uid, packageName);
514 } catch (RemoteException e) {
519 public int startOp(int op) {
520 return startOp(op, Process.myUid(), mContext.getBasePackageName());
523 public void finishOp(int op, int uid, String packageName) {
525 mService.finishOperation(op, uid, packageName);
526 } catch (RemoteException e) {
530 public void finishOp(int op) {
531 finishOp(op, Process.myUid(), mContext.getBasePackageName());