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.os.Binder;
20import android.os.IBinder;
21import android.util.ArrayMap;
22import com.android.internal.app.IAppOpsService;
23import com.android.internal.app.IAppOpsCallback;
24
25import java.util.ArrayList;
26import java.util.HashMap;
27import java.util.List;
28
29import android.content.Context;
30import android.os.Parcel;
31import android.os.Parcelable;
32import android.os.Process;
33import android.os.RemoteException;
34
35/**
36 * API for interacting with "application operation" tracking.
37 *
38 * <p>This API is not generally intended for third party application developers; most
39 * features are only available to system applicatins.  Obtain an instance of it through
40 * {@link Context#getSystemService(String) Context.getSystemService} with
41 * {@link Context#APP_OPS_SERVICE Context.APP_OPS_SERVICE}.</p>
42 */
43public class AppOpsManager {
44    /**
45     * <p>App ops allows callers to:</p>
46     *
47     * <ul>
48     * <li> Note when operations are happening, and find out if they are allowed for the current
49     * caller.</li>
50     * <li> Disallow specific apps from doing specific operations.</li>
51     * <li> Collect all of the current information about operations that have been executed or
52     * are not being allowed.</li>
53     * <li> Monitor for changes in whether an operation is allowed.</li>
54     * </ul>
55     *
56     * <p>Each operation is identified by a single integer; these integers are a fixed set of
57     * operations, enumerated by the OP_* constants.
58     *
59     * <p></p>When checking operations, the result is a "mode" integer indicating the current
60     * setting for the operation under that caller: MODE_ALLOWED, MODE_IGNORED (don't execute
61     * the operation but fake its behavior enough so that the caller doesn't crash),
62     * MODE_ERRORED (throw a SecurityException back to the caller; the normal operation calls
63     * will do this for you).
64     */
65
66    final Context mContext;
67    final IAppOpsService mService;
68    final ArrayMap<OnOpChangedListener, IAppOpsCallback> mModeWatchers
69            = new ArrayMap<OnOpChangedListener, IAppOpsCallback>();
70
71    static IBinder sToken;
72
73    /**
74     * Result from {@link #checkOp}, {@link #noteOp}, {@link #startOp}: the given caller is
75     * allowed to perform the given operation.
76     */
77    public static final int MODE_ALLOWED = 0;
78
79    /**
80     * Result from {@link #checkOp}, {@link #noteOp}, {@link #startOp}: the given caller is
81     * not allowed to perform the given operation, and this attempt should
82     * <em>silently fail</em> (it should not cause the app to crash).
83     */
84    public static final int MODE_IGNORED = 1;
85
86    /**
87     * Result from {@link #checkOpNoThrow}, {@link #noteOpNoThrow}, {@link #startOpNoThrow}: the
88     * given caller is not allowed to perform the given operation, and this attempt should
89     * cause it to have a fatal error, typically a {@link SecurityException}.
90     */
91    public static final int MODE_ERRORED = 2;
92
93    // when adding one of these:
94    //  - increment _NUM_OP
95    //  - add rows to sOpToSwitch, sOpToString, sOpNames, sOpPerms, sOpDefaultMode
96    //  - add descriptive strings to Settings/res/values/arrays.xml
97    //  - add the op to the appropriate template in AppOpsState.OpsTemplate (settings app)
98
99    /** @hide No operation specified. */
100    public static final int OP_NONE = -1;
101    /** @hide Access to coarse location information. */
102    public static final int OP_COARSE_LOCATION = 0;
103    /** @hide Access to fine location information. */
104    public static final int OP_FINE_LOCATION = 1;
105    /** @hide Causing GPS to run. */
106    public static final int OP_GPS = 2;
107    /** @hide */
108    public static final int OP_VIBRATE = 3;
109    /** @hide */
110    public static final int OP_READ_CONTACTS = 4;
111    /** @hide */
112    public static final int OP_WRITE_CONTACTS = 5;
113    /** @hide */
114    public static final int OP_READ_CALL_LOG = 6;
115    /** @hide */
116    public static final int OP_WRITE_CALL_LOG = 7;
117    /** @hide */
118    public static final int OP_READ_CALENDAR = 8;
119    /** @hide */
120    public static final int OP_WRITE_CALENDAR = 9;
121    /** @hide */
122    public static final int OP_WIFI_SCAN = 10;
123    /** @hide */
124    public static final int OP_POST_NOTIFICATION = 11;
125    /** @hide */
126    public static final int OP_NEIGHBORING_CELLS = 12;
127    /** @hide */
128    public static final int OP_CALL_PHONE = 13;
129    /** @hide */
130    public static final int OP_READ_SMS = 14;
131    /** @hide */
132    public static final int OP_WRITE_SMS = 15;
133    /** @hide */
134    public static final int OP_RECEIVE_SMS = 16;
135    /** @hide */
136    public static final int OP_RECEIVE_EMERGECY_SMS = 17;
137    /** @hide */
138    public static final int OP_RECEIVE_MMS = 18;
139    /** @hide */
140    public static final int OP_RECEIVE_WAP_PUSH = 19;
141    /** @hide */
142    public static final int OP_SEND_SMS = 20;
143    /** @hide */
144    public static final int OP_READ_ICC_SMS = 21;
145    /** @hide */
146    public static final int OP_WRITE_ICC_SMS = 22;
147    /** @hide */
148    public static final int OP_WRITE_SETTINGS = 23;
149    /** @hide */
150    public static final int OP_SYSTEM_ALERT_WINDOW = 24;
151    /** @hide */
152    public static final int OP_ACCESS_NOTIFICATIONS = 25;
153    /** @hide */
154    public static final int OP_CAMERA = 26;
155    /** @hide */
156    public static final int OP_RECORD_AUDIO = 27;
157    /** @hide */
158    public static final int OP_PLAY_AUDIO = 28;
159    /** @hide */
160    public static final int OP_READ_CLIPBOARD = 29;
161    /** @hide */
162    public static final int OP_WRITE_CLIPBOARD = 30;
163    /** @hide */
164    public static final int OP_TAKE_MEDIA_BUTTONS = 31;
165    /** @hide */
166    public static final int OP_TAKE_AUDIO_FOCUS = 32;
167    /** @hide */
168    public static final int OP_AUDIO_MASTER_VOLUME = 33;
169    /** @hide */
170    public static final int OP_AUDIO_VOICE_VOLUME = 34;
171    /** @hide */
172    public static final int OP_AUDIO_RING_VOLUME = 35;
173    /** @hide */
174    public static final int OP_AUDIO_MEDIA_VOLUME = 36;
175    /** @hide */
176    public static final int OP_AUDIO_ALARM_VOLUME = 37;
177    /** @hide */
178    public static final int OP_AUDIO_NOTIFICATION_VOLUME = 38;
179    /** @hide */
180    public static final int OP_AUDIO_BLUETOOTH_VOLUME = 39;
181    /** @hide */
182    public static final int OP_WAKE_LOCK = 40;
183    /** @hide Continually monitoring location data. */
184    public static final int OP_MONITOR_LOCATION = 41;
185    /** @hide Continually monitoring location data with a relatively high power request. */
186    public static final int OP_MONITOR_HIGH_POWER_LOCATION = 42;
187    /** @hide */
188    public static final int _NUM_OP = 43;
189
190    /** Access to coarse location information. */
191    public static final String OPSTR_COARSE_LOCATION =
192            "android:coarse_location";
193    /** Access to fine location information. */
194    public static final String OPSTR_FINE_LOCATION =
195            "android:fine_location";
196    /** Continually monitoring location data. */
197    public static final String OPSTR_MONITOR_LOCATION
198            = "android:monitor_location";
199    /** Continually monitoring location data with a relatively high power request. */
200    public static final String OPSTR_MONITOR_HIGH_POWER_LOCATION
201            = "android:monitor_location_high_power";
202
203    /**
204     * This maps each operation to the operation that serves as the
205     * switch to determine whether it is allowed.  Generally this is
206     * a 1:1 mapping, but for some things (like location) that have
207     * multiple low-level operations being tracked that should be
208     * presented to the user as one switch then this can be used to
209     * make them all controlled by the same single operation.
210     */
211    private static int[] sOpToSwitch = new int[] {
212            OP_COARSE_LOCATION,
213            OP_COARSE_LOCATION,
214            OP_COARSE_LOCATION,
215            OP_VIBRATE,
216            OP_READ_CONTACTS,
217            OP_WRITE_CONTACTS,
218            OP_READ_CALL_LOG,
219            OP_WRITE_CALL_LOG,
220            OP_READ_CALENDAR,
221            OP_WRITE_CALENDAR,
222            OP_COARSE_LOCATION,
223            OP_POST_NOTIFICATION,
224            OP_COARSE_LOCATION,
225            OP_CALL_PHONE,
226            OP_READ_SMS,
227            OP_WRITE_SMS,
228            OP_RECEIVE_SMS,
229            OP_RECEIVE_SMS,
230            OP_RECEIVE_SMS,
231            OP_RECEIVE_SMS,
232            OP_SEND_SMS,
233            OP_READ_SMS,
234            OP_WRITE_SMS,
235            OP_WRITE_SETTINGS,
236            OP_SYSTEM_ALERT_WINDOW,
237            OP_ACCESS_NOTIFICATIONS,
238            OP_CAMERA,
239            OP_RECORD_AUDIO,
240            OP_PLAY_AUDIO,
241            OP_READ_CLIPBOARD,
242            OP_WRITE_CLIPBOARD,
243            OP_TAKE_MEDIA_BUTTONS,
244            OP_TAKE_AUDIO_FOCUS,
245            OP_AUDIO_MASTER_VOLUME,
246            OP_AUDIO_VOICE_VOLUME,
247            OP_AUDIO_RING_VOLUME,
248            OP_AUDIO_MEDIA_VOLUME,
249            OP_AUDIO_ALARM_VOLUME,
250            OP_AUDIO_NOTIFICATION_VOLUME,
251            OP_AUDIO_BLUETOOTH_VOLUME,
252            OP_WAKE_LOCK,
253            OP_COARSE_LOCATION,
254            OP_COARSE_LOCATION,
255    };
256
257    /**
258     * This maps each operation to the public string constant for it.
259     * If it doesn't have a public string constant, it maps to null.
260     */
261    private static String[] sOpToString = new String[] {
262            OPSTR_COARSE_LOCATION,
263            OPSTR_FINE_LOCATION,
264            null,
265            null,
266            null,
267            null,
268            null,
269            null,
270            null,
271            null,
272            null,
273            null,
274            null,
275            null,
276            null,
277            null,
278            null,
279            null,
280            null,
281            null,
282            null,
283            null,
284            null,
285            null,
286            null,
287            null,
288            null,
289            null,
290            null,
291            null,
292            null,
293            null,
294            null,
295            null,
296            null,
297            null,
298            null,
299            null,
300            null,
301            null,
302            null,
303            OPSTR_MONITOR_LOCATION,
304            OPSTR_MONITOR_HIGH_POWER_LOCATION,
305    };
306
307    /**
308     * This provides a simple name for each operation to be used
309     * in debug output.
310     */
311    private static String[] sOpNames = new String[] {
312            "COARSE_LOCATION",
313            "FINE_LOCATION",
314            "GPS",
315            "VIBRATE",
316            "READ_CONTACTS",
317            "WRITE_CONTACTS",
318            "READ_CALL_LOG",
319            "WRITE_CALL_LOG",
320            "READ_CALENDAR",
321            "WRITE_CALENDAR",
322            "WIFI_SCAN",
323            "POST_NOTIFICATION",
324            "NEIGHBORING_CELLS",
325            "CALL_PHONE",
326            "READ_SMS",
327            "WRITE_SMS",
328            "RECEIVE_SMS",
329            "RECEIVE_EMERGECY_SMS",
330            "RECEIVE_MMS",
331            "RECEIVE_WAP_PUSH",
332            "SEND_SMS",
333            "READ_ICC_SMS",
334            "WRITE_ICC_SMS",
335            "WRITE_SETTINGS",
336            "SYSTEM_ALERT_WINDOW",
337            "ACCESS_NOTIFICATIONS",
338            "CAMERA",
339            "RECORD_AUDIO",
340            "PLAY_AUDIO",
341            "READ_CLIPBOARD",
342            "WRITE_CLIPBOARD",
343            "TAKE_MEDIA_BUTTONS",
344            "TAKE_AUDIO_FOCUS",
345            "AUDIO_MASTER_VOLUME",
346            "AUDIO_VOICE_VOLUME",
347            "AUDIO_RING_VOLUME",
348            "AUDIO_MEDIA_VOLUME",
349            "AUDIO_ALARM_VOLUME",
350            "AUDIO_NOTIFICATION_VOLUME",
351            "AUDIO_BLUETOOTH_VOLUME",
352            "WAKE_LOCK",
353            "MONITOR_LOCATION",
354            "MONITOR_HIGH_POWER_LOCATION",
355    };
356
357    /**
358     * This optionally maps a permission to an operation.  If there
359     * is no permission associated with an operation, it is null.
360     */
361    private static String[] sOpPerms = new String[] {
362            android.Manifest.permission.ACCESS_COARSE_LOCATION,
363            android.Manifest.permission.ACCESS_FINE_LOCATION,
364            null,
365            android.Manifest.permission.VIBRATE,
366            android.Manifest.permission.READ_CONTACTS,
367            android.Manifest.permission.WRITE_CONTACTS,
368            android.Manifest.permission.READ_CALL_LOG,
369            android.Manifest.permission.WRITE_CALL_LOG,
370            android.Manifest.permission.READ_CALENDAR,
371            android.Manifest.permission.WRITE_CALENDAR,
372            null, // no permission required for notifications
373            android.Manifest.permission.ACCESS_WIFI_STATE,
374            null, // neighboring cells shares the coarse location perm
375            android.Manifest.permission.CALL_PHONE,
376            android.Manifest.permission.READ_SMS,
377            android.Manifest.permission.WRITE_SMS,
378            android.Manifest.permission.RECEIVE_SMS,
379            android.Manifest.permission.RECEIVE_EMERGENCY_BROADCAST,
380            android.Manifest.permission.RECEIVE_MMS,
381            android.Manifest.permission.RECEIVE_WAP_PUSH,
382            android.Manifest.permission.SEND_SMS,
383            android.Manifest.permission.READ_SMS,
384            android.Manifest.permission.WRITE_SMS,
385            android.Manifest.permission.WRITE_SETTINGS,
386            android.Manifest.permission.SYSTEM_ALERT_WINDOW,
387            android.Manifest.permission.ACCESS_NOTIFICATIONS,
388            android.Manifest.permission.CAMERA,
389            android.Manifest.permission.RECORD_AUDIO,
390            null, // no permission for playing audio
391            null, // no permission for reading clipboard
392            null, // no permission for writing clipboard
393            null, // no permission for taking media buttons
394            null, // no permission for taking audio focus
395            null, // no permission for changing master volume
396            null, // no permission for changing voice volume
397            null, // no permission for changing ring volume
398            null, // no permission for changing media volume
399            null, // no permission for changing alarm volume
400            null, // no permission for changing notification volume
401            null, // no permission for changing bluetooth volume
402            android.Manifest.permission.WAKE_LOCK,
403            null, // no permission for generic location monitoring
404            null, // no permission for high power location monitoring
405    };
406
407    /**
408     * This specifies the default mode for each operation.
409     */
410    private static int[] sOpDefaultMode = new int[] {
411            AppOpsManager.MODE_ALLOWED,
412            AppOpsManager.MODE_ALLOWED,
413            AppOpsManager.MODE_ALLOWED,
414            AppOpsManager.MODE_ALLOWED,
415            AppOpsManager.MODE_ALLOWED,
416            AppOpsManager.MODE_ALLOWED,
417            AppOpsManager.MODE_ALLOWED,
418            AppOpsManager.MODE_ALLOWED,
419            AppOpsManager.MODE_ALLOWED,
420            AppOpsManager.MODE_ALLOWED,
421            AppOpsManager.MODE_ALLOWED,
422            AppOpsManager.MODE_ALLOWED,
423            AppOpsManager.MODE_ALLOWED,
424            AppOpsManager.MODE_ALLOWED,
425            AppOpsManager.MODE_ALLOWED,
426            AppOpsManager.MODE_IGNORED, // OP_WRITE_SMS
427            AppOpsManager.MODE_ALLOWED,
428            AppOpsManager.MODE_ALLOWED,
429            AppOpsManager.MODE_ALLOWED,
430            AppOpsManager.MODE_ALLOWED,
431            AppOpsManager.MODE_ALLOWED,
432            AppOpsManager.MODE_ALLOWED,
433            AppOpsManager.MODE_ALLOWED,
434            AppOpsManager.MODE_ALLOWED,
435            AppOpsManager.MODE_ALLOWED,
436            AppOpsManager.MODE_ALLOWED,
437            AppOpsManager.MODE_ALLOWED,
438            AppOpsManager.MODE_ALLOWED,
439            AppOpsManager.MODE_ALLOWED,
440            AppOpsManager.MODE_ALLOWED,
441            AppOpsManager.MODE_ALLOWED,
442            AppOpsManager.MODE_ALLOWED,
443            AppOpsManager.MODE_ALLOWED,
444            AppOpsManager.MODE_ALLOWED,
445            AppOpsManager.MODE_ALLOWED,
446            AppOpsManager.MODE_ALLOWED,
447            AppOpsManager.MODE_ALLOWED,
448            AppOpsManager.MODE_ALLOWED,
449            AppOpsManager.MODE_ALLOWED,
450            AppOpsManager.MODE_ALLOWED,
451            AppOpsManager.MODE_ALLOWED,
452            AppOpsManager.MODE_ALLOWED,
453            AppOpsManager.MODE_ALLOWED,
454    };
455
456    /**
457     * This specifies whether each option is allowed to be reset
458     * when resetting all app preferences.  Disable reset for
459     * app ops that are under strong control of some part of the
460     * system (such as OP_WRITE_SMS, which should be allowed only
461     * for whichever app is selected as the current SMS app).
462     */
463    private static boolean[] sOpDisableReset = new boolean[] {
464            false,
465            false,
466            false,
467            false,
468            false,
469            false,
470            false,
471            false,
472            false,
473            false,
474            false,
475            false,
476            false,
477            false,
478            false,
479            true,      // OP_WRITE_SMS
480            false,
481            false,
482            false,
483            false,
484            false,
485            false,
486            false,
487            false,
488            false,
489            false,
490            false,
491            false,
492            false,
493            false,
494            false,
495            false,
496            false,
497            false,
498            false,
499            false,
500            false,
501            false,
502            false,
503            false,
504            false,
505            false,
506            false,
507    };
508
509    private static HashMap<String, Integer> sOpStrToOp = new HashMap<String, Integer>();
510
511    static {
512        if (sOpToSwitch.length != _NUM_OP) {
513            throw new IllegalStateException("sOpToSwitch length " + sOpToSwitch.length
514                    + " should be " + _NUM_OP);
515        }
516        if (sOpToString.length != _NUM_OP) {
517            throw new IllegalStateException("sOpToString length " + sOpToString.length
518                    + " should be " + _NUM_OP);
519        }
520        if (sOpNames.length != _NUM_OP) {
521            throw new IllegalStateException("sOpNames length " + sOpNames.length
522                    + " should be " + _NUM_OP);
523        }
524        if (sOpPerms.length != _NUM_OP) {
525            throw new IllegalStateException("sOpPerms length " + sOpPerms.length
526                    + " should be " + _NUM_OP);
527        }
528        if (sOpDefaultMode.length != _NUM_OP) {
529            throw new IllegalStateException("sOpDefaultMode length " + sOpDefaultMode.length
530                    + " should be " + _NUM_OP);
531        }
532        if (sOpDisableReset.length != _NUM_OP) {
533            throw new IllegalStateException("sOpDisableReset length " + sOpDisableReset.length
534                    + " should be " + _NUM_OP);
535        }
536        for (int i=0; i<_NUM_OP; i++) {
537            if (sOpToString[i] != null) {
538                sOpStrToOp.put(sOpToString[i], i);
539            }
540        }
541    }
542
543    /**
544     * Retrieve the op switch that controls the given operation.
545     * @hide
546     */
547    public static int opToSwitch(int op) {
548        return sOpToSwitch[op];
549    }
550
551    /**
552     * Retrieve a non-localized name for the operation, for debugging output.
553     * @hide
554     */
555    public static String opToName(int op) {
556        if (op == OP_NONE) return "NONE";
557        return op < sOpNames.length ? sOpNames[op] : ("Unknown(" + op + ")");
558    }
559
560    /**
561     * Retrieve the permission associated with an operation, or null if there is not one.
562     * @hide
563     */
564    public static String opToPermission(int op) {
565        return sOpPerms[op];
566    }
567
568    /**
569     * Retrieve the default mode for the operation.
570     * @hide
571     */
572    public static int opToDefaultMode(int op) {
573        return sOpDefaultMode[op];
574    }
575
576    /**
577     * Retrieve whether the op allows itself to be reset.
578     * @hide
579     */
580    public static boolean opAllowsReset(int op) {
581        return !sOpDisableReset[op];
582    }
583
584    /**
585     * Class holding all of the operation information associated with an app.
586     * @hide
587     */
588    public static class PackageOps implements Parcelable {
589        private final String mPackageName;
590        private final int mUid;
591        private final List<OpEntry> mEntries;
592
593        public PackageOps(String packageName, int uid, List<OpEntry> entries) {
594            mPackageName = packageName;
595            mUid = uid;
596            mEntries = entries;
597        }
598
599        public String getPackageName() {
600            return mPackageName;
601        }
602
603        public int getUid() {
604            return mUid;
605        }
606
607        public List<OpEntry> getOps() {
608            return mEntries;
609        }
610
611        @Override
612        public int describeContents() {
613            return 0;
614        }
615
616        @Override
617        public void writeToParcel(Parcel dest, int flags) {
618            dest.writeString(mPackageName);
619            dest.writeInt(mUid);
620            dest.writeInt(mEntries.size());
621            for (int i=0; i<mEntries.size(); i++) {
622                mEntries.get(i).writeToParcel(dest, flags);
623            }
624        }
625
626        PackageOps(Parcel source) {
627            mPackageName = source.readString();
628            mUid = source.readInt();
629            mEntries = new ArrayList<OpEntry>();
630            final int N = source.readInt();
631            for (int i=0; i<N; i++) {
632                mEntries.add(OpEntry.CREATOR.createFromParcel(source));
633            }
634        }
635
636        public static final Creator<PackageOps> CREATOR = new Creator<PackageOps>() {
637            @Override public PackageOps createFromParcel(Parcel source) {
638                return new PackageOps(source);
639            }
640
641            @Override public PackageOps[] newArray(int size) {
642                return new PackageOps[size];
643            }
644        };
645    }
646
647    /**
648     * Class holding the information about one unique operation of an application.
649     * @hide
650     */
651    public static class OpEntry implements Parcelable {
652        private final int mOp;
653        private final int mMode;
654        private final long mTime;
655        private final long mRejectTime;
656        private final int mDuration;
657
658        public OpEntry(int op, int mode, long time, long rejectTime, int duration) {
659            mOp = op;
660            mMode = mode;
661            mTime = time;
662            mRejectTime = rejectTime;
663            mDuration = duration;
664        }
665
666        public int getOp() {
667            return mOp;
668        }
669
670        public int getMode() {
671            return mMode;
672        }
673
674        public long getTime() {
675            return mTime;
676        }
677
678        public long getRejectTime() {
679            return mRejectTime;
680        }
681
682        public boolean isRunning() {
683            return mDuration == -1;
684        }
685
686        public int getDuration() {
687            return mDuration == -1 ? (int)(System.currentTimeMillis()-mTime) : mDuration;
688        }
689
690        @Override
691        public int describeContents() {
692            return 0;
693        }
694
695        @Override
696        public void writeToParcel(Parcel dest, int flags) {
697            dest.writeInt(mOp);
698            dest.writeInt(mMode);
699            dest.writeLong(mTime);
700            dest.writeLong(mRejectTime);
701            dest.writeInt(mDuration);
702        }
703
704        OpEntry(Parcel source) {
705            mOp = source.readInt();
706            mMode = source.readInt();
707            mTime = source.readLong();
708            mRejectTime = source.readLong();
709            mDuration = source.readInt();
710        }
711
712        public static final Creator<OpEntry> CREATOR = new Creator<OpEntry>() {
713            @Override public OpEntry createFromParcel(Parcel source) {
714                return new OpEntry(source);
715            }
716
717            @Override public OpEntry[] newArray(int size) {
718                return new OpEntry[size];
719            }
720        };
721    }
722
723    /**
724     * Callback for notification of changes to operation state.
725     */
726    public interface OnOpChangedListener {
727        public void onOpChanged(String op, String packageName);
728    }
729
730    /**
731     * Callback for notification of changes to operation state.
732     * This allows you to see the raw op codes instead of strings.
733     * @hide
734     */
735    public static class OnOpChangedInternalListener implements OnOpChangedListener {
736        public void onOpChanged(String op, String packageName) { }
737        public void onOpChanged(int op, String packageName) { }
738    }
739
740    AppOpsManager(Context context, IAppOpsService service) {
741        mContext = context;
742        mService = service;
743    }
744
745    /**
746     * Retrieve current operation state for all applications.
747     *
748     * @param ops The set of operations you are interested in, or null if you want all of them.
749     * @hide
750     */
751    public List<AppOpsManager.PackageOps> getPackagesForOps(int[] ops) {
752        try {
753            return mService.getPackagesForOps(ops);
754        } catch (RemoteException e) {
755        }
756        return null;
757    }
758
759    /**
760     * Retrieve current operation state for one application.
761     *
762     * @param uid The uid of the application of interest.
763     * @param packageName The name of the application of interest.
764     * @param ops The set of operations you are interested in, or null if you want all of them.
765     * @hide
766     */
767    public List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName, int[] ops) {
768        try {
769            return mService.getOpsForPackage(uid, packageName, ops);
770        } catch (RemoteException e) {
771        }
772        return null;
773    }
774
775    /** @hide */
776    public void setMode(int code, int uid, String packageName, int mode) {
777        try {
778            mService.setMode(code, uid, packageName, mode);
779        } catch (RemoteException e) {
780        }
781    }
782
783    /** @hide */
784    public void resetAllModes() {
785        try {
786            mService.resetAllModes();
787        } catch (RemoteException e) {
788        }
789    }
790
791    /**
792     * Monitor for changes to the operating mode for the given op in the given app package.
793     * @param op The operation to monitor, one of OPSTR_*.
794     * @param packageName The name of the application to monitor.
795     * @param callback Where to report changes.
796     */
797    public void startWatchingMode(String op, String packageName,
798            final OnOpChangedListener callback) {
799        startWatchingMode(strOpToOp(op), packageName, callback);
800    }
801
802    /**
803     * Monitor for changes to the operating mode for the given op in the given app package.
804     * @param op The operation to monitor, one of OP_*.
805     * @param packageName The name of the application to monitor.
806     * @param callback Where to report changes.
807     * @hide
808     */
809    public void startWatchingMode(int op, String packageName, final OnOpChangedListener callback) {
810        synchronized (mModeWatchers) {
811            IAppOpsCallback cb = mModeWatchers.get(callback);
812            if (cb == null) {
813                cb = new IAppOpsCallback.Stub() {
814                    public void opChanged(int op, String packageName) {
815                        if (callback instanceof OnOpChangedInternalListener) {
816                            ((OnOpChangedInternalListener)callback).onOpChanged(op, packageName);
817                        }
818                        if (sOpToString[op] != null) {
819                            callback.onOpChanged(sOpToString[op], packageName);
820                        }
821                    }
822                };
823                mModeWatchers.put(callback, cb);
824            }
825            try {
826                mService.startWatchingMode(op, packageName, cb);
827            } catch (RemoteException e) {
828            }
829        }
830    }
831
832    /**
833     * Stop monitoring that was previously started with {@link #startWatchingMode}.  All
834     * monitoring associated with this callback will be removed.
835     */
836    public void stopWatchingMode(OnOpChangedListener callback) {
837        synchronized (mModeWatchers) {
838            IAppOpsCallback cb = mModeWatchers.get(callback);
839            if (cb != null) {
840                try {
841                    mService.stopWatchingMode(cb);
842                } catch (RemoteException e) {
843                }
844            }
845        }
846    }
847
848    private String buildSecurityExceptionMsg(int op, int uid, String packageName) {
849        return packageName + " from uid " + uid + " not allowed to perform " + sOpNames[op];
850    }
851
852    private int strOpToOp(String op) {
853        Integer val = sOpStrToOp.get(op);
854        if (val == null) {
855            throw new IllegalArgumentException("Unknown operation string: " + op);
856        }
857        return val;
858    }
859
860    /**
861     * Do a quick check for whether an application might be able to perform an operation.
862     * This is <em>not</em> a security check; you must use {@link #noteOp(String, int, String)}
863     * or {@link #startOp(String, int, String)} for your actual security checks, which also
864     * ensure that the given uid and package name are consistent.  This function can just be
865     * used for a quick check to see if an operation has been disabled for the application,
866     * as an early reject of some work.  This does not modify the time stamp or other data
867     * about the operation.
868     * @param op The operation to check.  One of the OPSTR_* constants.
869     * @param uid The user id of the application attempting to perform the operation.
870     * @param packageName The name of the application attempting to perform the operation.
871     * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or
872     * {@link #MODE_IGNORED} if it is not allowed and should be silently ignored (without
873     * causing the app to crash).
874     * @throws SecurityException If the app has been configured to crash on this op.
875     */
876    public int checkOp(String op, int uid, String packageName) {
877        return checkOp(strOpToOp(op), uid, packageName);
878    }
879
880    /**
881     * Like {@link #checkOp but instead of throwing a {@link SecurityException} it
882     * returns {@link #MODE_ERRORED}.
883     */
884    public int checkOpNoThrow(String op, int uid, String packageName) {
885        return checkOpNoThrow(strOpToOp(op), uid, packageName);
886    }
887
888    /**
889     * Make note of an application performing an operation.  Note that you must pass
890     * in both the uid and name of the application to be checked; this function will verify
891     * that these two match, and if not, return {@link #MODE_IGNORED}.  If this call
892     * succeeds, the last execution time of the operation for this app will be updated to
893     * the current time.
894     * @param op The operation to note.  One of the OPSTR_* constants.
895     * @param uid The user id of the application attempting to perform the operation.
896     * @param packageName The name of the application attempting to perform the operation.
897     * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or
898     * {@link #MODE_IGNORED} if it is not allowed and should be silently ignored (without
899     * causing the app to crash).
900     * @throws SecurityException If the app has been configured to crash on this op.
901     */
902    public int noteOp(String op, int uid, String packageName) {
903        return noteOp(strOpToOp(op), uid, packageName);
904    }
905
906    /**
907     * Like {@link #noteOp} but instead of throwing a {@link SecurityException} it
908     * returns {@link #MODE_ERRORED}.
909     */
910    public int noteOpNoThrow(String op, int uid, String packageName) {
911        return noteOpNoThrow(strOpToOp(op), uid, packageName);
912    }
913
914    /**
915     * Report that an application has started executing a long-running operation.  Note that you
916     * must pass in both the uid and name of the application to be checked; this function will
917     * verify that these two match, and if not, return {@link #MODE_IGNORED}.  If this call
918     * succeeds, the last execution time of the operation for this app will be updated to
919     * the current time and the operation will be marked as "running".  In this case you must
920     * later call {@link #finishOp(String, int, String)} to report when the application is no
921     * longer performing the operation.
922     * @param op The operation to start.  One of the OPSTR_* constants.
923     * @param uid The user id of the application attempting to perform the operation.
924     * @param packageName The name of the application attempting to perform the operation.
925     * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or
926     * {@link #MODE_IGNORED} if it is not allowed and should be silently ignored (without
927     * causing the app to crash).
928     * @throws SecurityException If the app has been configured to crash on this op.
929     */
930    public int startOp(String op, int uid, String packageName) {
931        return startOp(strOpToOp(op), uid, packageName);
932    }
933
934    /**
935     * Like {@link #startOp} but instead of throwing a {@link SecurityException} it
936     * returns {@link #MODE_ERRORED}.
937     */
938    public int startOpNoThrow(String op, int uid, String packageName) {
939        return startOpNoThrow(strOpToOp(op), uid, packageName);
940    }
941
942    /**
943     * Report that an application is no longer performing an operation that had previously
944     * been started with {@link #startOp(String, int, String)}.  There is no validation of input
945     * or result; the parameters supplied here must be the exact same ones previously passed
946     * in when starting the operation.
947     */
948    public void finishOp(String op, int uid, String packageName) {
949        finishOp(strOpToOp(op), uid, packageName);
950    }
951
952    /**
953     * Do a quick check for whether an application might be able to perform an operation.
954     * This is <em>not</em> a security check; you must use {@link #noteOp(int, int, String)}
955     * or {@link #startOp(int, int, String)} for your actual security checks, which also
956     * ensure that the given uid and package name are consistent.  This function can just be
957     * used for a quick check to see if an operation has been disabled for the application,
958     * as an early reject of some work.  This does not modify the time stamp or other data
959     * about the operation.
960     * @param op The operation to check.  One of the OP_* constants.
961     * @param uid The user id of the application attempting to perform the operation.
962     * @param packageName The name of the application attempting to perform the operation.
963     * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or
964     * {@link #MODE_IGNORED} if it is not allowed and should be silently ignored (without
965     * causing the app to crash).
966     * @throws SecurityException If the app has been configured to crash on this op.
967     * @hide
968     */
969    public int checkOp(int op, int uid, String packageName) {
970        try {
971            int mode = mService.checkOperation(op, uid, packageName);
972            if (mode == MODE_ERRORED) {
973                throw new SecurityException(buildSecurityExceptionMsg(op, uid, packageName));
974            }
975            return mode;
976        } catch (RemoteException e) {
977        }
978        return MODE_IGNORED;
979    }
980
981    /**
982     * Like {@link #checkOp} but instead of throwing a {@link SecurityException} it
983     * returns {@link #MODE_ERRORED}.
984     * @hide
985     */
986    public int checkOpNoThrow(int op, int uid, String packageName) {
987        try {
988            return mService.checkOperation(op, uid, packageName);
989        } catch (RemoteException e) {
990        }
991        return MODE_IGNORED;
992    }
993
994    /**
995     * Do a quick check to validate if a package name belongs to a UID.
996     *
997     * @throws SecurityException if the package name doesn't belong to the given
998     *             UID, or if ownership cannot be verified.
999     */
1000    public void checkPackage(int uid, String packageName) {
1001        try {
1002            if (mService.checkPackage(uid, packageName) != MODE_ALLOWED) {
1003                throw new SecurityException(
1004                        "Package " + packageName + " does not belong to " + uid);
1005            }
1006        } catch (RemoteException e) {
1007            throw new SecurityException("Unable to verify package ownership", e);
1008        }
1009    }
1010
1011    /**
1012     * Make note of an application performing an operation.  Note that you must pass
1013     * in both the uid and name of the application to be checked; this function will verify
1014     * that these two match, and if not, return {@link #MODE_IGNORED}.  If this call
1015     * succeeds, the last execution time of the operation for this app will be updated to
1016     * the current time.
1017     * @param op The operation to note.  One of the OP_* constants.
1018     * @param uid The user id of the application attempting to perform the operation.
1019     * @param packageName The name of the application attempting to perform the operation.
1020     * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or
1021     * {@link #MODE_IGNORED} if it is not allowed and should be silently ignored (without
1022     * causing the app to crash).
1023     * @throws SecurityException If the app has been configured to crash on this op.
1024     * @hide
1025     */
1026    public int noteOp(int op, int uid, String packageName) {
1027        try {
1028            int mode = mService.noteOperation(op, uid, packageName);
1029            if (mode == MODE_ERRORED) {
1030                throw new SecurityException(buildSecurityExceptionMsg(op, uid, packageName));
1031            }
1032            return mode;
1033        } catch (RemoteException e) {
1034        }
1035        return MODE_IGNORED;
1036    }
1037
1038    /**
1039     * Like {@link #noteOp} but instead of throwing a {@link SecurityException} it
1040     * returns {@link #MODE_ERRORED}.
1041     * @hide
1042     */
1043    public int noteOpNoThrow(int op, int uid, String packageName) {
1044        try {
1045            return mService.noteOperation(op, uid, packageName);
1046        } catch (RemoteException e) {
1047        }
1048        return MODE_IGNORED;
1049    }
1050
1051    /** @hide */
1052    public int noteOp(int op) {
1053        return noteOp(op, Process.myUid(), mContext.getOpPackageName());
1054    }
1055
1056    /** @hide */
1057    public static IBinder getToken(IAppOpsService service) {
1058        synchronized (AppOpsManager.class) {
1059            if (sToken != null) {
1060                return sToken;
1061            }
1062            try {
1063                sToken = service.getToken(new Binder());
1064            } catch (RemoteException e) {
1065                // System is dead, whatevs.
1066            }
1067            return sToken;
1068        }
1069    }
1070
1071    /**
1072     * Report that an application has started executing a long-running operation.  Note that you
1073     * must pass in both the uid and name of the application to be checked; this function will
1074     * verify that these two match, and if not, return {@link #MODE_IGNORED}.  If this call
1075     * succeeds, the last execution time of the operation for this app will be updated to
1076     * the current time and the operation will be marked as "running".  In this case you must
1077     * later call {@link #finishOp(int, int, String)} to report when the application is no
1078     * longer performing the operation.
1079     * @param op The operation to start.  One of the OP_* constants.
1080     * @param uid The user id of the application attempting to perform the operation.
1081     * @param packageName The name of the application attempting to perform the operation.
1082     * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or
1083     * {@link #MODE_IGNORED} if it is not allowed and should be silently ignored (without
1084     * causing the app to crash).
1085     * @throws SecurityException If the app has been configured to crash on this op.
1086     * @hide
1087     */
1088    public int startOp(int op, int uid, String packageName) {
1089        try {
1090            int mode = mService.startOperation(getToken(mService), op, uid, packageName);
1091            if (mode == MODE_ERRORED) {
1092                throw new SecurityException(buildSecurityExceptionMsg(op, uid, packageName));
1093            }
1094            return mode;
1095        } catch (RemoteException e) {
1096        }
1097        return MODE_IGNORED;
1098    }
1099
1100    /**
1101     * Like {@link #startOp} but instead of throwing a {@link SecurityException} it
1102     * returns {@link #MODE_ERRORED}.
1103     * @hide
1104     */
1105    public int startOpNoThrow(int op, int uid, String packageName) {
1106        try {
1107            return mService.startOperation(getToken(mService), op, uid, packageName);
1108        } catch (RemoteException e) {
1109        }
1110        return MODE_IGNORED;
1111    }
1112
1113    /** @hide */
1114    public int startOp(int op) {
1115        return startOp(op, Process.myUid(), mContext.getOpPackageName());
1116    }
1117
1118    /**
1119     * Report that an application is no longer performing an operation that had previously
1120     * been started with {@link #startOp(int, int, String)}.  There is no validation of input
1121     * or result; the parameters supplied here must be the exact same ones previously passed
1122     * in when starting the operation.
1123     * @hide
1124     */
1125    public void finishOp(int op, int uid, String packageName) {
1126        try {
1127            mService.finishOperation(getToken(mService), op, uid, packageName);
1128        } catch (RemoteException e) {
1129        }
1130    }
1131
1132    /** @hide */
1133    public void finishOp(int op) {
1134        finishOp(op, Process.myUid(), mContext.getOpPackageName());
1135    }
1136}
1137