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