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