AppOpsManager.java revision 713df150b92a0a5eea877f99405e31eefbf93a09
1/*
2 * Copyright (C) 2012 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
17package android.app;
18
19import android.Manifest;
20import com.android.internal.app.IAppOpsService;
21import com.android.internal.app.IAppOpsCallback;
22
23import java.util.ArrayList;
24import java.util.HashMap;
25import java.util.List;
26
27import android.content.Context;
28import android.os.Parcel;
29import android.os.Parcelable;
30import android.os.Process;
31import android.os.RemoteException;
32
33/**
34 * API for interacting with "application operation" tracking.  Allows you to:
35 *
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
39 * being allowed.
40 * - Monitor for changes in whether an operation is allowed.
41 *
42 * Each operation is identified by a single integer; these integers are a fixed set of
43 * operations, enumerated by the OP_* constants.
44 *
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).
49 *
50 * @hide
51 */
52public class AppOpsManager {
53    final Context mContext;
54    final IAppOpsService mService;
55    final HashMap<Callback, IAppOpsCallback> mModeWatchers
56            = new HashMap<Callback, IAppOpsCallback>();
57
58    public static final int MODE_ALLOWED = 0;
59    public static final int MODE_IGNORED = 1;
60    public static final int MODE_ERRORED = 2;
61
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;
98    public static final int OP_TAKE_MEDIA_BUTTONS = 31;
99    public static final int OP_TAKE_AUDIO_FOCUS = 32;
100    public static final int OP_AUDIO_MASTER_VOLUME = 33;
101    public static final int OP_AUDIO_VOICE_VOLUME = 34;
102    public static final int OP_AUDIO_RING_VOLUME = 35;
103    public static final int OP_AUDIO_MEDIA_VOLUME = 36;
104    public static final int OP_AUDIO_ALARM_VOLUME = 37;
105    public static final int OP_AUDIO_NOTIFICATION_VOLUME = 38;
106    public static final int OP_AUDIO_BLUETOOTH_VOLUME = 39;
107    public static final int OP_WAKE_LOCK = 40;
108    /** @hide */
109    public static final int _NUM_OP = 41;
110
111    /**
112     * This maps each operation to the operation that serves as the
113     * switch to determine whether it is allowed.  Generally this is
114     * a 1:1 mapping, but for some things (like location) that have
115     * multiple low-level operations being tracked that should be
116     * presented to hte user as one switch then this can be used to
117     * make them all controlled by the same single operation.
118     */
119    private static int[] sOpToSwitch = new int[] {
120            OP_COARSE_LOCATION,
121            OP_COARSE_LOCATION,
122            OP_COARSE_LOCATION,
123            OP_VIBRATE,
124            OP_READ_CONTACTS,
125            OP_WRITE_CONTACTS,
126            OP_READ_CALL_LOG,
127            OP_WRITE_CALL_LOG,
128            OP_READ_CALENDAR,
129            OP_WRITE_CALENDAR,
130            OP_COARSE_LOCATION,
131            OP_POST_NOTIFICATION,
132            OP_COARSE_LOCATION,
133            OP_CALL_PHONE,
134            OP_READ_SMS,
135            OP_WRITE_SMS,
136            OP_READ_SMS,
137            OP_READ_SMS,
138            OP_READ_SMS,
139            OP_READ_SMS,
140            OP_WRITE_SMS,
141            OP_READ_SMS,
142            OP_WRITE_SMS,
143            OP_WRITE_SETTINGS,
144            OP_SYSTEM_ALERT_WINDOW,
145            OP_ACCESS_NOTIFICATIONS,
146            OP_CAMERA,
147            OP_RECORD_AUDIO,
148            OP_PLAY_AUDIO,
149            OP_READ_CLIPBOARD,
150            OP_WRITE_CLIPBOARD,
151            OP_TAKE_MEDIA_BUTTONS,
152            OP_TAKE_AUDIO_FOCUS,
153            OP_AUDIO_MASTER_VOLUME,
154            OP_AUDIO_VOICE_VOLUME,
155            OP_AUDIO_RING_VOLUME,
156            OP_AUDIO_MEDIA_VOLUME,
157            OP_AUDIO_ALARM_VOLUME,
158            OP_AUDIO_NOTIFICATION_VOLUME,
159            OP_AUDIO_BLUETOOTH_VOLUME,
160            OP_WAKE_LOCK,
161    };
162
163    /**
164     * This provides a simple name for each operation to be used
165     * in debug output.
166     */
167    private static String[] sOpNames = new String[] {
168            "COARSE_LOCATION",
169            "FINE_LOCATION",
170            "GPS",
171            "VIBRATE",
172            "READ_CONTACTS",
173            "WRITE_CONTACTS",
174            "READ_CALL_LOG",
175            "WRITE_CALL_LOG",
176            "READ_CALENDAR",
177            "WRITE_CALENDAR",
178            "WIFI_SCAN",
179            "POST_NOTIFICATION",
180            "NEIGHBORING_CELLS",
181            "CALL_PHONE",
182            "READ_SMS",
183            "WRITE_SMS",
184            "RECEIVE_SMS",
185            "RECEIVE_EMERGECY_SMS",
186            "RECEIVE_MMS",
187            "RECEIVE_WAP_PUSH",
188            "SEND_SMS",
189            "READ_ICC_SMS",
190            "WRITE_ICC_SMS",
191            "WRITE_SETTINGS",
192            "SYSTEM_ALERT_WINDOW",
193            "ACCESS_NOTIFICATIONS",
194            "CAMERA",
195            "RECORD_AUDIO",
196            "PLAY_AUDIO",
197            "READ_CLIPBOARD",
198            "WRITE_CLIPBOARD",
199            "TAKE_MEDIA_BUTTONS",
200            "TAKE_AUDIO_FOCUS",
201            "AUDIO_MASTER_VOLUME",
202            "AUDIO_VOICE_VOLUME",
203            "AUDIO_RING_VOLUME",
204            "AUDIO_MEDIA_VOLUME",
205            "AUDIO_ALARM_VOLUME",
206            "AUDIO_NOTIFICATION_VOLUME",
207            "AUDIO_BLUETOOTH_VOLUME",
208            "WAKE_LOCK",
209    };
210
211    /**
212     * This optionally maps a permission to an operation.  If there
213     * is no permission associated with an operation, it is null.
214     */
215    private static String[] sOpPerms = new String[] {
216            android.Manifest.permission.ACCESS_COARSE_LOCATION,
217            android.Manifest.permission.ACCESS_FINE_LOCATION,
218            null,
219            android.Manifest.permission.VIBRATE,
220            android.Manifest.permission.READ_CONTACTS,
221            android.Manifest.permission.WRITE_CONTACTS,
222            android.Manifest.permission.READ_CALL_LOG,
223            android.Manifest.permission.WRITE_CALL_LOG,
224            android.Manifest.permission.READ_CALENDAR,
225            android.Manifest.permission.WRITE_CALENDAR,
226            null, // no permission required for notifications
227            android.Manifest.permission.ACCESS_WIFI_STATE,
228            null, // neighboring cells shares the coarse location perm
229            android.Manifest.permission.CALL_PHONE,
230            android.Manifest.permission.READ_SMS,
231            android.Manifest.permission.WRITE_SMS,
232            android.Manifest.permission.RECEIVE_SMS,
233            android.Manifest.permission.RECEIVE_EMERGENCY_BROADCAST,
234            android.Manifest.permission.RECEIVE_MMS,
235            android.Manifest.permission.RECEIVE_WAP_PUSH,
236            android.Manifest.permission.SEND_SMS,
237            android.Manifest.permission.READ_SMS,
238            android.Manifest.permission.WRITE_SMS,
239            android.Manifest.permission.WRITE_SETTINGS,
240            android.Manifest.permission.SYSTEM_ALERT_WINDOW,
241            android.Manifest.permission.ACCESS_NOTIFICATIONS,
242            android.Manifest.permission.CAMERA,
243            android.Manifest.permission.RECORD_AUDIO,
244            null, // no permission for playing audio
245            null, // no permission for reading clipboard
246            null, // no permission for writing clipboard
247            null, // no permission for taking media buttons
248            null, // no permission for taking audio focus
249            null, // no permission for changing master volume
250            null, // no permission for changing voice volume
251            null, // no permission for changing ring volume
252            null, // no permission for changing media volume
253            null, // no permission for changing alarm volume
254            null, // no permission for changing notification volume
255            null, // no permission for changing bluetooth volume
256            android.Manifest.permission.WAKE_LOCK,
257    };
258
259    /**
260     * Retrieve the op switch that controls the given operation.
261     */
262    public static int opToSwitch(int op) {
263        return sOpToSwitch[op];
264    }
265
266    /**
267     * Retrieve a non-localized name for the operation, for debugging output.
268     */
269    public static String opToName(int op) {
270        if (op == OP_NONE) return "NONE";
271        return op < sOpNames.length ? sOpNames[op] : ("Unknown(" + op + ")");
272    }
273
274    /**
275     * Retrieve the permission associated with an operation, or null if there is not one.
276     */
277    public static String opToPermission(int op) {
278        return sOpPerms[op];
279    }
280
281    /**
282     * Class holding all of the operation information associated with an app.
283     */
284    public static class PackageOps implements Parcelable {
285        private final String mPackageName;
286        private final int mUid;
287        private final List<OpEntry> mEntries;
288
289        public PackageOps(String packageName, int uid, List<OpEntry> entries) {
290            mPackageName = packageName;
291            mUid = uid;
292            mEntries = entries;
293        }
294
295        public String getPackageName() {
296            return mPackageName;
297        }
298
299        public int getUid() {
300            return mUid;
301        }
302
303        public List<OpEntry> getOps() {
304            return mEntries;
305        }
306
307        @Override
308        public int describeContents() {
309            return 0;
310        }
311
312        @Override
313        public void writeToParcel(Parcel dest, int flags) {
314            dest.writeString(mPackageName);
315            dest.writeInt(mUid);
316            dest.writeInt(mEntries.size());
317            for (int i=0; i<mEntries.size(); i++) {
318                mEntries.get(i).writeToParcel(dest, flags);
319            }
320        }
321
322        PackageOps(Parcel source) {
323            mPackageName = source.readString();
324            mUid = source.readInt();
325            mEntries = new ArrayList<OpEntry>();
326            final int N = source.readInt();
327            for (int i=0; i<N; i++) {
328                mEntries.add(OpEntry.CREATOR.createFromParcel(source));
329            }
330        }
331
332        public static final Creator<PackageOps> CREATOR = new Creator<PackageOps>() {
333            @Override public PackageOps createFromParcel(Parcel source) {
334                return new PackageOps(source);
335            }
336
337            @Override public PackageOps[] newArray(int size) {
338                return new PackageOps[size];
339            }
340        };
341    }
342
343    /**
344     * Class holding the information about one unique operation of an application.
345     */
346    public static class OpEntry implements Parcelable {
347        private final int mOp;
348        private final int mMode;
349        private final long mTime;
350        private final long mRejectTime;
351        private final int mDuration;
352
353        public OpEntry(int op, int mode, long time, long rejectTime, int duration) {
354            mOp = op;
355            mMode = mode;
356            mTime = time;
357            mRejectTime = rejectTime;
358            mDuration = duration;
359        }
360
361        public int getOp() {
362            return mOp;
363        }
364
365        public int getMode() {
366            return mMode;
367        }
368
369        public long getTime() {
370            return mTime;
371        }
372
373        public long getRejectTime() {
374            return mRejectTime;
375        }
376
377        public boolean isRunning() {
378            return mDuration == -1;
379        }
380
381        public int getDuration() {
382            return mDuration == -1 ? (int)(System.currentTimeMillis()-mTime) : mDuration;
383        }
384
385        @Override
386        public int describeContents() {
387            return 0;
388        }
389
390        @Override
391        public void writeToParcel(Parcel dest, int flags) {
392            dest.writeInt(mOp);
393            dest.writeInt(mMode);
394            dest.writeLong(mTime);
395            dest.writeLong(mRejectTime);
396            dest.writeInt(mDuration);
397        }
398
399        OpEntry(Parcel source) {
400            mOp = source.readInt();
401            mMode = source.readInt();
402            mTime = source.readLong();
403            mRejectTime = source.readLong();
404            mDuration = source.readInt();
405        }
406
407        public static final Creator<OpEntry> CREATOR = new Creator<OpEntry>() {
408            @Override public OpEntry createFromParcel(Parcel source) {
409                return new OpEntry(source);
410            }
411
412            @Override public OpEntry[] newArray(int size) {
413                return new OpEntry[size];
414            }
415        };
416    }
417
418    /**
419     * Callback for notification of changes to operation state.
420     */
421    public interface Callback {
422        public void opChanged(int op, String packageName);
423    }
424
425    public AppOpsManager(Context context, IAppOpsService service) {
426        mContext = context;
427        mService = service;
428    }
429
430    /**
431     * Retrieve current operation state for all applications.
432     *
433     * @param ops The set of operations you are interested in, or null if you want all of them.
434     */
435    public List<AppOpsManager.PackageOps> getPackagesForOps(int[] ops) {
436        try {
437            return mService.getPackagesForOps(ops);
438        } catch (RemoteException e) {
439        }
440        return null;
441    }
442
443    /**
444     * Retrieve current operation state for one application.
445     *
446     * @param uid The uid of the application of interest.
447     * @param packageName The name of the application of interest.
448     * @param ops The set of operations you are interested in, or null if you want all of them.
449     */
450    public List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName, int[] ops) {
451        try {
452            return mService.getOpsForPackage(uid, packageName, ops);
453        } catch (RemoteException e) {
454        }
455        return null;
456    }
457
458    public void setMode(int code, int uid, String packageName, int mode) {
459        try {
460            mService.setMode(code, uid, packageName, mode);
461        } catch (RemoteException e) {
462        }
463    }
464
465    public void startWatchingMode(int op, String packageName, final Callback callback) {
466        synchronized (mModeWatchers) {
467            IAppOpsCallback cb = mModeWatchers.get(callback);
468            if (cb == null) {
469                cb = new IAppOpsCallback.Stub() {
470                    public void opChanged(int op, String packageName) {
471                        callback.opChanged(op, packageName);
472                    }
473                };
474                mModeWatchers.put(callback, cb);
475            }
476            try {
477                mService.startWatchingMode(op, packageName, cb);
478            } catch (RemoteException e) {
479            }
480        }
481    }
482
483    public void stopWatchingMode(Callback callback) {
484        synchronized (mModeWatchers) {
485            IAppOpsCallback cb = mModeWatchers.get(callback);
486            if (cb != null) {
487                try {
488                    mService.stopWatchingMode(cb);
489                } catch (RemoteException e) {
490                }
491            }
492        }
493    }
494
495    public int checkOp(int op, int uid, String packageName) {
496        try {
497            int mode = mService.checkOperation(op, uid, packageName);
498            if (mode == MODE_ERRORED) {
499                throw new SecurityException("Operation not allowed");
500            }
501            return mode;
502        } catch (RemoteException e) {
503        }
504        return MODE_IGNORED;
505    }
506
507    public int checkOpNoThrow(int op, int uid, String packageName) {
508        try {
509            return mService.checkOperation(op, uid, packageName);
510        } catch (RemoteException e) {
511        }
512        return MODE_IGNORED;
513    }
514
515    public int noteOp(int op, int uid, String packageName) {
516        try {
517            int mode = mService.noteOperation(op, uid, packageName);
518            if (mode == MODE_ERRORED) {
519                throw new SecurityException("Operation not allowed");
520            }
521            return mode;
522        } catch (RemoteException e) {
523        }
524        return MODE_IGNORED;
525    }
526
527    public int noteOpNoThrow(int op, int uid, String packageName) {
528        try {
529            return mService.noteOperation(op, uid, packageName);
530        } catch (RemoteException e) {
531        }
532        return MODE_IGNORED;
533    }
534
535    public int noteOp(int op) {
536        return noteOp(op, Process.myUid(), mContext.getBasePackageName());
537    }
538
539    public int startOp(int op, int uid, String packageName) {
540        try {
541            int mode = mService.startOperation(op, uid, packageName);
542            if (mode == MODE_ERRORED) {
543                throw new SecurityException("Operation not allowed");
544            }
545            return mode;
546        } catch (RemoteException e) {
547        }
548        return MODE_IGNORED;
549    }
550
551    public int startOpNoThrow(int op, int uid, String packageName) {
552        try {
553            return mService.startOperation(op, uid, packageName);
554        } catch (RemoteException e) {
555        }
556        return MODE_IGNORED;
557    }
558
559    public int startOp(int op) {
560        return startOp(op, Process.myUid(), mContext.getBasePackageName());
561    }
562
563    public void finishOp(int op, int uid, String packageName) {
564        try {
565            mService.finishOperation(op, uid, packageName);
566        } catch (RemoteException e) {
567        }
568    }
569
570    public void finishOp(int op) {
571        finishOp(op, Process.myUid(), mContext.getBasePackageName());
572    }
573}
574