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