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