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