AppOpsManager.java revision 18966a8dd8dfae553eaaafa87a656af3b7518fc6
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.List;
27
28import android.content.Context;
29import android.os.Parcel;
30import android.os.Parcelable;
31import android.os.Process;
32import android.os.RemoteException;
33
34/**
35 * API for interacting with "application operation" tracking.  Allows you to:
36 *
37 * <ul>
38 * <li> Note when operations are happening, and find out if they are allowed for the current
39 * caller.</li>
40 * <li> Disallow specific apps from doing specific operations.</li>
41 * <li> Collect all of the current information about operations that have been executed or are not
42 * being allowed.</li>
43 * <li> Monitor for changes in whether an operation is allowed.</li>
44 * </ul>
45 *
46 * <p>Each operation is identified by a single integer; these integers are a fixed set of
47 * operations, enumerated by the OP_* constants.
48 *
49 * <p></p>When checking operations, the result is a "mode" integer indicating the current setting
50 * for the operation under that caller: MODE_ALLOWED, MODE_IGNORED (don't execute the operation but
51 * fake its behavior enough so that the caller doesn't crash), MODE_ERRORED (through a
52 * SecurityException back to the caller; the normal operation calls will do this for you).
53 */
54public class AppOpsManager {
55    final Context mContext;
56    final IAppOpsService mService;
57    final ArrayMap<Callback, IAppOpsCallback> mModeWatchers
58            = new ArrayMap<Callback, IAppOpsCallback>();
59
60    static IBinder sToken;
61
62    public static final int MODE_ALLOWED = 0;
63    public static final int MODE_IGNORED = 1;
64    public static final int MODE_ERRORED = 2;
65
66    // when adding one of these:
67    //  - increment _NUM_OP
68    //  - add rows to sOpToSwitch, sOpNames, sOpPerms
69    //  - add descriptive strings to Settings/res/values/arrays.xml
70    //  - add the op to the appropriate template in AppOpsState.OpsTemplate (settings app)
71
72    /** No operation specified. */
73    public static final int OP_NONE = -1;
74    /** Access to coarse location information. */
75    public static final int OP_COARSE_LOCATION = 0;
76    /** Access to fine location information. */
77    public static final int OP_FINE_LOCATION = 1;
78    /** Causing GPS to run. */
79    public static final int OP_GPS = 2;
80    /** @hide */
81    public static final int OP_VIBRATE = 3;
82    /** @hide */
83    public static final int OP_READ_CONTACTS = 4;
84    /** @hide */
85    public static final int OP_WRITE_CONTACTS = 5;
86    /** @hide */
87    public static final int OP_READ_CALL_LOG = 6;
88    /** @hide */
89    public static final int OP_WRITE_CALL_LOG = 7;
90    /** @hide */
91    public static final int OP_READ_CALENDAR = 8;
92    /** @hide */
93    public static final int OP_WRITE_CALENDAR = 9;
94    /** @hide */
95    public static final int OP_WIFI_SCAN = 10;
96    /** @hide */
97    public static final int OP_POST_NOTIFICATION = 11;
98    /** @hide */
99    public static final int OP_NEIGHBORING_CELLS = 12;
100    /** @hide */
101    public static final int OP_CALL_PHONE = 13;
102    /** @hide */
103    public static final int OP_READ_SMS = 14;
104    /** @hide */
105    public static final int OP_WRITE_SMS = 15;
106    /** @hide */
107    public static final int OP_RECEIVE_SMS = 16;
108    /** @hide */
109    public static final int OP_RECEIVE_EMERGECY_SMS = 17;
110    /** @hide */
111    public static final int OP_RECEIVE_MMS = 18;
112    /** @hide */
113    public static final int OP_RECEIVE_WAP_PUSH = 19;
114    /** @hide */
115    public static final int OP_SEND_SMS = 20;
116    /** @hide */
117    public static final int OP_READ_ICC_SMS = 21;
118    /** @hide */
119    public static final int OP_WRITE_ICC_SMS = 22;
120    /** @hide */
121    public static final int OP_WRITE_SETTINGS = 23;
122    /** @hide */
123    public static final int OP_SYSTEM_ALERT_WINDOW = 24;
124    /** @hide */
125    public static final int OP_ACCESS_NOTIFICATIONS = 25;
126    /** @hide */
127    public static final int OP_CAMERA = 26;
128    /** @hide */
129    public static final int OP_RECORD_AUDIO = 27;
130    /** @hide */
131    public static final int OP_PLAY_AUDIO = 28;
132    /** @hide */
133    public static final int OP_READ_CLIPBOARD = 29;
134    /** @hide */
135    public static final int OP_WRITE_CLIPBOARD = 30;
136    /** @hide */
137    public static final int OP_TAKE_MEDIA_BUTTONS = 31;
138    /** @hide */
139    public static final int OP_TAKE_AUDIO_FOCUS = 32;
140    /** @hide */
141    public static final int OP_AUDIO_MASTER_VOLUME = 33;
142    /** @hide */
143    public static final int OP_AUDIO_VOICE_VOLUME = 34;
144    /** @hide */
145    public static final int OP_AUDIO_RING_VOLUME = 35;
146    /** @hide */
147    public static final int OP_AUDIO_MEDIA_VOLUME = 36;
148    /** @hide */
149    public static final int OP_AUDIO_ALARM_VOLUME = 37;
150    /** @hide */
151    public static final int OP_AUDIO_NOTIFICATION_VOLUME = 38;
152    /** @hide */
153    public static final int OP_AUDIO_BLUETOOTH_VOLUME = 39;
154    /** @hide */
155    public static final int OP_WAKE_LOCK = 40;
156    /** Continually monitoring location data. */
157    public static final int OP_MONITOR_LOCATION = 41;
158    /** Continually monitoring location data with a relatively high power request. */
159    public static final int OP_MONITOR_HIGH_POWER_LOCATION = 42;
160    /** @hide */
161    public static final int _NUM_OP = 43;
162
163    /**
164     * This maps each operation to the operation that serves as the
165     * switch to determine whether it is allowed.  Generally this is
166     * a 1:1 mapping, but for some things (like location) that have
167     * multiple low-level operations being tracked that should be
168     * presented to the user as one switch then this can be used to
169     * make them all controlled by the same single operation.
170     */
171    private static int[] sOpToSwitch = new int[] {
172            OP_COARSE_LOCATION,
173            OP_COARSE_LOCATION,
174            OP_COARSE_LOCATION,
175            OP_VIBRATE,
176            OP_READ_CONTACTS,
177            OP_WRITE_CONTACTS,
178            OP_READ_CALL_LOG,
179            OP_WRITE_CALL_LOG,
180            OP_READ_CALENDAR,
181            OP_WRITE_CALENDAR,
182            OP_COARSE_LOCATION,
183            OP_POST_NOTIFICATION,
184            OP_COARSE_LOCATION,
185            OP_CALL_PHONE,
186            OP_READ_SMS,
187            OP_WRITE_SMS,
188            OP_RECEIVE_SMS,
189            OP_RECEIVE_SMS,
190            OP_RECEIVE_SMS,
191            OP_RECEIVE_SMS,
192            OP_SEND_SMS,
193            OP_READ_SMS,
194            OP_WRITE_SMS,
195            OP_WRITE_SETTINGS,
196            OP_SYSTEM_ALERT_WINDOW,
197            OP_ACCESS_NOTIFICATIONS,
198            OP_CAMERA,
199            OP_RECORD_AUDIO,
200            OP_PLAY_AUDIO,
201            OP_READ_CLIPBOARD,
202            OP_WRITE_CLIPBOARD,
203            OP_TAKE_MEDIA_BUTTONS,
204            OP_TAKE_AUDIO_FOCUS,
205            OP_AUDIO_MASTER_VOLUME,
206            OP_AUDIO_VOICE_VOLUME,
207            OP_AUDIO_RING_VOLUME,
208            OP_AUDIO_MEDIA_VOLUME,
209            OP_AUDIO_ALARM_VOLUME,
210            OP_AUDIO_NOTIFICATION_VOLUME,
211            OP_AUDIO_BLUETOOTH_VOLUME,
212            OP_WAKE_LOCK,
213            OP_COARSE_LOCATION,
214            OP_COARSE_LOCATION,
215    };
216
217    /**
218     * This provides a simple name for each operation to be used
219     * in debug output.
220     */
221    private static String[] sOpNames = new String[] {
222            "COARSE_LOCATION",
223            "FINE_LOCATION",
224            "GPS",
225            "VIBRATE",
226            "READ_CONTACTS",
227            "WRITE_CONTACTS",
228            "READ_CALL_LOG",
229            "WRITE_CALL_LOG",
230            "READ_CALENDAR",
231            "WRITE_CALENDAR",
232            "WIFI_SCAN",
233            "POST_NOTIFICATION",
234            "NEIGHBORING_CELLS",
235            "CALL_PHONE",
236            "READ_SMS",
237            "WRITE_SMS",
238            "RECEIVE_SMS",
239            "RECEIVE_EMERGECY_SMS",
240            "RECEIVE_MMS",
241            "RECEIVE_WAP_PUSH",
242            "SEND_SMS",
243            "READ_ICC_SMS",
244            "WRITE_ICC_SMS",
245            "WRITE_SETTINGS",
246            "SYSTEM_ALERT_WINDOW",
247            "ACCESS_NOTIFICATIONS",
248            "CAMERA",
249            "RECORD_AUDIO",
250            "PLAY_AUDIO",
251            "READ_CLIPBOARD",
252            "WRITE_CLIPBOARD",
253            "TAKE_MEDIA_BUTTONS",
254            "TAKE_AUDIO_FOCUS",
255            "AUDIO_MASTER_VOLUME",
256            "AUDIO_VOICE_VOLUME",
257            "AUDIO_RING_VOLUME",
258            "AUDIO_MEDIA_VOLUME",
259            "AUDIO_ALARM_VOLUME",
260            "AUDIO_NOTIFICATION_VOLUME",
261            "AUDIO_BLUETOOTH_VOLUME",
262            "WAKE_LOCK",
263            "MONITOR_LOCATION",
264            "MONITOR_HIGH_POWER_LOCATION",
265    };
266
267    /**
268     * This optionally maps a permission to an operation.  If there
269     * is no permission associated with an operation, it is null.
270     */
271    private static String[] sOpPerms = new String[] {
272            android.Manifest.permission.ACCESS_COARSE_LOCATION,
273            android.Manifest.permission.ACCESS_FINE_LOCATION,
274            null,
275            android.Manifest.permission.VIBRATE,
276            android.Manifest.permission.READ_CONTACTS,
277            android.Manifest.permission.WRITE_CONTACTS,
278            android.Manifest.permission.READ_CALL_LOG,
279            android.Manifest.permission.WRITE_CALL_LOG,
280            android.Manifest.permission.READ_CALENDAR,
281            android.Manifest.permission.WRITE_CALENDAR,
282            null, // no permission required for notifications
283            android.Manifest.permission.ACCESS_WIFI_STATE,
284            null, // neighboring cells shares the coarse location perm
285            android.Manifest.permission.CALL_PHONE,
286            android.Manifest.permission.READ_SMS,
287            android.Manifest.permission.WRITE_SMS,
288            android.Manifest.permission.RECEIVE_SMS,
289            android.Manifest.permission.RECEIVE_EMERGENCY_BROADCAST,
290            android.Manifest.permission.RECEIVE_MMS,
291            android.Manifest.permission.RECEIVE_WAP_PUSH,
292            android.Manifest.permission.SEND_SMS,
293            android.Manifest.permission.READ_SMS,
294            android.Manifest.permission.WRITE_SMS,
295            android.Manifest.permission.WRITE_SETTINGS,
296            android.Manifest.permission.SYSTEM_ALERT_WINDOW,
297            android.Manifest.permission.ACCESS_NOTIFICATIONS,
298            android.Manifest.permission.CAMERA,
299            android.Manifest.permission.RECORD_AUDIO,
300            null, // no permission for playing audio
301            null, // no permission for reading clipboard
302            null, // no permission for writing clipboard
303            null, // no permission for taking media buttons
304            null, // no permission for taking audio focus
305            null, // no permission for changing master volume
306            null, // no permission for changing voice volume
307            null, // no permission for changing ring volume
308            null, // no permission for changing media volume
309            null, // no permission for changing alarm volume
310            null, // no permission for changing notification volume
311            null, // no permission for changing bluetooth volume
312            android.Manifest.permission.WAKE_LOCK,
313            null, // no permission for generic location monitoring
314            null, // no permission for high power location monitoring
315    };
316
317    /**
318     * Retrieve the op switch that controls the given operation.
319     * @hide
320     */
321    public static int opToSwitch(int op) {
322        return sOpToSwitch[op];
323    }
324
325    /**
326     * Retrieve a non-localized name for the operation, for debugging output.
327     */
328    public static String opToName(int op) {
329        if (op == OP_NONE) return "NONE";
330        return op < sOpNames.length ? sOpNames[op] : ("Unknown(" + op + ")");
331    }
332
333    /**
334     * Retrieve the permission associated with an operation, or null if there is not one.
335     * @hide
336     */
337    public static String opToPermission(int op) {
338        return sOpPerms[op];
339    }
340
341    /**
342     * Class holding all of the operation information associated with an app.
343     * @hide
344     */
345    public static class PackageOps implements Parcelable {
346        private final String mPackageName;
347        private final int mUid;
348        private final List<OpEntry> mEntries;
349
350        public PackageOps(String packageName, int uid, List<OpEntry> entries) {
351            mPackageName = packageName;
352            mUid = uid;
353            mEntries = entries;
354        }
355
356        public String getPackageName() {
357            return mPackageName;
358        }
359
360        public int getUid() {
361            return mUid;
362        }
363
364        public List<OpEntry> getOps() {
365            return mEntries;
366        }
367
368        @Override
369        public int describeContents() {
370            return 0;
371        }
372
373        @Override
374        public void writeToParcel(Parcel dest, int flags) {
375            dest.writeString(mPackageName);
376            dest.writeInt(mUid);
377            dest.writeInt(mEntries.size());
378            for (int i=0; i<mEntries.size(); i++) {
379                mEntries.get(i).writeToParcel(dest, flags);
380            }
381        }
382
383        PackageOps(Parcel source) {
384            mPackageName = source.readString();
385            mUid = source.readInt();
386            mEntries = new ArrayList<OpEntry>();
387            final int N = source.readInt();
388            for (int i=0; i<N; i++) {
389                mEntries.add(OpEntry.CREATOR.createFromParcel(source));
390            }
391        }
392
393        public static final Creator<PackageOps> CREATOR = new Creator<PackageOps>() {
394            @Override public PackageOps createFromParcel(Parcel source) {
395                return new PackageOps(source);
396            }
397
398            @Override public PackageOps[] newArray(int size) {
399                return new PackageOps[size];
400            }
401        };
402    }
403
404    /**
405     * Class holding the information about one unique operation of an application.
406     * @hide
407     */
408    public static class OpEntry implements Parcelable {
409        private final int mOp;
410        private final int mMode;
411        private final long mTime;
412        private final long mRejectTime;
413        private final int mDuration;
414
415        public OpEntry(int op, int mode, long time, long rejectTime, int duration) {
416            mOp = op;
417            mMode = mode;
418            mTime = time;
419            mRejectTime = rejectTime;
420            mDuration = duration;
421        }
422
423        public int getOp() {
424            return mOp;
425        }
426
427        public int getMode() {
428            return mMode;
429        }
430
431        public long getTime() {
432            return mTime;
433        }
434
435        public long getRejectTime() {
436            return mRejectTime;
437        }
438
439        public boolean isRunning() {
440            return mDuration == -1;
441        }
442
443        public int getDuration() {
444            return mDuration == -1 ? (int)(System.currentTimeMillis()-mTime) : mDuration;
445        }
446
447        @Override
448        public int describeContents() {
449            return 0;
450        }
451
452        @Override
453        public void writeToParcel(Parcel dest, int flags) {
454            dest.writeInt(mOp);
455            dest.writeInt(mMode);
456            dest.writeLong(mTime);
457            dest.writeLong(mRejectTime);
458            dest.writeInt(mDuration);
459        }
460
461        OpEntry(Parcel source) {
462            mOp = source.readInt();
463            mMode = source.readInt();
464            mTime = source.readLong();
465            mRejectTime = source.readLong();
466            mDuration = source.readInt();
467        }
468
469        public static final Creator<OpEntry> CREATOR = new Creator<OpEntry>() {
470            @Override public OpEntry createFromParcel(Parcel source) {
471                return new OpEntry(source);
472            }
473
474            @Override public OpEntry[] newArray(int size) {
475                return new OpEntry[size];
476            }
477        };
478    }
479
480    /**
481     * Callback for notification of changes to operation state.
482     */
483    public interface Callback {
484        public void opChanged(int op, String packageName);
485    }
486
487    AppOpsManager(Context context, IAppOpsService service) {
488        mContext = context;
489        mService = service;
490    }
491
492    /**
493     * Retrieve current operation state for all applications.
494     *
495     * @param ops The set of operations you are interested in, or null if you want all of them.
496     * @hide
497     */
498    public List<AppOpsManager.PackageOps> getPackagesForOps(int[] ops) {
499        try {
500            return mService.getPackagesForOps(ops);
501        } catch (RemoteException e) {
502        }
503        return null;
504    }
505
506    /**
507     * Retrieve current operation state for one application.
508     *
509     * @param uid The uid of the application of interest.
510     * @param packageName The name of the application of interest.
511     * @param ops The set of operations you are interested in, or null if you want all of them.
512     * @hide
513     */
514    public List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName, int[] ops) {
515        try {
516            return mService.getOpsForPackage(uid, packageName, ops);
517        } catch (RemoteException e) {
518        }
519        return null;
520    }
521
522    /** @hide */
523    public void setMode(int code, int uid, String packageName, int mode) {
524        try {
525            mService.setMode(code, uid, packageName, mode);
526        } catch (RemoteException e) {
527        }
528    }
529
530    /** @hide */
531    public void resetAllModes() {
532        try {
533            mService.resetAllModes();
534        } catch (RemoteException e) {
535        }
536    }
537
538    /**
539     * Monitor for changes to the operating mode for the given op in the given app package.
540     * @param op The operation to monitor, one of OP_*.
541     * @param packageName The name of the application to monitor.
542     * @param callback Where to report changes.
543     */
544    public void startWatchingMode(int op, String packageName, final Callback callback) {
545        synchronized (mModeWatchers) {
546            IAppOpsCallback cb = mModeWatchers.get(callback);
547            if (cb == null) {
548                cb = new IAppOpsCallback.Stub() {
549                    public void opChanged(int op, String packageName) {
550                        callback.opChanged(op, packageName);
551                    }
552                };
553                mModeWatchers.put(callback, cb);
554            }
555            try {
556                mService.startWatchingMode(op, packageName, cb);
557            } catch (RemoteException e) {
558            }
559        }
560    }
561
562    /**
563     * Stop monitoring that was previously started with {@link #startWatchingMode}.  All
564     * monitoring associated with this callback will be removed.
565     */
566    public void stopWatchingMode(Callback callback) {
567        synchronized (mModeWatchers) {
568            IAppOpsCallback cb = mModeWatchers.get(callback);
569            if (cb != null) {
570                try {
571                    mService.stopWatchingMode(cb);
572                } catch (RemoteException e) {
573                }
574            }
575        }
576    }
577
578    /**
579     * Do a quick check for whether an application might be able to perform an operation.
580     * This is <em>not</em> a security check; you must use {@link #noteOp(int, int, String)}
581     * or {@link #startOp(int, int, String)} for your actual security checks, which also
582     * ensure that the given uid and package name are consistent.  This function can just be
583     * used for a quick check to see if an operation has been disabled for the application,
584     * as an early reject of some work.  This does not modify the time stamp or other data
585     * about the operation.
586     * @param op The operation to check.  One of the OP_* constants.
587     * @param uid The user id of the application attempting to perform the operation.
588     * @param packageName The name of the application attempting to perform the operation.
589     * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or
590     * {@link #MODE_IGNORED} if it is not allowed and should be silently ignored (without
591     * causing the app to crash).
592     * @throws SecurityException If the app has been configured to crash on this op.
593     */
594    public int checkOp(int op, int uid, String packageName) {
595        try {
596            int mode = mService.checkOperation(op, uid, packageName);
597            if (mode == MODE_ERRORED) {
598                throw new SecurityException("Operation not allowed");
599            }
600            return mode;
601        } catch (RemoteException e) {
602        }
603        return MODE_IGNORED;
604    }
605
606    /**
607     * Like {@link #checkOp} but instead of throwing a {@link SecurityException} it
608     * returns {@link #MODE_ERRORED}.
609     */
610    public int checkOpNoThrow(int op, int uid, String packageName) {
611        try {
612            return mService.checkOperation(op, uid, packageName);
613        } catch (RemoteException e) {
614        }
615        return MODE_IGNORED;
616    }
617
618    /**
619     * Make note of an application performing an operation.  Note that you must pass
620     * in both the uid and name of the application to be checked; this function will verify
621     * that these two match, and if not, return {@link #MODE_IGNORED}.  If this call
622     * succeeds, the last execution time of the operation for this app will be updated to
623     * the current time.
624     * @param op The operation to note.  One of the OP_* constants.
625     * @param uid The user id of the application attempting to perform the operation.
626     * @param packageName The name of the application attempting to perform the operation.
627     * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or
628     * {@link #MODE_IGNORED} if it is not allowed and should be silently ignored (without
629     * causing the app to crash).
630     * @throws SecurityException If the app has been configured to crash on this op.
631     */
632    public int noteOp(int op, int uid, String packageName) {
633        try {
634            int mode = mService.noteOperation(op, uid, packageName);
635            if (mode == MODE_ERRORED) {
636                throw new SecurityException("Operation not allowed");
637            }
638            return mode;
639        } catch (RemoteException e) {
640        }
641        return MODE_IGNORED;
642    }
643
644    /**
645     * Like {@link #noteOp} but instead of throwing a {@link SecurityException} it
646     * returns {@link #MODE_ERRORED}.
647     */
648    public int noteOpNoThrow(int op, int uid, String packageName) {
649        try {
650            return mService.noteOperation(op, uid, packageName);
651        } catch (RemoteException e) {
652        }
653        return MODE_IGNORED;
654    }
655
656    /** @hide */
657    public int noteOp(int op) {
658        return noteOp(op, Process.myUid(), mContext.getBasePackageName());
659    }
660
661    /** @hide */
662    public static IBinder getToken(IAppOpsService service) {
663        synchronized (AppOpsManager.class) {
664            if (sToken != null) {
665                return sToken;
666            }
667            try {
668                sToken = service.getToken(new Binder());
669            } catch (RemoteException e) {
670                // System is dead, whatevs.
671            }
672            return sToken;
673        }
674    }
675
676    /**
677     * Report that an application has started executing a long-running operation.  Note that you
678     * must pass in both the uid and name of the application to be checked; this function will
679     * verify that these two match, and if not, return {@link #MODE_IGNORED}.  If this call
680     * succeeds, the last execution time of the operation for this app will be updated to
681     * the current time and the operation will be marked as "running".  In this case you must
682     * later call {@link #finishOp(int, int, String)} to report when the application is no
683     * longer performing the operation.
684     * @param op The operation to start.  One of the OP_* constants.
685     * @param uid The user id of the application attempting to perform the operation.
686     * @param packageName The name of the application attempting to perform the operation.
687     * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or
688     * {@link #MODE_IGNORED} if it is not allowed and should be silently ignored (without
689     * causing the app to crash).
690     * @throws SecurityException If the app has been configured to crash on this op.
691     */
692    public int startOp(int op, int uid, String packageName) {
693        try {
694            int mode = mService.startOperation(getToken(mService), op, uid, packageName);
695            if (mode == MODE_ERRORED) {
696                throw new SecurityException("Operation not allowed");
697            }
698            return mode;
699        } catch (RemoteException e) {
700        }
701        return MODE_IGNORED;
702    }
703
704    /**
705     * Like {@link #startOp} but instead of throwing a {@link SecurityException} it
706     * returns {@link #MODE_ERRORED}.
707     */
708    public int startOpNoThrow(int op, int uid, String packageName) {
709        try {
710            return mService.startOperation(getToken(mService), op, uid, packageName);
711        } catch (RemoteException e) {
712        }
713        return MODE_IGNORED;
714    }
715
716    /** @hide */
717    public int startOp(int op) {
718        return startOp(op, Process.myUid(), mContext.getBasePackageName());
719    }
720
721    /**
722     * Report that an application is no longer performing an operation that had previously
723     * been started with {@link #startOp(int, int, String)}.  There is no validation of input
724     * or result; the parameters supplied here must be the exact same ones previously passed
725     * in when starting the operation.
726     */
727    public void finishOp(int op, int uid, String packageName) {
728        try {
729            mService.finishOperation(getToken(mService), op, uid, packageName);
730        } catch (RemoteException e) {
731        }
732    }
733
734    public void finishOp(int op) {
735        finishOp(op, Process.myUid(), mContext.getBasePackageName());
736    }
737}
738