AppOpsService.java revision ed0ea40a41aae8e65bc189efe6b631ca78259383
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.nio.charset.StandardCharsets; 27import java.util.ArrayList; 28import java.util.Collections; 29import java.util.HashMap; 30import java.util.Iterator; 31import java.util.List; 32import java.util.Map; 33 34import android.app.ActivityManager; 35import android.app.ActivityThread; 36import android.app.AppGlobals; 37import android.app.AppOpsManager; 38import android.content.Context; 39import android.content.pm.ApplicationInfo; 40import android.content.pm.IPackageManager; 41import android.content.pm.PackageManager; 42import android.media.AudioAttributes; 43import android.os.AsyncTask; 44import android.os.Binder; 45import android.os.Bundle; 46import android.os.Handler; 47import android.os.IBinder; 48import android.os.Process; 49import android.os.RemoteException; 50import android.os.ResultReceiver; 51import android.os.ServiceManager; 52import android.os.ShellCommand; 53import android.os.UserHandle; 54import android.os.storage.MountServiceInternal; 55import android.util.ArrayMap; 56import android.util.ArraySet; 57import android.util.AtomicFile; 58import android.util.Log; 59import android.util.Slog; 60import android.util.SparseArray; 61import android.util.SparseIntArray; 62import android.util.TimeUtils; 63import android.util.Xml; 64 65import com.android.internal.app.IAppOpsService; 66import com.android.internal.app.IAppOpsCallback; 67import com.android.internal.os.Zygote; 68import com.android.internal.util.ArrayUtils; 69import com.android.internal.util.FastXmlSerializer; 70import com.android.internal.util.XmlUtils; 71 72import libcore.util.EmptyArray; 73import org.xmlpull.v1.XmlPullParser; 74import org.xmlpull.v1.XmlPullParserException; 75import org.xmlpull.v1.XmlSerializer; 76 77public class AppOpsService extends IAppOpsService.Stub { 78 static final String TAG = "AppOps"; 79 static final boolean DEBUG = false; 80 81 // Write at most every 30 minutes. 82 static final long WRITE_DELAY = DEBUG ? 1000 : 30*60*1000; 83 84 Context mContext; 85 final AtomicFile mFile; 86 final Handler mHandler; 87 88 boolean mWriteScheduled; 89 boolean mFastWriteScheduled; 90 final Runnable mWriteRunner = new Runnable() { 91 public void run() { 92 synchronized (AppOpsService.this) { 93 mWriteScheduled = false; 94 mFastWriteScheduled = false; 95 AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() { 96 @Override protected Void doInBackground(Void... params) { 97 writeState(); 98 return null; 99 } 100 }; 101 task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[])null); 102 } 103 } 104 }; 105 106 final SparseArray<UidState> mUidStates = new SparseArray<>(); 107 108 private final SparseArray<boolean[]> mOpRestrictions = new SparseArray<boolean[]>(); 109 110 private static final class UidState { 111 public final int uid; 112 public ArrayMap<String, Ops> pkgOps; 113 public SparseIntArray opModes; 114 115 public UidState(int uid) { 116 this.uid = uid; 117 } 118 119 public void clear() { 120 pkgOps = null; 121 opModes = null; 122 } 123 124 public boolean isDefault() { 125 return (pkgOps == null || pkgOps.isEmpty()) 126 && (opModes == null || opModes.size() <= 0); 127 } 128 } 129 130 public final static class Ops extends SparseArray<Op> { 131 public final String packageName; 132 public final UidState uidState; 133 public final boolean isPrivileged; 134 135 public Ops(String _packageName, UidState _uidState, boolean _isPrivileged) { 136 packageName = _packageName; 137 uidState = _uidState; 138 isPrivileged = _isPrivileged; 139 } 140 } 141 142 public final static class Op { 143 public final int uid; 144 public final String packageName; 145 public int proxyUid = -1; 146 public String proxyPackageName; 147 public final int op; 148 public int mode; 149 public int duration; 150 public long time; 151 public long rejectTime; 152 public int nesting; 153 154 public Op(int _uid, String _packageName, int _op) { 155 uid = _uid; 156 packageName = _packageName; 157 op = _op; 158 mode = AppOpsManager.opToDefaultMode(op); 159 } 160 } 161 162 final SparseArray<ArrayList<Callback>> mOpModeWatchers 163 = new SparseArray<ArrayList<Callback>>(); 164 final ArrayMap<String, ArrayList<Callback>> mPackageModeWatchers 165 = new ArrayMap<String, ArrayList<Callback>>(); 166 final ArrayMap<IBinder, Callback> mModeWatchers 167 = new ArrayMap<IBinder, Callback>(); 168 final SparseArray<SparseArray<Restriction>> mAudioRestrictions 169 = new SparseArray<SparseArray<Restriction>>(); 170 171 public final class Callback implements DeathRecipient { 172 final IAppOpsCallback mCallback; 173 174 public Callback(IAppOpsCallback callback) { 175 mCallback = callback; 176 try { 177 mCallback.asBinder().linkToDeath(this, 0); 178 } catch (RemoteException e) { 179 } 180 } 181 182 public void unlinkToDeath() { 183 mCallback.asBinder().unlinkToDeath(this, 0); 184 } 185 186 @Override 187 public void binderDied() { 188 stopWatchingMode(mCallback); 189 } 190 } 191 192 final ArrayMap<IBinder, ClientState> mClients = new ArrayMap<IBinder, ClientState>(); 193 194 public final class ClientState extends Binder implements DeathRecipient { 195 final IBinder mAppToken; 196 final int mPid; 197 final ArrayList<Op> mStartedOps; 198 199 public ClientState(IBinder appToken) { 200 mAppToken = appToken; 201 mPid = Binder.getCallingPid(); 202 if (appToken instanceof Binder) { 203 // For local clients, there is no reason to track them. 204 mStartedOps = null; 205 } else { 206 mStartedOps = new ArrayList<Op>(); 207 try { 208 mAppToken.linkToDeath(this, 0); 209 } catch (RemoteException e) { 210 } 211 } 212 } 213 214 @Override 215 public String toString() { 216 return "ClientState{" + 217 "mAppToken=" + mAppToken + 218 ", " + (mStartedOps != null ? ("pid=" + mPid) : "local") + 219 '}'; 220 } 221 222 @Override 223 public void binderDied() { 224 synchronized (AppOpsService.this) { 225 for (int i=mStartedOps.size()-1; i>=0; i--) { 226 finishOperationLocked(mStartedOps.get(i)); 227 } 228 mClients.remove(mAppToken); 229 } 230 } 231 } 232 233 public AppOpsService(File storagePath, Handler handler) { 234 mFile = new AtomicFile(storagePath); 235 mHandler = handler; 236 readState(); 237 } 238 239 public void publish(Context context) { 240 mContext = context; 241 ServiceManager.addService(Context.APP_OPS_SERVICE, asBinder()); 242 } 243 244 public void systemReady() { 245 synchronized (this) { 246 boolean changed = false; 247 for (int i = mUidStates.size() - 1; i >= 0; i--) { 248 UidState uidState = mUidStates.valueAt(i); 249 250 String[] packageNames = getPackagesForUid(uidState.uid); 251 if (ArrayUtils.isEmpty(packageNames)) { 252 uidState.clear(); 253 mUidStates.removeAt(i); 254 changed = true; 255 continue; 256 } 257 258 ArrayMap<String, Ops> pkgs = uidState.pkgOps; 259 if (pkgs == null) { 260 continue; 261 } 262 263 Iterator<Ops> it = pkgs.values().iterator(); 264 while (it.hasNext()) { 265 Ops ops = it.next(); 266 int curUid = -1; 267 try { 268 curUid = AppGlobals.getPackageManager().getPackageUidEtc(ops.packageName, 269 PackageManager.GET_UNINSTALLED_PACKAGES, 270 UserHandle.getUserId(ops.uidState.uid)); 271 } catch (RemoteException ignored) { 272 } 273 if (curUid != ops.uidState.uid) { 274 Slog.i(TAG, "Pruning old package " + ops.packageName 275 + "/" + ops.uidState + ": new uid=" + curUid); 276 it.remove(); 277 changed = true; 278 } 279 } 280 281 if (uidState.isDefault()) { 282 mUidStates.removeAt(i); 283 } 284 } 285 if (changed) { 286 scheduleFastWriteLocked(); 287 } 288 } 289 290 MountServiceInternal mountServiceInternal = LocalServices.getService( 291 MountServiceInternal.class); 292 mountServiceInternal.addExternalStoragePolicy( 293 new MountServiceInternal.ExternalStorageMountPolicy() { 294 @Override 295 public int getMountMode(int uid, String packageName) { 296 if (Process.isIsolated(uid)) { 297 return Zygote.MOUNT_EXTERNAL_NONE; 298 } 299 if (noteOperation(AppOpsManager.OP_READ_EXTERNAL_STORAGE, uid, 300 packageName) != AppOpsManager.MODE_ALLOWED) { 301 return Zygote.MOUNT_EXTERNAL_NONE; 302 } 303 if (noteOperation(AppOpsManager.OP_WRITE_EXTERNAL_STORAGE, uid, 304 packageName) != AppOpsManager.MODE_ALLOWED) { 305 return Zygote.MOUNT_EXTERNAL_READ; 306 } 307 return Zygote.MOUNT_EXTERNAL_WRITE; 308 } 309 310 @Override 311 public boolean hasExternalStorage(int uid, String packageName) { 312 final int mountMode = getMountMode(uid, packageName); 313 return mountMode == Zygote.MOUNT_EXTERNAL_READ 314 || mountMode == Zygote.MOUNT_EXTERNAL_WRITE; 315 } 316 }); 317 } 318 319 public void packageRemoved(int uid, String packageName) { 320 synchronized (this) { 321 UidState uidState = mUidStates.get(uid); 322 if (uidState == null) { 323 return; 324 } 325 326 boolean changed = false; 327 328 // Remove any package state if such. 329 if (uidState.pkgOps != null && uidState.pkgOps.remove(packageName) != null) { 330 changed = true; 331 } 332 333 // If we just nuked the last package state check if the UID is valid. 334 if (changed && uidState.pkgOps.isEmpty() 335 && getPackagesForUid(uid).length <= 0) { 336 mUidStates.remove(uid); 337 } 338 339 if (changed) { 340 scheduleFastWriteLocked(); 341 } 342 } 343 } 344 345 public void uidRemoved(int uid) { 346 synchronized (this) { 347 if (mUidStates.indexOfKey(uid) >= 0) { 348 mUidStates.remove(uid); 349 scheduleFastWriteLocked(); 350 } 351 } 352 } 353 354 public void shutdown() { 355 Slog.w(TAG, "Writing app ops before shutdown..."); 356 boolean doWrite = false; 357 synchronized (this) { 358 if (mWriteScheduled) { 359 mWriteScheduled = false; 360 doWrite = true; 361 } 362 } 363 if (doWrite) { 364 writeState(); 365 } 366 } 367 368 private ArrayList<AppOpsManager.OpEntry> collectOps(Ops pkgOps, int[] ops) { 369 ArrayList<AppOpsManager.OpEntry> resOps = null; 370 if (ops == null) { 371 resOps = new ArrayList<AppOpsManager.OpEntry>(); 372 for (int j=0; j<pkgOps.size(); j++) { 373 Op curOp = pkgOps.valueAt(j); 374 resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time, 375 curOp.rejectTime, curOp.duration, curOp.proxyUid, 376 curOp.proxyPackageName)); 377 } 378 } else { 379 for (int j=0; j<ops.length; j++) { 380 Op curOp = pkgOps.get(ops[j]); 381 if (curOp != null) { 382 if (resOps == null) { 383 resOps = new ArrayList<AppOpsManager.OpEntry>(); 384 } 385 resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time, 386 curOp.rejectTime, curOp.duration, curOp.proxyUid, 387 curOp.proxyPackageName)); 388 } 389 } 390 } 391 return resOps; 392 } 393 394 @Override 395 public List<AppOpsManager.PackageOps> getPackagesForOps(int[] ops) { 396 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS, 397 Binder.getCallingPid(), Binder.getCallingUid(), null); 398 ArrayList<AppOpsManager.PackageOps> res = null; 399 synchronized (this) { 400 final int uidStateCount = mUidStates.size(); 401 for (int i = 0; i < uidStateCount; i++) { 402 UidState uidState = mUidStates.valueAt(i); 403 if (uidState.pkgOps == null || uidState.pkgOps.isEmpty()) { 404 continue; 405 } 406 ArrayMap<String, Ops> packages = uidState.pkgOps; 407 final int packageCount = packages.size(); 408 for (int j = 0; j < packageCount; j++) { 409 Ops pkgOps = packages.valueAt(j); 410 ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops); 411 if (resOps != null) { 412 if (res == null) { 413 res = new ArrayList<AppOpsManager.PackageOps>(); 414 } 415 AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps( 416 pkgOps.packageName, pkgOps.uidState.uid, resOps); 417 res.add(resPackage); 418 } 419 } 420 } 421 } 422 return res; 423 } 424 425 @Override 426 public List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName, 427 int[] ops) { 428 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS, 429 Binder.getCallingPid(), Binder.getCallingUid(), null); 430 synchronized (this) { 431 Ops pkgOps = getOpsLocked(uid, packageName, false); 432 if (pkgOps == null) { 433 return null; 434 } 435 ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops); 436 if (resOps == null) { 437 return null; 438 } 439 ArrayList<AppOpsManager.PackageOps> res = new ArrayList<AppOpsManager.PackageOps>(); 440 AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps( 441 pkgOps.packageName, pkgOps.uidState.uid, resOps); 442 res.add(resPackage); 443 return res; 444 } 445 } 446 447 private void pruneOp(Op op, int uid, String packageName) { 448 if (op.time == 0 && op.rejectTime == 0) { 449 Ops ops = getOpsLocked(uid, packageName, false); 450 if (ops != null) { 451 ops.remove(op.op); 452 if (ops.size() <= 0) { 453 UidState uidState = ops.uidState; 454 ArrayMap<String, Ops> pkgOps = uidState.pkgOps; 455 if (pkgOps != null) { 456 pkgOps.remove(ops.packageName); 457 if (pkgOps.isEmpty()) { 458 uidState.pkgOps = null; 459 } 460 if (uidState.isDefault()) { 461 mUidStates.remove(uid); 462 } 463 } 464 } 465 } 466 } 467 } 468 469 @Override 470 public void setUidMode(int code, int uid, int mode) { 471 if (Binder.getCallingPid() != Process.myPid()) { 472 mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS, 473 Binder.getCallingPid(), Binder.getCallingUid(), null); 474 } 475 verifyIncomingOp(code); 476 code = AppOpsManager.opToSwitch(code); 477 478 synchronized (this) { 479 final int defaultMode = AppOpsManager.opToDefaultMode(code); 480 481 UidState uidState = getUidStateLocked(uid, false); 482 if (uidState == null) { 483 if (mode == defaultMode) { 484 return; 485 } 486 uidState = new UidState(uid); 487 uidState.opModes = new SparseIntArray(); 488 uidState.opModes.put(code, mode); 489 mUidStates.put(uid, uidState); 490 scheduleWriteLocked(); 491 } else if (uidState.opModes == null) { 492 if (mode != defaultMode) { 493 uidState.opModes = new SparseIntArray(); 494 uidState.opModes.put(code, mode); 495 scheduleWriteLocked(); 496 } 497 } else { 498 if (uidState.opModes.get(code) == mode) { 499 return; 500 } 501 if (mode == defaultMode) { 502 uidState.opModes.delete(code); 503 if (uidState.opModes.size() <= 0) { 504 uidState.opModes = null; 505 } 506 } else { 507 uidState.opModes.put(code, mode); 508 } 509 scheduleWriteLocked(); 510 } 511 } 512 513 String[] uidPackageNames = getPackagesForUid(uid); 514 ArrayMap<Callback, ArraySet<String>> callbackSpecs = null; 515 516 synchronized (this) { 517 ArrayList<Callback> callbacks = mOpModeWatchers.get(code); 518 if (callbacks != null) { 519 final int callbackCount = callbacks.size(); 520 for (int i = 0; i < callbackCount; i++) { 521 Callback callback = callbacks.get(i); 522 ArraySet<String> changedPackages = new ArraySet<>(); 523 Collections.addAll(changedPackages, uidPackageNames); 524 callbackSpecs = new ArrayMap<>(); 525 callbackSpecs.put(callback, changedPackages); 526 } 527 } 528 529 for (String uidPackageName : uidPackageNames) { 530 callbacks = mPackageModeWatchers.get(uidPackageName); 531 if (callbacks != null) { 532 if (callbackSpecs == null) { 533 callbackSpecs = new ArrayMap<>(); 534 } 535 final int callbackCount = callbacks.size(); 536 for (int i = 0; i < callbackCount; i++) { 537 Callback callback = callbacks.get(i); 538 ArraySet<String> changedPackages = callbackSpecs.get(callback); 539 if (changedPackages == null) { 540 changedPackages = new ArraySet<>(); 541 callbackSpecs.put(callback, changedPackages); 542 } 543 changedPackages.add(uidPackageName); 544 } 545 } 546 } 547 } 548 549 if (callbackSpecs == null) { 550 return; 551 } 552 553 // There are components watching for mode changes such as window manager 554 // and location manager which are in our process. The callbacks in these 555 // components may require permissions our remote caller does not have. 556 final long identity = Binder.clearCallingIdentity(); 557 try { 558 for (int i = 0; i < callbackSpecs.size(); i++) { 559 Callback callback = callbackSpecs.keyAt(i); 560 ArraySet<String> reportedPackageNames = callbackSpecs.valueAt(i); 561 try { 562 if (reportedPackageNames == null) { 563 callback.mCallback.opChanged(code, uid, null); 564 } else { 565 final int reportedPackageCount = reportedPackageNames.size(); 566 for (int j = 0; j < reportedPackageCount; j++) { 567 String reportedPackageName = reportedPackageNames.valueAt(j); 568 callback.mCallback.opChanged(code, uid, reportedPackageName); 569 } 570 } 571 } catch (RemoteException e) { 572 Log.w(TAG, "Error dispatching op op change", e); 573 } 574 } 575 } finally { 576 Binder.restoreCallingIdentity(identity); 577 } 578 } 579 580 @Override 581 public void setMode(int code, int uid, String packageName, int mode) { 582 if (Binder.getCallingPid() != Process.myPid()) { 583 mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS, 584 Binder.getCallingPid(), Binder.getCallingUid(), null); 585 } 586 verifyIncomingOp(code); 587 ArrayList<Callback> repCbs = null; 588 code = AppOpsManager.opToSwitch(code); 589 synchronized (this) { 590 UidState uidState = getUidStateLocked(uid, false); 591 Op op = getOpLocked(code, uid, packageName, true); 592 if (op != null) { 593 if (op.mode != mode) { 594 op.mode = mode; 595 ArrayList<Callback> cbs = mOpModeWatchers.get(code); 596 if (cbs != null) { 597 if (repCbs == null) { 598 repCbs = new ArrayList<Callback>(); 599 } 600 repCbs.addAll(cbs); 601 } 602 cbs = mPackageModeWatchers.get(packageName); 603 if (cbs != null) { 604 if (repCbs == null) { 605 repCbs = new ArrayList<Callback>(); 606 } 607 repCbs.addAll(cbs); 608 } 609 if (mode == AppOpsManager.opToDefaultMode(op.op)) { 610 // If going into the default mode, prune this op 611 // if there is nothing else interesting in it. 612 pruneOp(op, uid, packageName); 613 } 614 scheduleFastWriteLocked(); 615 } 616 } 617 } 618 if (repCbs != null) { 619 // There are components watching for mode changes such as window manager 620 // and location manager which are in our process. The callbacks in these 621 // components may require permissions our remote caller does not have. 622 final long identity = Binder.clearCallingIdentity(); 623 try { 624 for (int i = 0; i < repCbs.size(); i++) { 625 try { 626 repCbs.get(i).mCallback.opChanged(code, uid, packageName); 627 } catch (RemoteException e) { 628 } 629 } 630 } finally { 631 Binder.restoreCallingIdentity(identity); 632 } 633 } 634 } 635 636 private static HashMap<Callback, ArrayList<ChangeRec>> addCallbacks( 637 HashMap<Callback, ArrayList<ChangeRec>> callbacks, 638 int op, int uid, String packageName, ArrayList<Callback> cbs) { 639 if (cbs == null) { 640 return callbacks; 641 } 642 if (callbacks == null) { 643 callbacks = new HashMap<>(); 644 } 645 boolean duplicate = false; 646 for (int i=0; i<cbs.size(); i++) { 647 Callback cb = cbs.get(i); 648 ArrayList<ChangeRec> reports = callbacks.get(cb); 649 if (reports == null) { 650 reports = new ArrayList<>(); 651 callbacks.put(cb, reports); 652 } else { 653 final int reportCount = reports.size(); 654 for (int j = 0; j < reportCount; j++) { 655 ChangeRec report = reports.get(j); 656 if (report.op == op && report.pkg.equals(packageName)) { 657 duplicate = true; 658 break; 659 } 660 } 661 } 662 if (!duplicate) { 663 reports.add(new ChangeRec(op, uid, packageName)); 664 } 665 } 666 return callbacks; 667 } 668 669 static final class ChangeRec { 670 final int op; 671 final int uid; 672 final String pkg; 673 674 ChangeRec(int _op, int _uid, String _pkg) { 675 op = _op; 676 uid = _uid; 677 pkg = _pkg; 678 } 679 } 680 681 @Override 682 public void resetAllModes(int reqUserId, String reqPackageName) { 683 final int callingPid = Binder.getCallingPid(); 684 final int callingUid = Binder.getCallingUid(); 685 mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS, 686 callingPid, callingUid, null); 687 reqUserId = ActivityManager.handleIncomingUser(callingPid, callingUid, reqUserId, 688 true, true, "resetAllModes", null); 689 690 int reqUid = -1; 691 if (reqPackageName != null) { 692 try { 693 reqUid = AppGlobals.getPackageManager().getPackageUid( 694 reqPackageName, reqUserId); 695 } catch (RemoteException e) { 696 /* ignore - local call */ 697 } 698 } 699 700 HashMap<Callback, ArrayList<ChangeRec>> callbacks = null; 701 synchronized (this) { 702 boolean changed = false; 703 for (int i = mUidStates.size() - 1; i >= 0; i--) { 704 UidState uidState = mUidStates.valueAt(i); 705 706 SparseIntArray opModes = uidState.opModes; 707 if (opModes != null && (uidState.uid == reqUid || reqUid == -1)) { 708 final int uidOpCount = opModes.size(); 709 for (int j = uidOpCount - 1; j >= 0; j--) { 710 final int code = opModes.keyAt(j); 711 if (AppOpsManager.opAllowsReset(code)) { 712 opModes.removeAt(j); 713 if (opModes.size() <= 0) { 714 uidState.opModes = null; 715 } 716 for (String packageName : getPackagesForUid(uidState.uid)) { 717 callbacks = addCallbacks(callbacks, code, uidState.uid, packageName, 718 mOpModeWatchers.get(code)); 719 callbacks = addCallbacks(callbacks, code, uidState.uid, packageName, 720 mPackageModeWatchers.get(packageName)); 721 } 722 } 723 } 724 } 725 726 if (uidState.pkgOps == null) { 727 continue; 728 } 729 730 if (reqUserId != UserHandle.USER_ALL 731 && reqUserId != UserHandle.getUserId(uidState.uid)) { 732 // Skip any ops for a different user 733 continue; 734 } 735 736 Map<String, Ops> packages = uidState.pkgOps; 737 Iterator<Map.Entry<String, Ops>> it = packages.entrySet().iterator(); 738 while (it.hasNext()) { 739 Map.Entry<String, Ops> ent = it.next(); 740 String packageName = ent.getKey(); 741 if (reqPackageName != null && !reqPackageName.equals(packageName)) { 742 // Skip any ops for a different package 743 continue; 744 } 745 Ops pkgOps = ent.getValue(); 746 for (int j=pkgOps.size()-1; j>=0; j--) { 747 Op curOp = pkgOps.valueAt(j); 748 if (AppOpsManager.opAllowsReset(curOp.op) 749 && curOp.mode != AppOpsManager.opToDefaultMode(curOp.op)) { 750 curOp.mode = AppOpsManager.opToDefaultMode(curOp.op); 751 changed = true; 752 callbacks = addCallbacks(callbacks, curOp.op, curOp.uid, packageName, 753 mOpModeWatchers.get(curOp.op)); 754 callbacks = addCallbacks(callbacks, curOp.op, curOp.uid, packageName, 755 mPackageModeWatchers.get(packageName)); 756 if (curOp.time == 0 && curOp.rejectTime == 0) { 757 pkgOps.removeAt(j); 758 } 759 } 760 } 761 if (pkgOps.size() == 0) { 762 it.remove(); 763 } 764 } 765 if (uidState.isDefault()) { 766 mUidStates.remove(uidState.uid); 767 } 768 } 769 770 if (changed) { 771 scheduleFastWriteLocked(); 772 } 773 } 774 if (callbacks != null) { 775 for (Map.Entry<Callback, ArrayList<ChangeRec>> ent : callbacks.entrySet()) { 776 Callback cb = ent.getKey(); 777 ArrayList<ChangeRec> reports = ent.getValue(); 778 for (int i=0; i<reports.size(); i++) { 779 ChangeRec rep = reports.get(i); 780 try { 781 cb.mCallback.opChanged(rep.op, rep.uid, rep.pkg); 782 } catch (RemoteException e) { 783 } 784 } 785 } 786 } 787 } 788 789 @Override 790 public void startWatchingMode(int op, String packageName, IAppOpsCallback callback) { 791 synchronized (this) { 792 op = (op != AppOpsManager.OP_NONE) ? AppOpsManager.opToSwitch(op) : op; 793 Callback cb = mModeWatchers.get(callback.asBinder()); 794 if (cb == null) { 795 cb = new Callback(callback); 796 mModeWatchers.put(callback.asBinder(), cb); 797 } 798 if (op != AppOpsManager.OP_NONE) { 799 ArrayList<Callback> cbs = mOpModeWatchers.get(op); 800 if (cbs == null) { 801 cbs = new ArrayList<Callback>(); 802 mOpModeWatchers.put(op, cbs); 803 } 804 cbs.add(cb); 805 } 806 if (packageName != null) { 807 ArrayList<Callback> cbs = mPackageModeWatchers.get(packageName); 808 if (cbs == null) { 809 cbs = new ArrayList<Callback>(); 810 mPackageModeWatchers.put(packageName, cbs); 811 } 812 cbs.add(cb); 813 } 814 } 815 } 816 817 @Override 818 public void stopWatchingMode(IAppOpsCallback callback) { 819 synchronized (this) { 820 Callback cb = mModeWatchers.remove(callback.asBinder()); 821 if (cb != null) { 822 cb.unlinkToDeath(); 823 for (int i=mOpModeWatchers.size()-1; i>=0; i--) { 824 ArrayList<Callback> cbs = mOpModeWatchers.valueAt(i); 825 cbs.remove(cb); 826 if (cbs.size() <= 0) { 827 mOpModeWatchers.removeAt(i); 828 } 829 } 830 for (int i=mPackageModeWatchers.size()-1; i>=0; i--) { 831 ArrayList<Callback> cbs = mPackageModeWatchers.valueAt(i); 832 cbs.remove(cb); 833 if (cbs.size() <= 0) { 834 mPackageModeWatchers.removeAt(i); 835 } 836 } 837 } 838 } 839 } 840 841 @Override 842 public IBinder getToken(IBinder clientToken) { 843 synchronized (this) { 844 ClientState cs = mClients.get(clientToken); 845 if (cs == null) { 846 cs = new ClientState(clientToken); 847 mClients.put(clientToken, cs); 848 } 849 return cs; 850 } 851 } 852 853 @Override 854 public int checkOperation(int code, int uid, String packageName) { 855 verifyIncomingUid(uid); 856 verifyIncomingOp(code); 857 synchronized (this) { 858 if (isOpRestricted(uid, code, packageName)) { 859 return AppOpsManager.MODE_IGNORED; 860 } 861 code = AppOpsManager.opToSwitch(code); 862 UidState uidState = getUidStateLocked(uid, false); 863 if (uidState != null && uidState.opModes != null) { 864 final int uidMode = uidState.opModes.get(code); 865 if (uidMode != AppOpsManager.MODE_ALLOWED) { 866 return uidMode; 867 } 868 } 869 Op op = getOpLocked(code, uid, packageName, false); 870 if (op == null) { 871 return AppOpsManager.opToDefaultMode(code); 872 } 873 return op.mode; 874 } 875 } 876 877 @Override 878 public int checkAudioOperation(int code, int usage, int uid, String packageName) { 879 synchronized (this) { 880 final int mode = checkRestrictionLocked(code, usage, uid, packageName); 881 if (mode != AppOpsManager.MODE_ALLOWED) { 882 return mode; 883 } 884 } 885 return checkOperation(code, uid, packageName); 886 } 887 888 private int checkRestrictionLocked(int code, int usage, int uid, String packageName) { 889 final SparseArray<Restriction> usageRestrictions = mAudioRestrictions.get(code); 890 if (usageRestrictions != null) { 891 final Restriction r = usageRestrictions.get(usage); 892 if (r != null && !r.exceptionPackages.contains(packageName)) { 893 return r.mode; 894 } 895 } 896 return AppOpsManager.MODE_ALLOWED; 897 } 898 899 @Override 900 public void setAudioRestriction(int code, int usage, int uid, int mode, 901 String[] exceptionPackages) { 902 verifyIncomingUid(uid); 903 verifyIncomingOp(code); 904 synchronized (this) { 905 SparseArray<Restriction> usageRestrictions = mAudioRestrictions.get(code); 906 if (usageRestrictions == null) { 907 usageRestrictions = new SparseArray<Restriction>(); 908 mAudioRestrictions.put(code, usageRestrictions); 909 } 910 usageRestrictions.remove(usage); 911 if (mode != AppOpsManager.MODE_ALLOWED) { 912 final Restriction r = new Restriction(); 913 r.mode = mode; 914 if (exceptionPackages != null) { 915 final int N = exceptionPackages.length; 916 r.exceptionPackages = new ArraySet<String>(N); 917 for (int i = 0; i < N; i++) { 918 final String pkg = exceptionPackages[i]; 919 if (pkg != null) { 920 r.exceptionPackages.add(pkg.trim()); 921 } 922 } 923 } 924 usageRestrictions.put(usage, r); 925 } 926 } 927 } 928 929 @Override 930 public int checkPackage(int uid, String packageName) { 931 synchronized (this) { 932 if (getOpsRawLocked(uid, packageName, true) != null) { 933 return AppOpsManager.MODE_ALLOWED; 934 } else { 935 return AppOpsManager.MODE_ERRORED; 936 } 937 } 938 } 939 940 @Override 941 public int noteProxyOperation(int code, String proxyPackageName, 942 int proxiedUid, String proxiedPackageName) { 943 verifyIncomingOp(code); 944 final int proxyMode = noteOperationUnchecked(code, Binder.getCallingUid(), 945 proxyPackageName, -1, null); 946 if (proxyMode != AppOpsManager.MODE_ALLOWED || Binder.getCallingUid() == proxiedUid) { 947 return proxyMode; 948 } 949 return noteOperationUnchecked(code, proxiedUid, proxiedPackageName, 950 Binder.getCallingUid(), proxyPackageName); 951 } 952 953 @Override 954 public int noteOperation(int code, int uid, String packageName) { 955 verifyIncomingUid(uid); 956 verifyIncomingOp(code); 957 return noteOperationUnchecked(code, uid, packageName, 0, null); 958 } 959 960 private int noteOperationUnchecked(int code, int uid, String packageName, 961 int proxyUid, String proxyPackageName) { 962 synchronized (this) { 963 Ops ops = getOpsLocked(uid, packageName, true); 964 if (ops == null) { 965 if (DEBUG) Log.d(TAG, "noteOperation: no op for code " + code + " uid " + uid 966 + " package " + packageName); 967 return AppOpsManager.MODE_ERRORED; 968 } 969 Op op = getOpLocked(ops, code, true); 970 if (isOpRestricted(uid, code, packageName)) { 971 return AppOpsManager.MODE_IGNORED; 972 } 973 if (op.duration == -1) { 974 Slog.w(TAG, "Noting op not finished: uid " + uid + " pkg " + packageName 975 + " code " + code + " time=" + op.time + " duration=" + op.duration); 976 } 977 op.duration = 0; 978 final int switchCode = AppOpsManager.opToSwitch(code); 979 UidState uidState = ops.uidState; 980 if (uidState.opModes != null) { 981 final int uidMode = uidState.opModes.get(switchCode); 982 if (uidMode != AppOpsManager.MODE_ALLOWED) { 983 if (DEBUG) Log.d(TAG, "noteOperation: reject #" + op.mode + " for code " 984 + switchCode + " (" + code + ") uid " + uid + " package " 985 + packageName); 986 op.rejectTime = System.currentTimeMillis(); 987 return uidMode; 988 } 989 } 990 final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op; 991 if (switchOp.mode != AppOpsManager.MODE_ALLOWED) { 992 if (DEBUG) Log.d(TAG, "noteOperation: reject #" + op.mode + " for code " 993 + switchCode + " (" + code + ") uid " + uid + " package " + packageName); 994 op.rejectTime = System.currentTimeMillis(); 995 return switchOp.mode; 996 } 997 if (DEBUG) Log.d(TAG, "noteOperation: allowing code " + code + " uid " + uid 998 + " package " + packageName); 999 op.time = System.currentTimeMillis(); 1000 op.rejectTime = 0; 1001 op.proxyUid = proxyUid; 1002 op.proxyPackageName = proxyPackageName; 1003 return AppOpsManager.MODE_ALLOWED; 1004 } 1005 } 1006 1007 @Override 1008 public int startOperation(IBinder token, int code, int uid, String packageName) { 1009 verifyIncomingUid(uid); 1010 verifyIncomingOp(code); 1011 ClientState client = (ClientState)token; 1012 synchronized (this) { 1013 Ops ops = getOpsLocked(uid, packageName, true); 1014 if (ops == null) { 1015 if (DEBUG) Log.d(TAG, "startOperation: no op for code " + code + " uid " + uid 1016 + " package " + packageName); 1017 return AppOpsManager.MODE_ERRORED; 1018 } 1019 Op op = getOpLocked(ops, code, true); 1020 if (isOpRestricted(uid, code, packageName)) { 1021 return AppOpsManager.MODE_IGNORED; 1022 } 1023 final int switchCode = AppOpsManager.opToSwitch(code); 1024 UidState uidState = ops.uidState; 1025 if (uidState.opModes != null) { 1026 final int uidMode = uidState.opModes.get(switchCode); 1027 if (uidMode != AppOpsManager.MODE_ALLOWED) { 1028 if (DEBUG) Log.d(TAG, "noteOperation: reject #" + op.mode + " for code " 1029 + switchCode + " (" + code + ") uid " + uid + " package " 1030 + packageName); 1031 op.rejectTime = System.currentTimeMillis(); 1032 return uidMode; 1033 } 1034 } 1035 final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op; 1036 if (switchOp.mode != AppOpsManager.MODE_ALLOWED) { 1037 if (DEBUG) Log.d(TAG, "startOperation: reject #" + op.mode + " for code " 1038 + switchCode + " (" + code + ") uid " + uid + " package " + packageName); 1039 op.rejectTime = System.currentTimeMillis(); 1040 return switchOp.mode; 1041 } 1042 if (DEBUG) Log.d(TAG, "startOperation: allowing code " + code + " uid " + uid 1043 + " package " + packageName); 1044 if (op.nesting == 0) { 1045 op.time = System.currentTimeMillis(); 1046 op.rejectTime = 0; 1047 op.duration = -1; 1048 } 1049 op.nesting++; 1050 if (client.mStartedOps != null) { 1051 client.mStartedOps.add(op); 1052 } 1053 return AppOpsManager.MODE_ALLOWED; 1054 } 1055 } 1056 1057 @Override 1058 public void finishOperation(IBinder token, int code, int uid, String packageName) { 1059 verifyIncomingUid(uid); 1060 verifyIncomingOp(code); 1061 ClientState client = (ClientState)token; 1062 synchronized (this) { 1063 Op op = getOpLocked(code, uid, packageName, true); 1064 if (op == null) { 1065 return; 1066 } 1067 if (client.mStartedOps != null) { 1068 if (!client.mStartedOps.remove(op)) { 1069 throw new IllegalStateException("Operation not started: uid" + op.uid 1070 + " pkg=" + op.packageName + " op=" + op.op); 1071 } 1072 } 1073 finishOperationLocked(op); 1074 } 1075 } 1076 1077 @Override 1078 public int permissionToOpCode(String permission) { 1079 return AppOpsManager.permissionToOpCode(permission); 1080 } 1081 1082 void finishOperationLocked(Op op) { 1083 if (op.nesting <= 1) { 1084 if (op.nesting == 1) { 1085 op.duration = (int)(System.currentTimeMillis() - op.time); 1086 op.time += op.duration; 1087 } else { 1088 Slog.w(TAG, "Finishing op nesting under-run: uid " + op.uid + " pkg " 1089 + op.packageName + " code " + op.op + " time=" + op.time 1090 + " duration=" + op.duration + " nesting=" + op.nesting); 1091 } 1092 op.nesting = 0; 1093 } else { 1094 op.nesting--; 1095 } 1096 } 1097 1098 private void verifyIncomingUid(int uid) { 1099 if (uid == Binder.getCallingUid()) { 1100 return; 1101 } 1102 if (Binder.getCallingPid() == Process.myPid()) { 1103 return; 1104 } 1105 mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS, 1106 Binder.getCallingPid(), Binder.getCallingUid(), null); 1107 } 1108 1109 private void verifyIncomingOp(int op) { 1110 if (op >= 0 && op < AppOpsManager._NUM_OP) { 1111 return; 1112 } 1113 throw new IllegalArgumentException("Bad operation #" + op); 1114 } 1115 1116 private UidState getUidStateLocked(int uid, boolean edit) { 1117 UidState uidState = mUidStates.get(uid); 1118 if (uidState == null) { 1119 if (!edit) { 1120 return null; 1121 } 1122 uidState = new UidState(uid); 1123 mUidStates.put(uid, uidState); 1124 } 1125 return uidState; 1126 } 1127 1128 private Ops getOpsLocked(int uid, String packageName, boolean edit) { 1129 if (uid == 0) { 1130 packageName = "root"; 1131 } else if (uid == Process.SHELL_UID) { 1132 packageName = "com.android.shell"; 1133 } 1134 return getOpsRawLocked(uid, packageName, edit); 1135 } 1136 1137 private Ops getOpsRawLocked(int uid, String packageName, boolean edit) { 1138 UidState uidState = getUidStateLocked(uid, edit); 1139 if (uidState == null) { 1140 return null; 1141 } 1142 1143 if (uidState.pkgOps == null) { 1144 if (!edit) { 1145 return null; 1146 } 1147 uidState.pkgOps = new ArrayMap<>(); 1148 } 1149 1150 Ops ops = uidState.pkgOps.get(packageName); 1151 if (ops == null) { 1152 if (!edit) { 1153 return null; 1154 } 1155 boolean isPrivileged = false; 1156 // This is the first time we have seen this package name under this uid, 1157 // so let's make sure it is valid. 1158 if (uid != 0) { 1159 final long ident = Binder.clearCallingIdentity(); 1160 try { 1161 int pkgUid = -1; 1162 try { 1163 ApplicationInfo appInfo = ActivityThread.getPackageManager() 1164 .getApplicationInfo(packageName, 0, UserHandle.getUserId(uid)); 1165 if (appInfo != null) { 1166 pkgUid = appInfo.uid; 1167 isPrivileged = (appInfo.privateFlags 1168 & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0; 1169 } else { 1170 if ("media".equals(packageName)) { 1171 pkgUid = Process.MEDIA_UID; 1172 isPrivileged = false; 1173 } else if ("audioserver".equals(packageName)) { 1174 pkgUid = Process.AUDIOSERVER_UID; 1175 isPrivileged = false; 1176 } 1177 } 1178 } catch (RemoteException e) { 1179 Slog.w(TAG, "Could not contact PackageManager", e); 1180 } 1181 if (pkgUid != uid) { 1182 // Oops! The package name is not valid for the uid they are calling 1183 // under. Abort. 1184 RuntimeException ex = new RuntimeException("here"); 1185 ex.fillInStackTrace(); 1186 Slog.w(TAG, "Bad call: specified package " + packageName 1187 + " under uid " + uid + " but it is really " + pkgUid, ex); 1188 return null; 1189 } 1190 } finally { 1191 Binder.restoreCallingIdentity(ident); 1192 } 1193 } 1194 ops = new Ops(packageName, uidState, isPrivileged); 1195 uidState.pkgOps.put(packageName, ops); 1196 } 1197 return ops; 1198 } 1199 1200 private void scheduleWriteLocked() { 1201 if (!mWriteScheduled) { 1202 mWriteScheduled = true; 1203 mHandler.postDelayed(mWriteRunner, WRITE_DELAY); 1204 } 1205 } 1206 1207 private void scheduleFastWriteLocked() { 1208 if (!mFastWriteScheduled) { 1209 mWriteScheduled = true; 1210 mFastWriteScheduled = true; 1211 mHandler.removeCallbacks(mWriteRunner); 1212 mHandler.postDelayed(mWriteRunner, 10*1000); 1213 } 1214 } 1215 1216 private Op getOpLocked(int code, int uid, String packageName, boolean edit) { 1217 Ops ops = getOpsLocked(uid, packageName, edit); 1218 if (ops == null) { 1219 return null; 1220 } 1221 return getOpLocked(ops, code, edit); 1222 } 1223 1224 private Op getOpLocked(Ops ops, int code, boolean edit) { 1225 Op op = ops.get(code); 1226 if (op == null) { 1227 if (!edit) { 1228 return null; 1229 } 1230 op = new Op(ops.uidState.uid, ops.packageName, code); 1231 ops.put(code, op); 1232 } 1233 if (edit) { 1234 scheduleWriteLocked(); 1235 } 1236 return op; 1237 } 1238 1239 private boolean isOpRestricted(int uid, int code, String packageName) { 1240 int userHandle = UserHandle.getUserId(uid); 1241 boolean[] opRestrictions = mOpRestrictions.get(userHandle); 1242 if ((opRestrictions != null) && opRestrictions[code]) { 1243 if (AppOpsManager.opAllowSystemBypassRestriction(code)) { 1244 synchronized (this) { 1245 Ops ops = getOpsLocked(uid, packageName, true); 1246 if ((ops != null) && ops.isPrivileged) { 1247 return false; 1248 } 1249 } 1250 } 1251 return true; 1252 } 1253 return false; 1254 } 1255 1256 void readState() { 1257 synchronized (mFile) { 1258 synchronized (this) { 1259 FileInputStream stream; 1260 try { 1261 stream = mFile.openRead(); 1262 } catch (FileNotFoundException e) { 1263 Slog.i(TAG, "No existing app ops " + mFile.getBaseFile() + "; starting empty"); 1264 return; 1265 } 1266 boolean success = false; 1267 mUidStates.clear(); 1268 try { 1269 XmlPullParser parser = Xml.newPullParser(); 1270 parser.setInput(stream, StandardCharsets.UTF_8.name()); 1271 int type; 1272 while ((type = parser.next()) != XmlPullParser.START_TAG 1273 && type != XmlPullParser.END_DOCUMENT) { 1274 ; 1275 } 1276 1277 if (type != XmlPullParser.START_TAG) { 1278 throw new IllegalStateException("no start tag found"); 1279 } 1280 1281 int outerDepth = parser.getDepth(); 1282 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 1283 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 1284 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 1285 continue; 1286 } 1287 1288 String tagName = parser.getName(); 1289 if (tagName.equals("pkg")) { 1290 readPackage(parser); 1291 } else if (tagName.equals("uid")) { 1292 readUidOps(parser); 1293 } else { 1294 Slog.w(TAG, "Unknown element under <app-ops>: " 1295 + parser.getName()); 1296 XmlUtils.skipCurrentTag(parser); 1297 } 1298 } 1299 success = true; 1300 } catch (IllegalStateException e) { 1301 Slog.w(TAG, "Failed parsing " + e); 1302 } catch (NullPointerException e) { 1303 Slog.w(TAG, "Failed parsing " + e); 1304 } catch (NumberFormatException e) { 1305 Slog.w(TAG, "Failed parsing " + e); 1306 } catch (XmlPullParserException e) { 1307 Slog.w(TAG, "Failed parsing " + e); 1308 } catch (IOException e) { 1309 Slog.w(TAG, "Failed parsing " + e); 1310 } catch (IndexOutOfBoundsException e) { 1311 Slog.w(TAG, "Failed parsing " + e); 1312 } finally { 1313 if (!success) { 1314 mUidStates.clear(); 1315 } 1316 try { 1317 stream.close(); 1318 } catch (IOException e) { 1319 } 1320 } 1321 } 1322 } 1323 } 1324 1325 void readUidOps(XmlPullParser parser) throws NumberFormatException, 1326 XmlPullParserException, IOException { 1327 final int uid = Integer.parseInt(parser.getAttributeValue(null, "n")); 1328 int outerDepth = parser.getDepth(); 1329 int type; 1330 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 1331 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 1332 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 1333 continue; 1334 } 1335 1336 String tagName = parser.getName(); 1337 if (tagName.equals("op")) { 1338 final int code = Integer.parseInt(parser.getAttributeValue(null, "n")); 1339 final int mode = Integer.parseInt(parser.getAttributeValue(null, "m")); 1340 UidState uidState = getUidStateLocked(uid, true); 1341 if (uidState.opModes == null) { 1342 uidState.opModes = new SparseIntArray(); 1343 } 1344 uidState.opModes.put(code, mode); 1345 } else { 1346 Slog.w(TAG, "Unknown element under <uid-ops>: " 1347 + parser.getName()); 1348 XmlUtils.skipCurrentTag(parser); 1349 } 1350 } 1351 } 1352 1353 void readPackage(XmlPullParser parser) throws NumberFormatException, 1354 XmlPullParserException, IOException { 1355 String pkgName = parser.getAttributeValue(null, "n"); 1356 int outerDepth = parser.getDepth(); 1357 int type; 1358 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 1359 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 1360 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 1361 continue; 1362 } 1363 1364 String tagName = parser.getName(); 1365 if (tagName.equals("uid")) { 1366 readUid(parser, pkgName); 1367 } else { 1368 Slog.w(TAG, "Unknown element under <pkg>: " 1369 + parser.getName()); 1370 XmlUtils.skipCurrentTag(parser); 1371 } 1372 } 1373 } 1374 1375 void readUid(XmlPullParser parser, String pkgName) throws NumberFormatException, 1376 XmlPullParserException, IOException { 1377 int uid = Integer.parseInt(parser.getAttributeValue(null, "n")); 1378 String isPrivilegedString = parser.getAttributeValue(null, "p"); 1379 boolean isPrivileged = false; 1380 if (isPrivilegedString == null) { 1381 try { 1382 IPackageManager packageManager = ActivityThread.getPackageManager(); 1383 if (packageManager != null) { 1384 ApplicationInfo appInfo = ActivityThread.getPackageManager() 1385 .getApplicationInfo(pkgName, 0, UserHandle.getUserId(uid)); 1386 if (appInfo != null) { 1387 isPrivileged = (appInfo.privateFlags 1388 & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0; 1389 } 1390 } else { 1391 // Could not load data, don't add to cache so it will be loaded later. 1392 return; 1393 } 1394 } catch (RemoteException e) { 1395 Slog.w(TAG, "Could not contact PackageManager", e); 1396 } 1397 } else { 1398 isPrivileged = Boolean.parseBoolean(isPrivilegedString); 1399 } 1400 int outerDepth = parser.getDepth(); 1401 int type; 1402 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 1403 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 1404 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 1405 continue; 1406 } 1407 1408 String tagName = parser.getName(); 1409 if (tagName.equals("op")) { 1410 Op op = new Op(uid, pkgName, Integer.parseInt(parser.getAttributeValue(null, "n"))); 1411 String mode = parser.getAttributeValue(null, "m"); 1412 if (mode != null) { 1413 op.mode = Integer.parseInt(mode); 1414 } 1415 String time = parser.getAttributeValue(null, "t"); 1416 if (time != null) { 1417 op.time = Long.parseLong(time); 1418 } 1419 time = parser.getAttributeValue(null, "r"); 1420 if (time != null) { 1421 op.rejectTime = Long.parseLong(time); 1422 } 1423 String dur = parser.getAttributeValue(null, "d"); 1424 if (dur != null) { 1425 op.duration = Integer.parseInt(dur); 1426 } 1427 String proxyUid = parser.getAttributeValue(null, "pu"); 1428 if (proxyUid != null) { 1429 op.proxyUid = Integer.parseInt(proxyUid); 1430 } 1431 String proxyPackageName = parser.getAttributeValue(null, "pp"); 1432 if (proxyPackageName != null) { 1433 op.proxyPackageName = proxyPackageName; 1434 } 1435 1436 UidState uidState = getUidStateLocked(uid, true); 1437 if (uidState.pkgOps == null) { 1438 uidState.pkgOps = new ArrayMap<>(); 1439 } 1440 1441 Ops ops = uidState.pkgOps.get(pkgName); 1442 if (ops == null) { 1443 ops = new Ops(pkgName, uidState, isPrivileged); 1444 uidState.pkgOps.put(pkgName, ops); 1445 } 1446 ops.put(op.op, op); 1447 } else { 1448 Slog.w(TAG, "Unknown element under <pkg>: " 1449 + parser.getName()); 1450 XmlUtils.skipCurrentTag(parser); 1451 } 1452 } 1453 } 1454 1455 void writeState() { 1456 synchronized (mFile) { 1457 List<AppOpsManager.PackageOps> allOps = getPackagesForOps(null); 1458 1459 FileOutputStream stream; 1460 try { 1461 stream = mFile.startWrite(); 1462 } catch (IOException e) { 1463 Slog.w(TAG, "Failed to write state: " + e); 1464 return; 1465 } 1466 1467 try { 1468 XmlSerializer out = new FastXmlSerializer(); 1469 out.setOutput(stream, StandardCharsets.UTF_8.name()); 1470 out.startDocument(null, true); 1471 out.startTag(null, "app-ops"); 1472 1473 final int uidStateCount = mUidStates.size(); 1474 for (int i = 0; i < uidStateCount; i++) { 1475 UidState uidState = mUidStates.valueAt(i); 1476 if (uidState.opModes != null && uidState.opModes.size() > 0) { 1477 out.startTag(null, "uid"); 1478 out.attribute(null, "n", Integer.toString(uidState.uid)); 1479 SparseIntArray uidOpModes = uidState.opModes; 1480 final int opCount = uidOpModes.size(); 1481 for (int j = 0; j < opCount; j++) { 1482 final int op = uidOpModes.keyAt(j); 1483 final int mode = uidOpModes.valueAt(j); 1484 out.startTag(null, "op"); 1485 out.attribute(null, "n", Integer.toString(op)); 1486 out.attribute(null, "m", Integer.toString(mode)); 1487 out.endTag(null, "op"); 1488 } 1489 out.endTag(null, "uid"); 1490 } 1491 } 1492 1493 if (allOps != null) { 1494 String lastPkg = null; 1495 for (int i=0; i<allOps.size(); i++) { 1496 AppOpsManager.PackageOps pkg = allOps.get(i); 1497 if (!pkg.getPackageName().equals(lastPkg)) { 1498 if (lastPkg != null) { 1499 out.endTag(null, "pkg"); 1500 } 1501 lastPkg = pkg.getPackageName(); 1502 out.startTag(null, "pkg"); 1503 out.attribute(null, "n", lastPkg); 1504 } 1505 out.startTag(null, "uid"); 1506 out.attribute(null, "n", Integer.toString(pkg.getUid())); 1507 synchronized (this) { 1508 Ops ops = getOpsLocked(pkg.getUid(), pkg.getPackageName(), false); 1509 // Should always be present as the list of PackageOps is generated 1510 // from Ops. 1511 if (ops != null) { 1512 out.attribute(null, "p", Boolean.toString(ops.isPrivileged)); 1513 } else { 1514 out.attribute(null, "p", Boolean.toString(false)); 1515 } 1516 } 1517 List<AppOpsManager.OpEntry> ops = pkg.getOps(); 1518 for (int j=0; j<ops.size(); j++) { 1519 AppOpsManager.OpEntry op = ops.get(j); 1520 out.startTag(null, "op"); 1521 out.attribute(null, "n", Integer.toString(op.getOp())); 1522 if (op.getMode() != AppOpsManager.opToDefaultMode(op.getOp())) { 1523 out.attribute(null, "m", Integer.toString(op.getMode())); 1524 } 1525 long time = op.getTime(); 1526 if (time != 0) { 1527 out.attribute(null, "t", Long.toString(time)); 1528 } 1529 time = op.getRejectTime(); 1530 if (time != 0) { 1531 out.attribute(null, "r", Long.toString(time)); 1532 } 1533 int dur = op.getDuration(); 1534 if (dur != 0) { 1535 out.attribute(null, "d", Integer.toString(dur)); 1536 } 1537 int proxyUid = op.getProxyUid(); 1538 if (proxyUid != -1) { 1539 out.attribute(null, "pu", Integer.toString(proxyUid)); 1540 } 1541 String proxyPackageName = op.getProxyPackageName(); 1542 if (proxyPackageName != null) { 1543 out.attribute(null, "pp", proxyPackageName); 1544 } 1545 out.endTag(null, "op"); 1546 } 1547 out.endTag(null, "uid"); 1548 } 1549 if (lastPkg != null) { 1550 out.endTag(null, "pkg"); 1551 } 1552 } 1553 1554 out.endTag(null, "app-ops"); 1555 out.endDocument(); 1556 mFile.finishWrite(stream); 1557 } catch (IOException e) { 1558 Slog.w(TAG, "Failed to write state, restoring backup.", e); 1559 mFile.failWrite(stream); 1560 } 1561 } 1562 } 1563 1564 static class Shell extends ShellCommand { 1565 final IAppOpsService mInterface; 1566 final AppOpsService mInternal; 1567 1568 int userId = UserHandle.USER_SYSTEM; 1569 String packageName; 1570 String opStr; 1571 int op; 1572 int packageUid; 1573 1574 Shell(IAppOpsService iface, AppOpsService internal) { 1575 mInterface = iface; 1576 mInternal = internal; 1577 } 1578 1579 @Override 1580 public int onCommand(String cmd) { 1581 return onShellCommand(this, cmd); 1582 } 1583 1584 @Override 1585 public void onHelp() { 1586 PrintWriter pw = getOutPrintWriter(); 1587 dumpCommandHelp(pw); 1588 } 1589 1590 private int strOpToOp(String op, PrintWriter err) { 1591 try { 1592 return AppOpsManager.strOpToOp(op); 1593 } catch (IllegalArgumentException e) { 1594 } 1595 try { 1596 return Integer.parseInt(op); 1597 } catch (NumberFormatException e) { 1598 } 1599 try { 1600 return AppOpsManager.strDebugOpToOp(op); 1601 } catch (IllegalArgumentException e) { 1602 err.println("Error: " + e.getMessage()); 1603 return -1; 1604 } 1605 } 1606 1607 int parseUserPackageOp(boolean reqOp, PrintWriter err) throws RemoteException { 1608 userId = UserHandle.USER_CURRENT; 1609 packageName = null; 1610 opStr = null; 1611 for (String argument; (argument = getNextArg()) != null;) { 1612 if ("--user".equals(argument)) { 1613 userId = UserHandle.parseUserArg(getNextArgRequired()); 1614 } else { 1615 if (packageName == null) { 1616 packageName = argument; 1617 } else if (opStr == null) { 1618 opStr = argument; 1619 break; 1620 } 1621 } 1622 } 1623 if (packageName == null) { 1624 err.println("Error: Package name not specified."); 1625 return -1; 1626 } else if (opStr == null && reqOp) { 1627 err.println("Error: Operation not specified."); 1628 return -1; 1629 } 1630 if (opStr != null) { 1631 op = strOpToOp(opStr, err); 1632 if (op < 0) { 1633 return -1; 1634 } 1635 } else { 1636 op = AppOpsManager.OP_NONE; 1637 } 1638 if (userId == UserHandle.USER_CURRENT) { 1639 userId = ActivityManager.getCurrentUser(); 1640 } 1641 if ("root".equals(packageName)) { 1642 packageUid = 0; 1643 } else { 1644 packageUid = AppGlobals.getPackageManager().getPackageUid(packageName, userId); 1645 } 1646 if (packageUid < 0) { 1647 err.println("Error: No UID for " + packageName + " in user " + userId); 1648 return -1; 1649 } 1650 return 0; 1651 } 1652 } 1653 1654 @Override public void onShellCommand(FileDescriptor in, FileDescriptor out, 1655 FileDescriptor err, String[] args, ResultReceiver resultReceiver) { 1656 (new Shell(this, this)).exec(this, in, out, err, args, resultReceiver); 1657 } 1658 1659 static void dumpCommandHelp(PrintWriter pw) { 1660 pw.println("AppOps service (appops) commands:"); 1661 pw.println(" help"); 1662 pw.println(" Print this help text."); 1663 pw.println(" set [--user <USER_ID>] <PACKAGE> <OP> <MODE>"); 1664 pw.println(" Set the mode for a particular application and operation."); 1665 pw.println(" get [--user <USER_ID>] <PACKAGE> [<OP>]"); 1666 pw.println(" Return the mode for a particular application and optional operation."); 1667 pw.println(" reset [--user <USER_ID>] [<PACKAGE>]"); 1668 pw.println(" Reset the given application or all applications to default modes."); 1669 pw.println(" write-settings"); 1670 pw.println(" Immediately write pending changes to storage."); 1671 pw.println(" read-settings"); 1672 pw.println(" Read the last written settings, replacing current state in RAM."); 1673 pw.println(" options:"); 1674 pw.println(" <PACKAGE> an Android package name."); 1675 pw.println(" <OP> an AppOps operation."); 1676 pw.println(" <MODE> one of allow, ignore, deny, or default"); 1677 pw.println(" <USER_ID> the user id under which the package is installed. If --user is not"); 1678 pw.println(" specified, the current user is assumed."); 1679 } 1680 1681 static int onShellCommand(Shell shell, String cmd) { 1682 if (cmd == null) { 1683 return shell.handleDefaultCommands(cmd); 1684 } 1685 PrintWriter pw = shell.getOutPrintWriter(); 1686 PrintWriter err = shell.getErrPrintWriter(); 1687 try { 1688 switch (cmd) { 1689 case "set": { 1690 int res = shell.parseUserPackageOp(true, err); 1691 if (res < 0) { 1692 return res; 1693 } 1694 String modeStr = shell.getNextArg(); 1695 if (modeStr == null) { 1696 err.println("Error: Mode not specified."); 1697 return -1; 1698 } 1699 1700 final int mode; 1701 switch (modeStr) { 1702 case "allow": 1703 mode = AppOpsManager.MODE_ALLOWED; 1704 break; 1705 case "deny": 1706 mode = AppOpsManager.MODE_ERRORED; 1707 break; 1708 case "ignore": 1709 mode = AppOpsManager.MODE_IGNORED; 1710 break; 1711 case "default": 1712 mode = AppOpsManager.MODE_DEFAULT; 1713 break; 1714 default: 1715 err.println("Error: Mode " + modeStr + " is not valid,"); 1716 return -1; 1717 } 1718 1719 shell.mInterface.setMode(shell.op, shell.packageUid, shell.packageName, mode); 1720 return 0; 1721 } 1722 case "get": { 1723 int res = shell.parseUserPackageOp(false, err); 1724 if (res < 0) { 1725 return res; 1726 } 1727 1728 List<AppOpsManager.PackageOps> ops = shell.mInterface.getOpsForPackage( 1729 shell.packageUid, shell.packageName, 1730 shell.op != AppOpsManager.OP_NONE ? new int[] {shell.op} : null); 1731 if (ops == null || ops.size() <= 0) { 1732 pw.println("No operations."); 1733 return 0; 1734 } 1735 final long now = System.currentTimeMillis(); 1736 for (int i=0; i<ops.size(); i++) { 1737 List<AppOpsManager.OpEntry> entries = ops.get(i).getOps(); 1738 for (int j=0; j<entries.size(); j++) { 1739 AppOpsManager.OpEntry ent = entries.get(j); 1740 pw.print(AppOpsManager.opToName(ent.getOp())); 1741 pw.print(": "); 1742 switch (ent.getMode()) { 1743 case AppOpsManager.MODE_ALLOWED: 1744 pw.print("allow"); 1745 break; 1746 case AppOpsManager.MODE_IGNORED: 1747 pw.print("ignore"); 1748 break; 1749 case AppOpsManager.MODE_ERRORED: 1750 pw.print("deny"); 1751 break; 1752 case AppOpsManager.MODE_DEFAULT: 1753 pw.print("default"); 1754 break; 1755 default: 1756 pw.print("mode="); 1757 pw.print(ent.getMode()); 1758 break; 1759 } 1760 if (ent.getTime() != 0) { 1761 pw.print("; time="); 1762 TimeUtils.formatDuration(now - ent.getTime(), pw); 1763 pw.print(" ago"); 1764 } 1765 if (ent.getRejectTime() != 0) { 1766 pw.print("; rejectTime="); 1767 TimeUtils.formatDuration(now - ent.getRejectTime(), pw); 1768 pw.print(" ago"); 1769 } 1770 if (ent.getDuration() == -1) { 1771 pw.print(" (running)"); 1772 } else if (ent.getDuration() != 0) { 1773 pw.print("; duration="); 1774 TimeUtils.formatDuration(ent.getDuration(), pw); 1775 } 1776 pw.println(); 1777 } 1778 } 1779 return 0; 1780 } 1781 case "reset": { 1782 String packageName = null; 1783 int userId = UserHandle.USER_CURRENT; 1784 for (String argument; (argument = shell.getNextArg()) != null;) { 1785 if ("--user".equals(argument)) { 1786 String userStr = shell.getNextArgRequired(); 1787 userId = UserHandle.parseUserArg(userStr); 1788 } else { 1789 if (packageName == null) { 1790 packageName = argument; 1791 } else { 1792 err.println("Error: Unsupported argument: " + argument); 1793 return -1; 1794 } 1795 } 1796 } 1797 1798 if (userId == UserHandle.USER_CURRENT) { 1799 userId = ActivityManager.getCurrentUser(); 1800 } 1801 1802 shell.mInterface.resetAllModes(userId, packageName); 1803 pw.print("Reset all modes for: "); 1804 if (userId == UserHandle.USER_ALL) { 1805 pw.print("all users"); 1806 } else { 1807 pw.print("user "); pw.print(userId); 1808 } 1809 pw.print(", "); 1810 if (packageName == null) { 1811 pw.println("all packages"); 1812 } else { 1813 pw.print("package "); pw.println(packageName); 1814 } 1815 return 0; 1816 } 1817 case "write-settings": { 1818 shell.mInternal.mContext.enforcePermission( 1819 android.Manifest.permission.UPDATE_APP_OPS_STATS, 1820 Binder.getCallingPid(), Binder.getCallingUid(), null); 1821 long token = Binder.clearCallingIdentity(); 1822 try { 1823 synchronized (shell.mInternal) { 1824 shell.mInternal.mHandler.removeCallbacks(shell.mInternal.mWriteRunner); 1825 } 1826 shell.mInternal.writeState(); 1827 pw.println("Current settings written."); 1828 } finally { 1829 Binder.restoreCallingIdentity(token); 1830 } 1831 return 0; 1832 } 1833 case "read-settings": { 1834 shell.mInternal.mContext.enforcePermission( 1835 android.Manifest.permission.UPDATE_APP_OPS_STATS, 1836 Binder.getCallingPid(), Binder.getCallingUid(), null); 1837 long token = Binder.clearCallingIdentity(); 1838 try { 1839 shell.mInternal.readState(); 1840 pw.println("Last settings read."); 1841 } finally { 1842 Binder.restoreCallingIdentity(token); 1843 } 1844 return 0; 1845 } 1846 default: 1847 return shell.handleDefaultCommands(cmd); 1848 } 1849 } catch (RemoteException e) { 1850 pw.println("Remote exception: " + e); 1851 } 1852 return -1; 1853 } 1854 1855 private void dumpHelp(PrintWriter pw) { 1856 pw.println("AppOps service (appops) dump options:"); 1857 pw.println(" none"); 1858 } 1859 1860 @Override 1861 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1862 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 1863 != PackageManager.PERMISSION_GRANTED) { 1864 pw.println("Permission Denial: can't dump ApOps service from from pid=" 1865 + Binder.getCallingPid() 1866 + ", uid=" + Binder.getCallingUid()); 1867 return; 1868 } 1869 1870 if (args != null) { 1871 for (int i=0; i<args.length; i++) { 1872 String arg = args[i]; 1873 if ("-h".equals(arg)) { 1874 dumpHelp(pw); 1875 return; 1876 } else if ("-a".equals(arg)) { 1877 // dump all data 1878 } else if (arg.length() > 0 && arg.charAt(0) == '-'){ 1879 pw.println("Unknown option: " + arg); 1880 return; 1881 } else { 1882 pw.println("Unknown command: " + arg); 1883 return; 1884 } 1885 } 1886 } 1887 1888 synchronized (this) { 1889 pw.println("Current AppOps Service state:"); 1890 final long now = System.currentTimeMillis(); 1891 boolean needSep = false; 1892 if (mOpModeWatchers.size() > 0) { 1893 needSep = true; 1894 pw.println(" Op mode watchers:"); 1895 for (int i=0; i<mOpModeWatchers.size(); i++) { 1896 pw.print(" Op "); pw.print(AppOpsManager.opToName(mOpModeWatchers.keyAt(i))); 1897 pw.println(":"); 1898 ArrayList<Callback> callbacks = mOpModeWatchers.valueAt(i); 1899 for (int j=0; j<callbacks.size(); j++) { 1900 pw.print(" #"); pw.print(j); pw.print(": "); 1901 pw.println(callbacks.get(j)); 1902 } 1903 } 1904 } 1905 if (mPackageModeWatchers.size() > 0) { 1906 needSep = true; 1907 pw.println(" Package mode watchers:"); 1908 for (int i=0; i<mPackageModeWatchers.size(); i++) { 1909 pw.print(" Pkg "); pw.print(mPackageModeWatchers.keyAt(i)); 1910 pw.println(":"); 1911 ArrayList<Callback> callbacks = mPackageModeWatchers.valueAt(i); 1912 for (int j=0; j<callbacks.size(); j++) { 1913 pw.print(" #"); pw.print(j); pw.print(": "); 1914 pw.println(callbacks.get(j)); 1915 } 1916 } 1917 } 1918 if (mModeWatchers.size() > 0) { 1919 needSep = true; 1920 pw.println(" All mode watchers:"); 1921 for (int i=0; i<mModeWatchers.size(); i++) { 1922 pw.print(" "); pw.print(mModeWatchers.keyAt(i)); 1923 pw.print(" -> "); pw.println(mModeWatchers.valueAt(i)); 1924 } 1925 } 1926 if (mClients.size() > 0) { 1927 needSep = true; 1928 pw.println(" Clients:"); 1929 for (int i=0; i<mClients.size(); i++) { 1930 pw.print(" "); pw.print(mClients.keyAt(i)); pw.println(":"); 1931 ClientState cs = mClients.valueAt(i); 1932 pw.print(" "); pw.println(cs); 1933 if (cs.mStartedOps != null && cs.mStartedOps.size() > 0) { 1934 pw.println(" Started ops:"); 1935 for (int j=0; j<cs.mStartedOps.size(); j++) { 1936 Op op = cs.mStartedOps.get(j); 1937 pw.print(" "); pw.print("uid="); pw.print(op.uid); 1938 pw.print(" pkg="); pw.print(op.packageName); 1939 pw.print(" op="); pw.println(AppOpsManager.opToName(op.op)); 1940 } 1941 } 1942 } 1943 } 1944 if (mAudioRestrictions.size() > 0) { 1945 boolean printedHeader = false; 1946 for (int o=0; o<mAudioRestrictions.size(); o++) { 1947 final String op = AppOpsManager.opToName(mAudioRestrictions.keyAt(o)); 1948 final SparseArray<Restriction> restrictions = mAudioRestrictions.valueAt(o); 1949 for (int i=0; i<restrictions.size(); i++) { 1950 if (!printedHeader){ 1951 pw.println(" Audio Restrictions:"); 1952 printedHeader = true; 1953 needSep = true; 1954 } 1955 final int usage = restrictions.keyAt(i); 1956 pw.print(" "); pw.print(op); 1957 pw.print(" usage="); pw.print(AudioAttributes.usageToString(usage)); 1958 Restriction r = restrictions.valueAt(i); 1959 pw.print(": mode="); pw.println(r.mode); 1960 if (!r.exceptionPackages.isEmpty()) { 1961 pw.println(" Exceptions:"); 1962 for (int j=0; j<r.exceptionPackages.size(); j++) { 1963 pw.print(" "); pw.println(r.exceptionPackages.valueAt(j)); 1964 } 1965 } 1966 } 1967 } 1968 } 1969 if (needSep) { 1970 pw.println(); 1971 } 1972 for (int i=0; i<mUidStates.size(); i++) { 1973 UidState uidState = mUidStates.valueAt(i); 1974 1975 pw.print(" Uid "); UserHandle.formatUid(pw, uidState.uid); pw.println(":"); 1976 1977 SparseIntArray opModes = uidState.opModes; 1978 if (opModes != null) { 1979 final int opModeCount = opModes.size(); 1980 for (int j = 0; j < opModeCount; j++) { 1981 final int code = opModes.keyAt(j); 1982 final int mode = opModes.valueAt(j); 1983 pw.print(" "); pw.print(AppOpsManager.opToName(code)); 1984 pw.print(": mode="); pw.println(mode); 1985 } 1986 } 1987 1988 ArrayMap<String, Ops> pkgOps = uidState.pkgOps; 1989 if (pkgOps == null) { 1990 continue; 1991 } 1992 1993 for (Ops ops : pkgOps.values()) { 1994 pw.print(" Package "); pw.print(ops.packageName); pw.println(":"); 1995 for (int j=0; j<ops.size(); j++) { 1996 Op op = ops.valueAt(j); 1997 pw.print(" "); pw.print(AppOpsManager.opToName(op.op)); 1998 pw.print(": mode="); pw.print(op.mode); 1999 if (op.time != 0) { 2000 pw.print("; time="); TimeUtils.formatDuration(now-op.time, pw); 2001 pw.print(" ago"); 2002 } 2003 if (op.rejectTime != 0) { 2004 pw.print("; rejectTime="); TimeUtils.formatDuration(now-op.rejectTime, pw); 2005 pw.print(" ago"); 2006 } 2007 if (op.duration == -1) { 2008 pw.print(" (running)"); 2009 } else if (op.duration != 0) { 2010 pw.print("; duration="); TimeUtils.formatDuration(op.duration, pw); 2011 } 2012 pw.println(); 2013 } 2014 } 2015 } 2016 } 2017 } 2018 2019 private static final class Restriction { 2020 private static final ArraySet<String> NO_EXCEPTIONS = new ArraySet<String>(); 2021 int mode; 2022 ArraySet<String> exceptionPackages = NO_EXCEPTIONS; 2023 } 2024 2025 @Override 2026 public void setUserRestrictions(Bundle restrictions, int userHandle) throws RemoteException { 2027 checkSystemUid("setUserRestrictions"); 2028 boolean[] opRestrictions = mOpRestrictions.get(userHandle); 2029 if (opRestrictions == null) { 2030 opRestrictions = new boolean[AppOpsManager._NUM_OP]; 2031 mOpRestrictions.put(userHandle, opRestrictions); 2032 } 2033 for (int i = 0; i < opRestrictions.length; ++i) { 2034 String restriction = AppOpsManager.opToRestriction(i); 2035 if (restriction != null) { 2036 opRestrictions[i] = restrictions.getBoolean(restriction, false); 2037 } else { 2038 opRestrictions[i] = false; 2039 } 2040 } 2041 } 2042 2043 @Override 2044 public void removeUser(int userHandle) throws RemoteException { 2045 checkSystemUid("removeUser"); 2046 mOpRestrictions.remove(userHandle); 2047 } 2048 2049 private void checkSystemUid(String function) { 2050 int uid = Binder.getCallingUid(); 2051 if (uid != Process.SYSTEM_UID) { 2052 throw new SecurityException(function + " must by called by the system"); 2053 } 2054 } 2055 2056 private static String[] getPackagesForUid(int uid) { 2057 String[] packageNames = null; 2058 try { 2059 packageNames = AppGlobals.getPackageManager().getPackagesForUid(uid); 2060 } catch (RemoteException e) { 2061 /* ignore - local call */ 2062 } 2063 if (packageNames == null) { 2064 return EmptyArray.STRING; 2065 } 2066 return packageNames; 2067 } 2068} 2069