AppOpsService.java revision 133b9df951c633a1f72b7e12f8aa9ee9d7da9db6
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 com.android.server; 18 19import java.io.File; 20import java.io.FileDescriptor; 21import java.io.FileInputStream; 22import java.io.FileNotFoundException; 23import java.io.FileOutputStream; 24import java.io.IOException; 25import java.io.PrintWriter; 26import java.util.ArrayList; 27import java.util.HashMap; 28import java.util.Iterator; 29import java.util.List; 30import java.util.Map; 31 32import android.app.AppOpsManager; 33import android.content.Context; 34import android.content.pm.PackageManager; 35import android.content.pm.PackageManager.NameNotFoundException; 36import android.media.AudioService; 37import android.os.AsyncTask; 38import android.os.Binder; 39import android.os.Bundle; 40import android.os.Handler; 41import android.os.IBinder; 42import android.os.Process; 43import android.os.RemoteException; 44import android.os.ServiceManager; 45import android.os.UserHandle; 46import android.os.UserManager; 47import android.util.ArrayMap; 48import android.util.ArraySet; 49import android.util.AtomicFile; 50import android.util.Log; 51import android.util.Pair; 52import android.util.Slog; 53import android.util.SparseArray; 54import android.util.SparseIntArray; 55import android.util.TimeUtils; 56import android.util.Xml; 57 58import com.android.internal.app.IAppOpsService; 59import com.android.internal.app.IAppOpsCallback; 60import com.android.internal.util.FastXmlSerializer; 61import com.android.internal.util.XmlUtils; 62import com.google.android.util.AbstractMessageParser.MusicTrack; 63 64import org.xmlpull.v1.XmlPullParser; 65import org.xmlpull.v1.XmlPullParserException; 66import org.xmlpull.v1.XmlSerializer; 67 68public class AppOpsService extends IAppOpsService.Stub { 69 static final String TAG = "AppOps"; 70 static final boolean DEBUG = false; 71 72 // Write at most every 30 minutes. 73 static final long WRITE_DELAY = DEBUG ? 1000 : 30*60*1000; 74 75 Context mContext; 76 final AtomicFile mFile; 77 final Handler mHandler; 78 79 boolean mWriteScheduled; 80 final Runnable mWriteRunner = new Runnable() { 81 public void run() { 82 synchronized (AppOpsService.this) { 83 mWriteScheduled = false; 84 AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() { 85 @Override protected Void doInBackground(Void... params) { 86 writeState(); 87 return null; 88 } 89 }; 90 task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[])null); 91 } 92 } 93 }; 94 95 final SparseArray<HashMap<String, Ops>> mUidOps 96 = new SparseArray<HashMap<String, Ops>>(); 97 98 private int mDeviceOwnerUid; 99 private final SparseIntArray mProfileOwnerUids = new SparseIntArray(); 100 private final SparseArray<boolean[]> mOpRestrictions = new SparseArray<boolean[]>(); 101 102 public final static class Ops extends SparseArray<Op> { 103 public final String packageName; 104 public final int uid; 105 106 public Ops(String _packageName, int _uid) { 107 packageName = _packageName; 108 uid = _uid; 109 } 110 } 111 112 public final static class Op { 113 public final int uid; 114 public final String packageName; 115 public final int op; 116 public int mode; 117 public int duration; 118 public long time; 119 public long rejectTime; 120 public int nesting; 121 122 public Op(int _uid, String _packageName, int _op) { 123 uid = _uid; 124 packageName = _packageName; 125 op = _op; 126 mode = AppOpsManager.opToDefaultMode(op); 127 } 128 } 129 130 final SparseArray<ArrayList<Callback>> mOpModeWatchers 131 = new SparseArray<ArrayList<Callback>>(); 132 final ArrayMap<String, ArrayList<Callback>> mPackageModeWatchers 133 = new ArrayMap<String, ArrayList<Callback>>(); 134 final ArrayMap<IBinder, Callback> mModeWatchers 135 = new ArrayMap<IBinder, Callback>(); 136 final SparseArray<SparseArray<Restriction>> mAudioRestrictions 137 = new SparseArray<SparseArray<Restriction>>(); 138 139 public final class Callback implements DeathRecipient { 140 final IAppOpsCallback mCallback; 141 142 public Callback(IAppOpsCallback callback) { 143 mCallback = callback; 144 try { 145 mCallback.asBinder().linkToDeath(this, 0); 146 } catch (RemoteException e) { 147 } 148 } 149 150 public void unlinkToDeath() { 151 mCallback.asBinder().unlinkToDeath(this, 0); 152 } 153 154 @Override 155 public void binderDied() { 156 stopWatchingMode(mCallback); 157 } 158 } 159 160 final ArrayMap<IBinder, ClientState> mClients = new ArrayMap<IBinder, ClientState>(); 161 162 public final class ClientState extends Binder implements DeathRecipient { 163 final IBinder mAppToken; 164 final int mPid; 165 final ArrayList<Op> mStartedOps; 166 167 public ClientState(IBinder appToken) { 168 mAppToken = appToken; 169 mPid = Binder.getCallingPid(); 170 if (appToken instanceof Binder) { 171 // For local clients, there is no reason to track them. 172 mStartedOps = null; 173 } else { 174 mStartedOps = new ArrayList<Op>(); 175 try { 176 mAppToken.linkToDeath(this, 0); 177 } catch (RemoteException e) { 178 } 179 } 180 } 181 182 @Override 183 public String toString() { 184 return "ClientState{" + 185 "mAppToken=" + mAppToken + 186 ", " + (mStartedOps != null ? ("pid=" + mPid) : "local") + 187 '}'; 188 } 189 190 @Override 191 public void binderDied() { 192 synchronized (AppOpsService.this) { 193 for (int i=mStartedOps.size()-1; i>=0; i--) { 194 finishOperationLocked(mStartedOps.get(i)); 195 } 196 mClients.remove(mAppToken); 197 } 198 } 199 } 200 201 public AppOpsService(File storagePath, Handler handler) { 202 mFile = new AtomicFile(storagePath); 203 mHandler = handler; 204 readState(); 205 } 206 207 public void publish(Context context) { 208 mContext = context; 209 ServiceManager.addService(Context.APP_OPS_SERVICE, asBinder()); 210 } 211 212 public void systemReady() { 213 synchronized (this) { 214 boolean changed = false; 215 for (int i=0; i<mUidOps.size(); i++) { 216 HashMap<String, Ops> pkgs = mUidOps.valueAt(i); 217 Iterator<Ops> it = pkgs.values().iterator(); 218 while (it.hasNext()) { 219 Ops ops = it.next(); 220 int curUid; 221 try { 222 curUid = mContext.getPackageManager().getPackageUid(ops.packageName, 223 UserHandle.getUserId(ops.uid)); 224 } catch (NameNotFoundException e) { 225 curUid = -1; 226 } 227 if (curUid != ops.uid) { 228 Slog.i(TAG, "Pruning old package " + ops.packageName 229 + "/" + ops.uid + ": new uid=" + curUid); 230 it.remove(); 231 changed = true; 232 } 233 } 234 if (pkgs.size() <= 0) { 235 mUidOps.removeAt(i); 236 } 237 } 238 if (changed) { 239 scheduleWriteLocked(); 240 } 241 } 242 } 243 244 public void packageRemoved(int uid, String packageName) { 245 synchronized (this) { 246 HashMap<String, Ops> pkgs = mUidOps.get(uid); 247 if (pkgs != null) { 248 if (pkgs.remove(packageName) != null) { 249 if (pkgs.size() <= 0) { 250 mUidOps.remove(uid); 251 } 252 scheduleWriteLocked(); 253 } 254 } 255 } 256 } 257 258 public void uidRemoved(int uid) { 259 synchronized (this) { 260 if (mUidOps.indexOfKey(uid) >= 0) { 261 mUidOps.remove(uid); 262 scheduleWriteLocked(); 263 } 264 } 265 } 266 267 public void shutdown() { 268 Slog.w(TAG, "Writing app ops before shutdown..."); 269 boolean doWrite = false; 270 synchronized (this) { 271 if (mWriteScheduled) { 272 mWriteScheduled = false; 273 doWrite = true; 274 } 275 } 276 if (doWrite) { 277 writeState(); 278 } 279 } 280 281 private ArrayList<AppOpsManager.OpEntry> collectOps(Ops pkgOps, int[] ops) { 282 ArrayList<AppOpsManager.OpEntry> resOps = null; 283 if (ops == null) { 284 resOps = new ArrayList<AppOpsManager.OpEntry>(); 285 for (int j=0; j<pkgOps.size(); j++) { 286 Op curOp = pkgOps.valueAt(j); 287 resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time, 288 curOp.rejectTime, curOp.duration)); 289 } 290 } else { 291 for (int j=0; j<ops.length; j++) { 292 Op curOp = pkgOps.get(ops[j]); 293 if (curOp != null) { 294 if (resOps == null) { 295 resOps = new ArrayList<AppOpsManager.OpEntry>(); 296 } 297 resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time, 298 curOp.rejectTime, curOp.duration)); 299 } 300 } 301 } 302 return resOps; 303 } 304 305 @Override 306 public List<AppOpsManager.PackageOps> getPackagesForOps(int[] ops) { 307 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS, 308 Binder.getCallingPid(), Binder.getCallingUid(), null); 309 ArrayList<AppOpsManager.PackageOps> res = null; 310 synchronized (this) { 311 for (int i=0; i<mUidOps.size(); i++) { 312 HashMap<String, Ops> packages = mUidOps.valueAt(i); 313 for (Ops pkgOps : packages.values()) { 314 ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops); 315 if (resOps != null) { 316 if (res == null) { 317 res = new ArrayList<AppOpsManager.PackageOps>(); 318 } 319 AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps( 320 pkgOps.packageName, pkgOps.uid, resOps); 321 res.add(resPackage); 322 } 323 } 324 } 325 } 326 return res; 327 } 328 329 @Override 330 public List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName, 331 int[] ops) { 332 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS, 333 Binder.getCallingPid(), Binder.getCallingUid(), null); 334 synchronized (this) { 335 Ops pkgOps = getOpsLocked(uid, packageName, false); 336 if (pkgOps == null) { 337 return null; 338 } 339 ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops); 340 if (resOps == null) { 341 return null; 342 } 343 ArrayList<AppOpsManager.PackageOps> res = new ArrayList<AppOpsManager.PackageOps>(); 344 AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps( 345 pkgOps.packageName, pkgOps.uid, resOps); 346 res.add(resPackage); 347 return res; 348 } 349 } 350 351 private void pruneOp(Op op, int uid, String packageName) { 352 if (op.time == 0 && op.rejectTime == 0) { 353 Ops ops = getOpsLocked(uid, packageName, false); 354 if (ops != null) { 355 ops.remove(op.op); 356 if (ops.size() <= 0) { 357 HashMap<String, Ops> pkgOps = mUidOps.get(uid); 358 if (pkgOps != null) { 359 pkgOps.remove(ops.packageName); 360 if (pkgOps.size() <= 0) { 361 mUidOps.remove(uid); 362 } 363 } 364 } 365 } 366 } 367 } 368 369 @Override 370 public void setMode(int code, int uid, String packageName, int mode) { 371 if (Binder.getCallingPid() == Process.myPid()) { 372 return; 373 } 374 mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS, 375 Binder.getCallingPid(), Binder.getCallingUid(), null); 376 verifyIncomingOp(code); 377 ArrayList<Callback> repCbs = null; 378 code = AppOpsManager.opToSwitch(code); 379 synchronized (this) { 380 Op op = getOpLocked(code, uid, packageName, true); 381 if (op != null) { 382 if (op.mode != mode) { 383 op.mode = mode; 384 ArrayList<Callback> cbs = mOpModeWatchers.get(code); 385 if (cbs != null) { 386 if (repCbs == null) { 387 repCbs = new ArrayList<Callback>(); 388 } 389 repCbs.addAll(cbs); 390 } 391 cbs = mPackageModeWatchers.get(packageName); 392 if (cbs != null) { 393 if (repCbs == null) { 394 repCbs = new ArrayList<Callback>(); 395 } 396 repCbs.addAll(cbs); 397 } 398 if (mode == AppOpsManager.opToDefaultMode(op.op)) { 399 // If going into the default mode, prune this op 400 // if there is nothing else interesting in it. 401 pruneOp(op, uid, packageName); 402 } 403 scheduleWriteNowLocked(); 404 } 405 } 406 } 407 if (repCbs != null) { 408 for (int i=0; i<repCbs.size(); i++) { 409 try { 410 repCbs.get(i).mCallback.opChanged(code, packageName); 411 } catch (RemoteException e) { 412 } 413 } 414 } 415 } 416 417 private static HashMap<Callback, ArrayList<Pair<String, Integer>>> addCallbacks( 418 HashMap<Callback, ArrayList<Pair<String, Integer>>> callbacks, 419 String packageName, int op, ArrayList<Callback> cbs) { 420 if (cbs == null) { 421 return callbacks; 422 } 423 if (callbacks == null) { 424 callbacks = new HashMap<Callback, ArrayList<Pair<String, Integer>>>(); 425 } 426 for (int i=0; i<cbs.size(); i++) { 427 Callback cb = cbs.get(i); 428 ArrayList<Pair<String, Integer>> reports = callbacks.get(cb); 429 if (reports == null) { 430 reports = new ArrayList<Pair<String, Integer>>(); 431 callbacks.put(cb, reports); 432 } 433 reports.add(new Pair<String, Integer>(packageName, op)); 434 } 435 return callbacks; 436 } 437 438 @Override 439 public void resetAllModes() { 440 mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS, 441 Binder.getCallingPid(), Binder.getCallingUid(), null); 442 HashMap<Callback, ArrayList<Pair<String, Integer>>> callbacks = null; 443 synchronized (this) { 444 boolean changed = false; 445 for (int i=mUidOps.size()-1; i>=0; i--) { 446 HashMap<String, Ops> packages = mUidOps.valueAt(i); 447 Iterator<Map.Entry<String, Ops>> it = packages.entrySet().iterator(); 448 while (it.hasNext()) { 449 Map.Entry<String, Ops> ent = it.next(); 450 String packageName = ent.getKey(); 451 Ops pkgOps = ent.getValue(); 452 for (int j=pkgOps.size()-1; j>=0; j--) { 453 Op curOp = pkgOps.valueAt(j); 454 if (AppOpsManager.opAllowsReset(curOp.op) 455 && curOp.mode != AppOpsManager.opToDefaultMode(curOp.op)) { 456 curOp.mode = AppOpsManager.opToDefaultMode(curOp.op); 457 changed = true; 458 callbacks = addCallbacks(callbacks, packageName, curOp.op, 459 mOpModeWatchers.get(curOp.op)); 460 callbacks = addCallbacks(callbacks, packageName, curOp.op, 461 mPackageModeWatchers.get(packageName)); 462 if (curOp.time == 0 && curOp.rejectTime == 0) { 463 pkgOps.removeAt(j); 464 } 465 } 466 } 467 if (pkgOps.size() == 0) { 468 it.remove(); 469 } 470 } 471 if (packages.size() == 0) { 472 mUidOps.removeAt(i); 473 } 474 } 475 if (changed) { 476 scheduleWriteNowLocked(); 477 } 478 } 479 if (callbacks != null) { 480 for (Map.Entry<Callback, ArrayList<Pair<String, Integer>>> ent : callbacks.entrySet()) { 481 Callback cb = ent.getKey(); 482 ArrayList<Pair<String, Integer>> reports = ent.getValue(); 483 for (int i=0; i<reports.size(); i++) { 484 Pair<String, Integer> rep = reports.get(i); 485 try { 486 cb.mCallback.opChanged(rep.second, rep.first); 487 } catch (RemoteException e) { 488 } 489 } 490 } 491 } 492 } 493 494 @Override 495 public void startWatchingMode(int op, String packageName, IAppOpsCallback callback) { 496 synchronized (this) { 497 op = AppOpsManager.opToSwitch(op); 498 Callback cb = mModeWatchers.get(callback.asBinder()); 499 if (cb == null) { 500 cb = new Callback(callback); 501 mModeWatchers.put(callback.asBinder(), cb); 502 } 503 if (op != AppOpsManager.OP_NONE) { 504 ArrayList<Callback> cbs = mOpModeWatchers.get(op); 505 if (cbs == null) { 506 cbs = new ArrayList<Callback>(); 507 mOpModeWatchers.put(op, cbs); 508 } 509 cbs.add(cb); 510 } 511 if (packageName != null) { 512 ArrayList<Callback> cbs = mPackageModeWatchers.get(packageName); 513 if (cbs == null) { 514 cbs = new ArrayList<Callback>(); 515 mPackageModeWatchers.put(packageName, cbs); 516 } 517 cbs.add(cb); 518 } 519 } 520 } 521 522 @Override 523 public void stopWatchingMode(IAppOpsCallback callback) { 524 synchronized (this) { 525 Callback cb = mModeWatchers.remove(callback.asBinder()); 526 if (cb != null) { 527 cb.unlinkToDeath(); 528 for (int i=mOpModeWatchers.size()-1; i>=0; i--) { 529 ArrayList<Callback> cbs = mOpModeWatchers.valueAt(i); 530 cbs.remove(cb); 531 if (cbs.size() <= 0) { 532 mOpModeWatchers.removeAt(i); 533 } 534 } 535 for (int i=mPackageModeWatchers.size()-1; i>=0; i--) { 536 ArrayList<Callback> cbs = mPackageModeWatchers.valueAt(i); 537 cbs.remove(cb); 538 if (cbs.size() <= 0) { 539 mPackageModeWatchers.removeAt(i); 540 } 541 } 542 } 543 } 544 } 545 546 @Override 547 public IBinder getToken(IBinder clientToken) { 548 synchronized (this) { 549 ClientState cs = mClients.get(clientToken); 550 if (cs == null) { 551 cs = new ClientState(clientToken); 552 mClients.put(clientToken, cs); 553 } 554 return cs; 555 } 556 } 557 558 @Override 559 public int checkOperation(int code, int uid, String packageName) { 560 verifyIncomingUid(uid); 561 verifyIncomingOp(code); 562 synchronized (this) { 563 if (isOpRestricted(uid, code)) { 564 return AppOpsManager.MODE_IGNORED; 565 } 566 Op op = getOpLocked(AppOpsManager.opToSwitch(code), uid, packageName, false); 567 if (op == null) { 568 return AppOpsManager.opToDefaultMode(code); 569 } 570 return op.mode; 571 } 572 } 573 574 @Override 575 public int checkAudioOperation(int code, int stream, int uid, String packageName) { 576 synchronized (this) { 577 final int mode = checkRestrictionLocked(code, stream, uid, packageName); 578 if (mode != AppOpsManager.MODE_ALLOWED) { 579 return mode; 580 } 581 } 582 return checkOperation(code, uid, packageName); 583 } 584 585 private int checkRestrictionLocked(int code, int stream, int uid, String packageName) { 586 final SparseArray<Restriction> streamRestrictions = mAudioRestrictions.get(code); 587 if (streamRestrictions != null) { 588 final Restriction r = streamRestrictions.get(stream); 589 if (r != null && !r.exceptionPackages.contains(packageName)) { 590 return r.mode; 591 } 592 } 593 return AppOpsManager.MODE_ALLOWED; 594 } 595 596 @Override 597 public void setAudioRestriction(int code, int stream, int uid, int mode, 598 String[] exceptionPackages) { 599 verifyIncomingUid(uid); 600 verifyIncomingOp(code); 601 synchronized (this) { 602 SparseArray<Restriction> streamRestrictions = mAudioRestrictions.get(code); 603 if (streamRestrictions == null) { 604 streamRestrictions = new SparseArray<Restriction>(); 605 mAudioRestrictions.put(code, streamRestrictions); 606 } 607 streamRestrictions.remove(stream); 608 if (mode != AppOpsManager.MODE_ALLOWED) { 609 final Restriction r = new Restriction(); 610 r.mode = mode; 611 if (exceptionPackages != null) { 612 final int N = exceptionPackages.length; 613 r.exceptionPackages = new ArraySet<String>(N); 614 for (int i = 0; i < N; i++) { 615 final String pkg = exceptionPackages[i]; 616 if (pkg != null) { 617 r.exceptionPackages.add(pkg.trim()); 618 } 619 } 620 } 621 streamRestrictions.put(stream, r); 622 } 623 } 624 } 625 626 @Override 627 public int checkPackage(int uid, String packageName) { 628 synchronized (this) { 629 if (getOpsLocked(uid, packageName, true) != null) { 630 return AppOpsManager.MODE_ALLOWED; 631 } else { 632 return AppOpsManager.MODE_ERRORED; 633 } 634 } 635 } 636 637 @Override 638 public int noteOperation(int code, int uid, String packageName) { 639 verifyIncomingUid(uid); 640 verifyIncomingOp(code); 641 synchronized (this) { 642 Ops ops = getOpsLocked(uid, packageName, true); 643 if (ops == null) { 644 if (DEBUG) Log.d(TAG, "noteOperation: no op for code " + code + " uid " + uid 645 + " package " + packageName); 646 return AppOpsManager.MODE_ERRORED; 647 } 648 Op op = getOpLocked(ops, code, true); 649 if (isOpRestricted(uid, code)) { 650 return AppOpsManager.MODE_IGNORED; 651 } 652 if (op.duration == -1) { 653 Slog.w(TAG, "Noting op not finished: uid " + uid + " pkg " + packageName 654 + " code " + code + " time=" + op.time + " duration=" + op.duration); 655 } 656 op.duration = 0; 657 final int switchCode = AppOpsManager.opToSwitch(code); 658 final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op; 659 if (switchOp.mode != AppOpsManager.MODE_ALLOWED) { 660 if (DEBUG) Log.d(TAG, "noteOperation: reject #" + op.mode + " for code " 661 + switchCode + " (" + code + ") uid " + uid + " package " + packageName); 662 op.rejectTime = System.currentTimeMillis(); 663 return switchOp.mode; 664 } 665 if (DEBUG) Log.d(TAG, "noteOperation: allowing code " + code + " uid " + uid 666 + " package " + packageName); 667 op.time = System.currentTimeMillis(); 668 op.rejectTime = 0; 669 return AppOpsManager.MODE_ALLOWED; 670 } 671 } 672 673 @Override 674 public int startOperation(IBinder token, int code, int uid, String packageName) { 675 verifyIncomingUid(uid); 676 verifyIncomingOp(code); 677 ClientState client = (ClientState)token; 678 synchronized (this) { 679 Ops ops = getOpsLocked(uid, packageName, true); 680 if (ops == null) { 681 if (DEBUG) Log.d(TAG, "startOperation: no op for code " + code + " uid " + uid 682 + " package " + packageName); 683 return AppOpsManager.MODE_ERRORED; 684 } 685 Op op = getOpLocked(ops, code, true); 686 if (isOpRestricted(uid, code)) { 687 return AppOpsManager.MODE_IGNORED; 688 } 689 final int switchCode = AppOpsManager.opToSwitch(code); 690 final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op; 691 if (switchOp.mode != AppOpsManager.MODE_ALLOWED) { 692 if (DEBUG) Log.d(TAG, "startOperation: reject #" + op.mode + " for code " 693 + switchCode + " (" + code + ") uid " + uid + " package " + packageName); 694 op.rejectTime = System.currentTimeMillis(); 695 return switchOp.mode; 696 } 697 if (DEBUG) Log.d(TAG, "startOperation: allowing code " + code + " uid " + uid 698 + " package " + packageName); 699 if (op.nesting == 0) { 700 op.time = System.currentTimeMillis(); 701 op.rejectTime = 0; 702 op.duration = -1; 703 } 704 op.nesting++; 705 if (client.mStartedOps != null) { 706 client.mStartedOps.add(op); 707 } 708 return AppOpsManager.MODE_ALLOWED; 709 } 710 } 711 712 @Override 713 public void finishOperation(IBinder token, int code, int uid, String packageName) { 714 verifyIncomingUid(uid); 715 verifyIncomingOp(code); 716 ClientState client = (ClientState)token; 717 synchronized (this) { 718 Op op = getOpLocked(code, uid, packageName, true); 719 if (op == null) { 720 return; 721 } 722 if (client.mStartedOps != null) { 723 if (!client.mStartedOps.remove(op)) { 724 throw new IllegalStateException("Operation not started: uid" + op.uid 725 + " pkg=" + op.packageName + " op=" + op.op); 726 } 727 } 728 finishOperationLocked(op); 729 } 730 } 731 732 void finishOperationLocked(Op op) { 733 if (op.nesting <= 1) { 734 if (op.nesting == 1) { 735 op.duration = (int)(System.currentTimeMillis() - op.time); 736 op.time += op.duration; 737 } else { 738 Slog.w(TAG, "Finishing op nesting under-run: uid " + op.uid + " pkg " 739 + op.packageName + " code " + op.op + " time=" + op.time 740 + " duration=" + op.duration + " nesting=" + op.nesting); 741 } 742 op.nesting = 0; 743 } else { 744 op.nesting--; 745 } 746 } 747 748 private void verifyIncomingUid(int uid) { 749 if (uid == Binder.getCallingUid()) { 750 return; 751 } 752 if (Binder.getCallingPid() == Process.myPid()) { 753 return; 754 } 755 mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS, 756 Binder.getCallingPid(), Binder.getCallingUid(), null); 757 } 758 759 private void verifyIncomingOp(int op) { 760 if (op >= 0 && op < AppOpsManager._NUM_OP) { 761 return; 762 } 763 throw new IllegalArgumentException("Bad operation #" + op); 764 } 765 766 private Ops getOpsLocked(int uid, String packageName, boolean edit) { 767 HashMap<String, Ops> pkgOps = mUidOps.get(uid); 768 if (pkgOps == null) { 769 if (!edit) { 770 return null; 771 } 772 pkgOps = new HashMap<String, Ops>(); 773 mUidOps.put(uid, pkgOps); 774 } 775 if (uid == 0) { 776 packageName = "root"; 777 } else if (uid == Process.SHELL_UID) { 778 packageName = "com.android.shell"; 779 } 780 Ops ops = pkgOps.get(packageName); 781 if (ops == null) { 782 if (!edit) { 783 return null; 784 } 785 // This is the first time we have seen this package name under this uid, 786 // so let's make sure it is valid. 787 if (uid != 0) { 788 final long ident = Binder.clearCallingIdentity(); 789 try { 790 int pkgUid = -1; 791 try { 792 pkgUid = mContext.getPackageManager().getPackageUid(packageName, 793 UserHandle.getUserId(uid)); 794 } catch (NameNotFoundException e) { 795 if ("media".equals(packageName)) { 796 pkgUid = Process.MEDIA_UID; 797 } 798 } 799 if (pkgUid != uid) { 800 // Oops! The package name is not valid for the uid they are calling 801 // under. Abort. 802 Slog.w(TAG, "Bad call: specified package " + packageName 803 + " under uid " + uid + " but it is really " + pkgUid); 804 return null; 805 } 806 } finally { 807 Binder.restoreCallingIdentity(ident); 808 } 809 } 810 ops = new Ops(packageName, uid); 811 pkgOps.put(packageName, ops); 812 } 813 return ops; 814 } 815 816 private void scheduleWriteLocked() { 817 if (!mWriteScheduled) { 818 mWriteScheduled = true; 819 mHandler.postDelayed(mWriteRunner, WRITE_DELAY); 820 } 821 } 822 823 private void scheduleWriteNowLocked() { 824 if (!mWriteScheduled) { 825 mWriteScheduled = true; 826 } 827 mHandler.removeCallbacks(mWriteRunner); 828 mHandler.post(mWriteRunner); 829 } 830 831 private Op getOpLocked(int code, int uid, String packageName, boolean edit) { 832 Ops ops = getOpsLocked(uid, packageName, edit); 833 if (ops == null) { 834 return null; 835 } 836 return getOpLocked(ops, code, edit); 837 } 838 839 private Op getOpLocked(Ops ops, int code, boolean edit) { 840 Op op = ops.get(code); 841 if (op == null) { 842 if (!edit) { 843 return null; 844 } 845 op = new Op(ops.uid, ops.packageName, code); 846 ops.put(code, op); 847 } 848 if (edit) { 849 scheduleWriteLocked(); 850 } 851 return op; 852 } 853 854 private boolean isOpRestricted(int uid, int code) { 855 int userHandle = UserHandle.getUserId(uid); 856 boolean[] opRestrictions = mOpRestrictions.get(userHandle); 857 if ((opRestrictions != null) && opRestrictions[code]) { 858 if (userHandle == UserHandle.USER_OWNER) { 859 if (uid != mDeviceOwnerUid) { 860 return true; 861 } 862 } else { 863 if (uid != mProfileOwnerUids.get(userHandle, -1)) { 864 return true; 865 } 866 } 867 } 868 return false; 869 } 870 871 void readState() { 872 synchronized (mFile) { 873 synchronized (this) { 874 FileInputStream stream; 875 try { 876 stream = mFile.openRead(); 877 } catch (FileNotFoundException e) { 878 Slog.i(TAG, "No existing app ops " + mFile.getBaseFile() + "; starting empty"); 879 return; 880 } 881 boolean success = false; 882 try { 883 XmlPullParser parser = Xml.newPullParser(); 884 parser.setInput(stream, null); 885 int type; 886 while ((type = parser.next()) != XmlPullParser.START_TAG 887 && type != XmlPullParser.END_DOCUMENT) { 888 ; 889 } 890 891 if (type != XmlPullParser.START_TAG) { 892 throw new IllegalStateException("no start tag found"); 893 } 894 895 int outerDepth = parser.getDepth(); 896 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 897 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 898 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 899 continue; 900 } 901 902 String tagName = parser.getName(); 903 if (tagName.equals("pkg")) { 904 readPackage(parser); 905 } else { 906 Slog.w(TAG, "Unknown element under <app-ops>: " 907 + parser.getName()); 908 XmlUtils.skipCurrentTag(parser); 909 } 910 } 911 success = true; 912 } catch (IllegalStateException e) { 913 Slog.w(TAG, "Failed parsing " + e); 914 } catch (NullPointerException e) { 915 Slog.w(TAG, "Failed parsing " + e); 916 } catch (NumberFormatException e) { 917 Slog.w(TAG, "Failed parsing " + e); 918 } catch (XmlPullParserException e) { 919 Slog.w(TAG, "Failed parsing " + e); 920 } catch (IOException e) { 921 Slog.w(TAG, "Failed parsing " + e); 922 } catch (IndexOutOfBoundsException e) { 923 Slog.w(TAG, "Failed parsing " + e); 924 } finally { 925 if (!success) { 926 mUidOps.clear(); 927 } 928 try { 929 stream.close(); 930 } catch (IOException e) { 931 } 932 } 933 } 934 } 935 } 936 937 void readPackage(XmlPullParser parser) throws NumberFormatException, 938 XmlPullParserException, IOException { 939 String pkgName = parser.getAttributeValue(null, "n"); 940 int outerDepth = parser.getDepth(); 941 int type; 942 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 943 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 944 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 945 continue; 946 } 947 948 String tagName = parser.getName(); 949 if (tagName.equals("uid")) { 950 readUid(parser, pkgName); 951 } else { 952 Slog.w(TAG, "Unknown element under <pkg>: " 953 + parser.getName()); 954 XmlUtils.skipCurrentTag(parser); 955 } 956 } 957 } 958 959 void readUid(XmlPullParser parser, String pkgName) throws NumberFormatException, 960 XmlPullParserException, IOException { 961 int uid = Integer.parseInt(parser.getAttributeValue(null, "n")); 962 int outerDepth = parser.getDepth(); 963 int type; 964 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 965 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 966 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 967 continue; 968 } 969 970 String tagName = parser.getName(); 971 if (tagName.equals("op")) { 972 Op op = new Op(uid, pkgName, Integer.parseInt(parser.getAttributeValue(null, "n"))); 973 String mode = parser.getAttributeValue(null, "m"); 974 if (mode != null) { 975 op.mode = Integer.parseInt(mode); 976 } 977 String time = parser.getAttributeValue(null, "t"); 978 if (time != null) { 979 op.time = Long.parseLong(time); 980 } 981 time = parser.getAttributeValue(null, "r"); 982 if (time != null) { 983 op.rejectTime = Long.parseLong(time); 984 } 985 String dur = parser.getAttributeValue(null, "d"); 986 if (dur != null) { 987 op.duration = Integer.parseInt(dur); 988 } 989 HashMap<String, Ops> pkgOps = mUidOps.get(uid); 990 if (pkgOps == null) { 991 pkgOps = new HashMap<String, Ops>(); 992 mUidOps.put(uid, pkgOps); 993 } 994 Ops ops = pkgOps.get(pkgName); 995 if (ops == null) { 996 ops = new Ops(pkgName, uid); 997 pkgOps.put(pkgName, ops); 998 } 999 ops.put(op.op, op); 1000 } else { 1001 Slog.w(TAG, "Unknown element under <pkg>: " 1002 + parser.getName()); 1003 XmlUtils.skipCurrentTag(parser); 1004 } 1005 } 1006 } 1007 1008 void writeState() { 1009 synchronized (mFile) { 1010 List<AppOpsManager.PackageOps> allOps = getPackagesForOps(null); 1011 1012 FileOutputStream stream; 1013 try { 1014 stream = mFile.startWrite(); 1015 } catch (IOException e) { 1016 Slog.w(TAG, "Failed to write state: " + e); 1017 return; 1018 } 1019 1020 try { 1021 XmlSerializer out = new FastXmlSerializer(); 1022 out.setOutput(stream, "utf-8"); 1023 out.startDocument(null, true); 1024 out.startTag(null, "app-ops"); 1025 1026 if (allOps != null) { 1027 String lastPkg = null; 1028 for (int i=0; i<allOps.size(); i++) { 1029 AppOpsManager.PackageOps pkg = allOps.get(i); 1030 if (!pkg.getPackageName().equals(lastPkg)) { 1031 if (lastPkg != null) { 1032 out.endTag(null, "pkg"); 1033 } 1034 lastPkg = pkg.getPackageName(); 1035 out.startTag(null, "pkg"); 1036 out.attribute(null, "n", lastPkg); 1037 } 1038 out.startTag(null, "uid"); 1039 out.attribute(null, "n", Integer.toString(pkg.getUid())); 1040 List<AppOpsManager.OpEntry> ops = pkg.getOps(); 1041 for (int j=0; j<ops.size(); j++) { 1042 AppOpsManager.OpEntry op = ops.get(j); 1043 out.startTag(null, "op"); 1044 out.attribute(null, "n", Integer.toString(op.getOp())); 1045 if (op.getMode() != AppOpsManager.opToDefaultMode(op.getOp())) { 1046 out.attribute(null, "m", Integer.toString(op.getMode())); 1047 } 1048 long time = op.getTime(); 1049 if (time != 0) { 1050 out.attribute(null, "t", Long.toString(time)); 1051 } 1052 time = op.getRejectTime(); 1053 if (time != 0) { 1054 out.attribute(null, "r", Long.toString(time)); 1055 } 1056 int dur = op.getDuration(); 1057 if (dur != 0) { 1058 out.attribute(null, "d", Integer.toString(dur)); 1059 } 1060 out.endTag(null, "op"); 1061 } 1062 out.endTag(null, "uid"); 1063 } 1064 if (lastPkg != null) { 1065 out.endTag(null, "pkg"); 1066 } 1067 } 1068 1069 out.endTag(null, "app-ops"); 1070 out.endDocument(); 1071 mFile.finishWrite(stream); 1072 } catch (IOException e) { 1073 Slog.w(TAG, "Failed to write state, restoring backup.", e); 1074 mFile.failWrite(stream); 1075 } 1076 } 1077 } 1078 1079 @Override 1080 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1081 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 1082 != PackageManager.PERMISSION_GRANTED) { 1083 pw.println("Permission Denial: can't dump ApOps service from from pid=" 1084 + Binder.getCallingPid() 1085 + ", uid=" + Binder.getCallingUid()); 1086 return; 1087 } 1088 1089 synchronized (this) { 1090 pw.println("Current AppOps Service state:"); 1091 final long now = System.currentTimeMillis(); 1092 boolean needSep = false; 1093 if (mOpModeWatchers.size() > 0) { 1094 needSep = true; 1095 pw.println(" Op mode watchers:"); 1096 for (int i=0; i<mOpModeWatchers.size(); i++) { 1097 pw.print(" Op "); pw.print(AppOpsManager.opToName(mOpModeWatchers.keyAt(i))); 1098 pw.println(":"); 1099 ArrayList<Callback> callbacks = mOpModeWatchers.valueAt(i); 1100 for (int j=0; j<callbacks.size(); j++) { 1101 pw.print(" #"); pw.print(j); pw.print(": "); 1102 pw.println(callbacks.get(j)); 1103 } 1104 } 1105 } 1106 if (mPackageModeWatchers.size() > 0) { 1107 needSep = true; 1108 pw.println(" Package mode watchers:"); 1109 for (int i=0; i<mPackageModeWatchers.size(); i++) { 1110 pw.print(" Pkg "); pw.print(mPackageModeWatchers.keyAt(i)); 1111 pw.println(":"); 1112 ArrayList<Callback> callbacks = mPackageModeWatchers.valueAt(i); 1113 for (int j=0; j<callbacks.size(); j++) { 1114 pw.print(" #"); pw.print(j); pw.print(": "); 1115 pw.println(callbacks.get(j)); 1116 } 1117 } 1118 } 1119 if (mModeWatchers.size() > 0) { 1120 needSep = true; 1121 pw.println(" All mode watchers:"); 1122 for (int i=0; i<mModeWatchers.size(); i++) { 1123 pw.print(" "); pw.print(mModeWatchers.keyAt(i)); 1124 pw.print(" -> "); pw.println(mModeWatchers.valueAt(i)); 1125 } 1126 } 1127 if (mClients.size() > 0) { 1128 needSep = true; 1129 pw.println(" Clients:"); 1130 for (int i=0; i<mClients.size(); i++) { 1131 pw.print(" "); pw.print(mClients.keyAt(i)); pw.println(":"); 1132 ClientState cs = mClients.valueAt(i); 1133 pw.print(" "); pw.println(cs); 1134 if (cs.mStartedOps != null && cs.mStartedOps.size() > 0) { 1135 pw.println(" Started ops:"); 1136 for (int j=0; j<cs.mStartedOps.size(); j++) { 1137 Op op = cs.mStartedOps.get(j); 1138 pw.print(" "); pw.print("uid="); pw.print(op.uid); 1139 pw.print(" pkg="); pw.print(op.packageName); 1140 pw.print(" op="); pw.println(AppOpsManager.opToName(op.op)); 1141 } 1142 } 1143 } 1144 } 1145 if (mAudioRestrictions.size() > 0) { 1146 boolean printedHeader = false; 1147 for (int o=0; o<mAudioRestrictions.size(); o++) { 1148 final String op = AppOpsManager.opToName(mAudioRestrictions.keyAt(o)); 1149 final SparseArray<Restriction> restrictions = mAudioRestrictions.valueAt(o); 1150 for (int i=0; i<restrictions.size(); i++) { 1151 if (!printedHeader){ 1152 pw.println(" Audio Restrictions:"); 1153 printedHeader = true; 1154 needSep = true; 1155 } 1156 final int stream = restrictions.keyAt(i); 1157 pw.print(" "); pw.print(op); 1158 pw.print(" stream="); pw.print(AudioService.streamToString(stream)); 1159 Restriction r = restrictions.valueAt(i); 1160 pw.print(": mode="); pw.println(r.mode); 1161 if (!r.exceptionPackages.isEmpty()) { 1162 pw.println(" Exceptions:"); 1163 for (int j=0; j<r.exceptionPackages.size(); j++) { 1164 pw.print(" "); pw.println(r.exceptionPackages.valueAt(j)); 1165 } 1166 } 1167 } 1168 } 1169 } 1170 if (needSep) { 1171 pw.println(); 1172 } 1173 for (int i=0; i<mUidOps.size(); i++) { 1174 pw.print(" Uid "); UserHandle.formatUid(pw, mUidOps.keyAt(i)); pw.println(":"); 1175 HashMap<String, Ops> pkgOps = mUidOps.valueAt(i); 1176 for (Ops ops : pkgOps.values()) { 1177 pw.print(" Package "); pw.print(ops.packageName); pw.println(":"); 1178 for (int j=0; j<ops.size(); j++) { 1179 Op op = ops.valueAt(j); 1180 pw.print(" "); pw.print(AppOpsManager.opToName(op.op)); 1181 pw.print(": mode="); pw.print(op.mode); 1182 if (op.time != 0) { 1183 pw.print("; time="); TimeUtils.formatDuration(now-op.time, pw); 1184 pw.print(" ago"); 1185 } 1186 if (op.rejectTime != 0) { 1187 pw.print("; rejectTime="); TimeUtils.formatDuration(now-op.rejectTime, pw); 1188 pw.print(" ago"); 1189 } 1190 if (op.duration == -1) { 1191 pw.println(" (running)"); 1192 } else { 1193 pw.print("; duration="); 1194 TimeUtils.formatDuration(op.duration, pw); 1195 pw.println(); 1196 } 1197 } 1198 } 1199 } 1200 } 1201 } 1202 1203 private static final class Restriction { 1204 private static final ArraySet<String> NO_EXCEPTIONS = new ArraySet<String>(); 1205 int mode; 1206 ArraySet<String> exceptionPackages = NO_EXCEPTIONS; 1207 } 1208 1209 @Override 1210 public void setDeviceOwner(String packageName) throws RemoteException { 1211 checkSystemUid("setDeviceOwner"); 1212 try { 1213 mDeviceOwnerUid = mContext.getPackageManager().getPackageUid(packageName, 1214 UserHandle.USER_OWNER); 1215 } catch (NameNotFoundException e) { 1216 Log.e(TAG, "Could not find Device Owner UID"); 1217 mDeviceOwnerUid = -1; 1218 throw new IllegalArgumentException("Could not find device owner package " 1219 + packageName); 1220 } 1221 } 1222 1223 @Override 1224 public void setProfileOwner(String packageName, int userHandle) throws RemoteException { 1225 checkSystemUid("setProfileOwner"); 1226 try { 1227 int uid = mContext.getPackageManager().getPackageUid(packageName, 1228 userHandle); 1229 mProfileOwnerUids.put(userHandle, uid); 1230 } catch (NameNotFoundException e) { 1231 Log.e(TAG, "Could not find Profile Owner UID"); 1232 mProfileOwnerUids.put(userHandle, -1); 1233 throw new IllegalArgumentException("Could not find profile owner package " 1234 + packageName); 1235 } 1236 } 1237 1238 @Override 1239 public void setUserRestrictions(Bundle restrictions, int userHandle) throws RemoteException { 1240 checkSystemUid("setUserRestrictions"); 1241 boolean[] opRestrictions = mOpRestrictions.get(userHandle); 1242 if (opRestrictions == null) { 1243 opRestrictions = new boolean[AppOpsManager._NUM_OP]; 1244 mOpRestrictions.put(userHandle, opRestrictions); 1245 } 1246 for (int i = 0; i < opRestrictions.length; ++i) { 1247 String restriction = AppOpsManager.opToRestriction(i); 1248 if (restriction != null) { 1249 opRestrictions[i] = restrictions.getBoolean(restriction, false); 1250 } else { 1251 opRestrictions[i] = false; 1252 } 1253 } 1254 } 1255 1256 @Override 1257 public void removeUser(int userHandle) throws RemoteException { 1258 checkSystemUid("removeUser"); 1259 mOpRestrictions.remove(userHandle); 1260 final int index = mProfileOwnerUids.indexOfKey(userHandle); 1261 if (index >= 0) { 1262 mProfileOwnerUids.removeAt(index); 1263 } 1264 } 1265 1266 private void checkSystemUid(String function) { 1267 int uid = Binder.getCallingUid(); 1268 if (uid != Process.SYSTEM_UID) { 1269 throw new SecurityException(function + " must by called by the system"); 1270 } 1271 } 1272 1273} 1274