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