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