1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.appop; 18 19 import static android.app.AppOpsManager.MODE_ALLOWED; 20 import static android.app.AppOpsManager.OP_NONE; 21 import static android.app.AppOpsManager.OP_SCHEDULE_EXACT_ALARM; 22 import static android.app.AppOpsManager.OP_USE_FULL_SCREEN_INTENT; 23 import static android.app.AppOpsManager.WATCH_FOREGROUND_CHANGES; 24 import static android.app.AppOpsManager.opRestrictsRead; 25 import static android.app.AppOpsManager.opToDefaultMode; 26 27 import static com.android.server.appop.AppOpsService.ModeCallback.ALL_OPS; 28 29 import android.Manifest; 30 import android.annotation.NonNull; 31 import android.annotation.Nullable; 32 import android.annotation.UserIdInt; 33 import android.app.AppGlobals; 34 import android.app.AppOpsManager; 35 import android.app.AppOpsManager.Mode; 36 import android.content.Context; 37 import android.content.pm.PackageManager; 38 import android.content.pm.PackageManagerInternal; 39 import android.content.pm.UserPackage; 40 import android.os.AsyncTask; 41 import android.os.Binder; 42 import android.os.Handler; 43 import android.os.RemoteException; 44 import android.os.UserHandle; 45 import android.permission.PermissionManager; 46 import android.util.ArrayMap; 47 import android.util.ArraySet; 48 import android.util.AtomicFile; 49 import android.util.Slog; 50 import android.util.SparseArray; 51 import android.util.SparseBooleanArray; 52 import android.util.SparseIntArray; 53 import android.util.Xml; 54 55 import com.android.internal.annotations.GuardedBy; 56 import com.android.internal.annotations.VisibleForTesting; 57 import com.android.internal.util.XmlUtils; 58 import com.android.internal.util.function.pooled.PooledLambda; 59 import com.android.modules.utils.TypedXmlPullParser; 60 import com.android.modules.utils.TypedXmlSerializer; 61 import com.android.server.LocalServices; 62 import com.android.server.pm.UserManagerInternal; 63 import com.android.server.pm.permission.PermissionManagerServiceInternal; 64 65 import libcore.util.EmptyArray; 66 67 import org.xmlpull.v1.XmlPullParser; 68 import org.xmlpull.v1.XmlPullParserException; 69 70 import java.io.File; 71 import java.io.FileInputStream; 72 import java.io.FileNotFoundException; 73 import java.io.FileOutputStream; 74 import java.io.IOException; 75 import java.io.PrintWriter; 76 import java.util.ArrayList; 77 import java.util.Collections; 78 import java.util.List; 79 import java.util.Objects; 80 81 82 /** 83 * Legacy implementation for App-ops service's app-op mode (uid and package) storage and access. 84 * In the future this class will also include mode callbacks and op restrictions. 85 */ 86 public class AppOpsCheckingServiceImpl implements AppOpsCheckingServiceInterface { 87 88 static final String TAG = "LegacyAppOpsServiceInterfaceImpl"; 89 90 private static final boolean DEBUG = false; 91 92 // Write at most every 30 minutes. 93 private static final long WRITE_DELAY = DEBUG ? 1000 : 30 * 60 * 1000; 94 95 /** 96 * Sentinel integer version to denote that there was no appops.xml found on boot. 97 * This will happen when a device boots with no existing userdata. 98 */ 99 private static final int NO_FILE_VERSION = -2; 100 101 /** 102 * Sentinel integer version to denote that there was no version in the appops.xml found on boot. 103 * This means the file is coming from a build before versioning was added. 104 */ 105 private static final int NO_VERSION = -1; 106 107 /** 108 * Increment by one every time and add the corresponding upgrade logic in 109 * {@link #upgradeLocked(int)} below. The first version was 1. 110 */ 111 @VisibleForTesting 112 static final int CURRENT_VERSION = 4; 113 114 /** 115 * This stores the version of appops.xml seen at boot. If this is smaller than 116 * {@link #CURRENT_VERSION}, then we will run {@link #upgradeLocked(int)} on startup. 117 */ 118 private int mVersionAtBoot = NO_FILE_VERSION; 119 120 // Must be the same object that the AppOpsService is using for locking. 121 final Object mLock; 122 final Handler mHandler; 123 final Context mContext; 124 final SparseArray<int[]> mSwitchedOps; 125 126 @GuardedBy("mLock") 127 @VisibleForTesting 128 final SparseArray<SparseIntArray> mUidModes = new SparseArray<>(); 129 130 @GuardedBy("mLock") 131 final SparseArray<ArrayMap<String, SparseIntArray>> mUserPackageModes = new SparseArray<>(); 132 133 final SparseArray<ArraySet<OnOpModeChangedListener>> mOpModeWatchers = new SparseArray<>(); 134 final ArrayMap<String, ArraySet<OnOpModeChangedListener>> mPackageModeWatchers = 135 new ArrayMap<>(); 136 137 final AtomicFile mFile; 138 final Runnable mWriteRunner = new Runnable() { 139 public void run() { 140 synchronized (mLock) { 141 mWriteScheduled = false; 142 mFastWriteScheduled = false; 143 AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() { 144 @Override 145 protected Void doInBackground(Void... params) { 146 writeState(); 147 return null; 148 } 149 }; 150 task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null); 151 } 152 } 153 }; 154 155 boolean mWriteScheduled; 156 boolean mFastWriteScheduled; 157 158 159 // Constant meaning that any UID should be matched when dispatching callbacks 160 private static final int UID_ANY = -2; 161 AppOpsCheckingServiceImpl(File storageFile, @NonNull Object lock, Handler handler, Context context, SparseArray<int[]> switchedOps)162 AppOpsCheckingServiceImpl(File storageFile, 163 @NonNull Object lock, Handler handler, Context context, 164 SparseArray<int[]> switchedOps) { 165 this.mFile = new AtomicFile(storageFile); 166 this.mLock = lock; 167 this.mHandler = handler; 168 this.mContext = context; 169 this.mSwitchedOps = switchedOps; 170 } 171 172 @Override systemReady()173 public void systemReady() { 174 synchronized (mLock) { 175 // TODO: This file version upgrade code may still need to happen after we switch to 176 // another implementation of AppOpsCheckingServiceInterface. 177 upgradeLocked(mVersionAtBoot); 178 } 179 } 180 181 @Override getNonDefaultUidModes(int uid)182 public SparseIntArray getNonDefaultUidModes(int uid) { 183 synchronized (mLock) { 184 SparseIntArray opModes = mUidModes.get(uid, null); 185 if (opModes == null) { 186 return new SparseIntArray(); 187 } 188 return opModes.clone(); 189 } 190 } 191 192 @Override getNonDefaultPackageModes(String packageName, int userId)193 public SparseIntArray getNonDefaultPackageModes(String packageName, int userId) { 194 synchronized (mLock) { 195 ArrayMap<String, SparseIntArray> packageModes = mUserPackageModes.get(userId); 196 if (packageModes == null) { 197 return new SparseIntArray(); 198 } 199 SparseIntArray opModes = packageModes.get(packageName); 200 if (opModes == null) { 201 return new SparseIntArray(); 202 } 203 return opModes.clone(); 204 } 205 } 206 207 @Override getUidMode(int uid, int op)208 public int getUidMode(int uid, int op) { 209 synchronized (mLock) { 210 SparseIntArray opModes = mUidModes.get(uid, null); 211 if (opModes == null) { 212 return AppOpsManager.opToDefaultMode(op); 213 } 214 return opModes.get(op, AppOpsManager.opToDefaultMode(op)); 215 } 216 } 217 218 @Override setUidMode(int uid, int op, int mode)219 public boolean setUidMode(int uid, int op, int mode) { 220 final int defaultMode = AppOpsManager.opToDefaultMode(op); 221 synchronized (mLock) { 222 SparseIntArray opModes = mUidModes.get(uid, null); 223 if (opModes == null) { 224 if (mode != defaultMode) { 225 opModes = new SparseIntArray(); 226 mUidModes.put(uid, opModes); 227 opModes.put(op, mode); 228 scheduleWriteLocked(); 229 } 230 } else { 231 if (opModes.indexOfKey(op) >= 0 && opModes.get(op) == mode) { 232 return false; 233 } 234 if (mode == defaultMode) { 235 opModes.delete(op); 236 if (opModes.size() <= 0) { 237 opModes = null; 238 mUidModes.delete(uid); 239 } 240 } else { 241 opModes.put(op, mode); 242 } 243 scheduleWriteLocked(); 244 } 245 } 246 return true; 247 } 248 249 @Override getPackageMode(String packageName, int op, @UserIdInt int userId)250 public int getPackageMode(String packageName, int op, @UserIdInt int userId) { 251 synchronized (mLock) { 252 ArrayMap<String, SparseIntArray> packageModes = mUserPackageModes.get(userId, null); 253 if (packageModes == null) { 254 return AppOpsManager.opToDefaultMode(op); 255 } 256 SparseIntArray opModes = packageModes.getOrDefault(packageName, null); 257 if (opModes == null) { 258 return AppOpsManager.opToDefaultMode(op); 259 } 260 return opModes.get(op, AppOpsManager.opToDefaultMode(op)); 261 } 262 } 263 264 @Override setPackageMode(String packageName, int op, @Mode int mode, @UserIdInt int userId)265 public void setPackageMode(String packageName, int op, @Mode int mode, @UserIdInt int userId) { 266 final int defaultMode = AppOpsManager.opToDefaultMode(op); 267 synchronized (mLock) { 268 ArrayMap<String, SparseIntArray> packageModes = mUserPackageModes.get(userId, null); 269 if (packageModes == null) { 270 packageModes = new ArrayMap<>(); 271 mUserPackageModes.put(userId, packageModes); 272 } 273 SparseIntArray opModes = packageModes.get(packageName); 274 if (opModes == null) { 275 if (mode != defaultMode) { 276 opModes = new SparseIntArray(); 277 packageModes.put(packageName, opModes); 278 opModes.put(op, mode); 279 scheduleWriteLocked(); 280 } 281 } else { 282 if (opModes.indexOfKey(op) >= 0 && opModes.get(op) == mode) { 283 return; 284 } 285 if (mode == defaultMode) { 286 opModes.delete(op); 287 if (opModes.size() <= 0) { 288 opModes = null; 289 packageModes.remove(packageName); 290 } 291 } else { 292 opModes.put(op, mode); 293 } 294 scheduleWriteLocked(); 295 } 296 } 297 } 298 299 @Override removeUid(int uid)300 public void removeUid(int uid) { 301 synchronized (mLock) { 302 SparseIntArray opModes = mUidModes.get(uid); 303 if (opModes == null) { 304 return; 305 } 306 mUidModes.remove(uid); 307 scheduleFastWriteLocked(); 308 } 309 } 310 311 @Override areUidModesDefault(int uid)312 public boolean areUidModesDefault(int uid) { 313 synchronized (mLock) { 314 SparseIntArray opModes = mUidModes.get(uid); 315 return (opModes == null || opModes.size() <= 0); 316 } 317 } 318 319 @Override arePackageModesDefault(@onNull String packageName, @UserIdInt int userId)320 public boolean arePackageModesDefault(@NonNull String packageName, @UserIdInt int userId) { 321 synchronized (mLock) { 322 ArrayMap<String, SparseIntArray> packageModes = mUserPackageModes.get(userId, null); 323 if (packageModes == null) { 324 return true; 325 } 326 SparseIntArray opModes = packageModes.get(packageName); 327 return (opModes == null || opModes.size() <= 0); 328 } 329 } 330 331 @Override removePackage(String packageName, @UserIdInt int userId)332 public boolean removePackage(String packageName, @UserIdInt int userId) { 333 synchronized (mLock) { 334 ArrayMap<String, SparseIntArray> packageModes = mUserPackageModes.get(userId, null); 335 if (packageModes == null) { 336 return false; 337 } 338 SparseIntArray ops = packageModes.remove(packageName); 339 if (ops != null) { 340 scheduleFastWriteLocked(); 341 return true; 342 } 343 return false; 344 } 345 } 346 347 @Override clearAllModes()348 public void clearAllModes() { 349 synchronized (mLock) { 350 mUidModes.clear(); 351 mUserPackageModes.clear(); 352 } 353 } 354 355 @Override startWatchingOpModeChanged(@onNull OnOpModeChangedListener changedListener, int op)356 public void startWatchingOpModeChanged(@NonNull OnOpModeChangedListener changedListener, 357 int op) { 358 Objects.requireNonNull(changedListener); 359 synchronized (mLock) { 360 ArraySet<OnOpModeChangedListener> modeWatcherSet = mOpModeWatchers.get(op); 361 if (modeWatcherSet == null) { 362 modeWatcherSet = new ArraySet<>(); 363 mOpModeWatchers.put(op, modeWatcherSet); 364 } 365 modeWatcherSet.add(changedListener); 366 } 367 } 368 369 @Override startWatchingPackageModeChanged(@onNull OnOpModeChangedListener changedListener, @NonNull String packageName)370 public void startWatchingPackageModeChanged(@NonNull OnOpModeChangedListener changedListener, 371 @NonNull String packageName) { 372 Objects.requireNonNull(changedListener); 373 Objects.requireNonNull(packageName); 374 synchronized (mLock) { 375 ArraySet<OnOpModeChangedListener> modeWatcherSet = 376 mPackageModeWatchers.get(packageName); 377 if (modeWatcherSet == null) { 378 modeWatcherSet = new ArraySet<>(); 379 mPackageModeWatchers.put(packageName, modeWatcherSet); 380 } 381 modeWatcherSet.add(changedListener); 382 } 383 } 384 385 @Override removeListener(@onNull OnOpModeChangedListener changedListener)386 public void removeListener(@NonNull OnOpModeChangedListener changedListener) { 387 Objects.requireNonNull(changedListener); 388 389 synchronized (mLock) { 390 for (int i = mOpModeWatchers.size() - 1; i >= 0; i--) { 391 ArraySet<OnOpModeChangedListener> cbs = mOpModeWatchers.valueAt(i); 392 cbs.remove(changedListener); 393 if (cbs.size() <= 0) { 394 mOpModeWatchers.removeAt(i); 395 } 396 } 397 398 for (int i = mPackageModeWatchers.size() - 1; i >= 0; i--) { 399 ArraySet<OnOpModeChangedListener> cbs = mPackageModeWatchers.valueAt(i); 400 cbs.remove(changedListener); 401 if (cbs.size() <= 0) { 402 mPackageModeWatchers.removeAt(i); 403 } 404 } 405 } 406 } 407 408 @Override getOpModeChangedListeners(int op)409 public ArraySet<OnOpModeChangedListener> getOpModeChangedListeners(int op) { 410 synchronized (mLock) { 411 ArraySet<OnOpModeChangedListener> modeChangedListenersSet = mOpModeWatchers.get(op); 412 if (modeChangedListenersSet == null) { 413 return new ArraySet<>(); 414 } 415 return new ArraySet<>(modeChangedListenersSet); 416 } 417 } 418 419 @Override getPackageModeChangedListeners( @onNull String packageName)420 public ArraySet<OnOpModeChangedListener> getPackageModeChangedListeners( 421 @NonNull String packageName) { 422 Objects.requireNonNull(packageName); 423 424 synchronized (mLock) { 425 ArraySet<OnOpModeChangedListener> modeChangedListenersSet = 426 mPackageModeWatchers.get(packageName); 427 if (modeChangedListenersSet == null) { 428 return new ArraySet<>(); 429 } 430 return new ArraySet<>(modeChangedListenersSet); 431 } 432 } 433 434 @Override notifyWatchersOfChange(int code, int uid)435 public void notifyWatchersOfChange(int code, int uid) { 436 ArraySet<OnOpModeChangedListener> listenerSet = getOpModeChangedListeners(code); 437 if (listenerSet == null) { 438 return; 439 } 440 for (int i = 0; i < listenerSet.size(); i++) { 441 final OnOpModeChangedListener listener = listenerSet.valueAt(i); 442 notifyOpChanged(listener, code, uid, null); 443 } 444 } 445 446 @Override notifyOpChanged(@onNull OnOpModeChangedListener onModeChangedListener, int code, int uid, @Nullable String packageName)447 public void notifyOpChanged(@NonNull OnOpModeChangedListener onModeChangedListener, int code, 448 int uid, @Nullable String packageName) { 449 Objects.requireNonNull(onModeChangedListener); 450 451 if (uid != UID_ANY && onModeChangedListener.getWatchingUid() >= 0 452 && onModeChangedListener.getWatchingUid() != uid) { 453 return; 454 } 455 456 // See CALL_BACK_ON_CHANGED_LISTENER_WITH_SWITCHED_OP_CHANGE 457 int[] switchedCodes; 458 if (onModeChangedListener.getWatchedOpCode() == ALL_OPS) { 459 switchedCodes = mSwitchedOps.get(code); 460 } else if (onModeChangedListener.getWatchedOpCode() == OP_NONE) { 461 switchedCodes = new int[]{code}; 462 } else { 463 switchedCodes = new int[]{onModeChangedListener.getWatchedOpCode()}; 464 } 465 466 for (int switchedCode : switchedCodes) { 467 // There are features watching for mode changes such as window manager 468 // and location manager which are in our process. The callbacks in these 469 // features may require permissions our remote caller does not have. 470 final long identity = Binder.clearCallingIdentity(); 471 try { 472 if (shouldIgnoreCallback(switchedCode, onModeChangedListener.getCallingPid(), 473 onModeChangedListener.getCallingUid())) { 474 continue; 475 } 476 onModeChangedListener.onOpModeChanged(switchedCode, uid, packageName); 477 } catch (RemoteException e) { 478 /* ignore */ 479 } finally { 480 Binder.restoreCallingIdentity(identity); 481 } 482 } 483 } 484 shouldIgnoreCallback(int op, int watcherPid, int watcherUid)485 private boolean shouldIgnoreCallback(int op, int watcherPid, int watcherUid) { 486 // If it's a restricted read op, ignore it if watcher doesn't have manage ops permission, 487 // as watcher should not use this to signal if the value is changed. 488 return opRestrictsRead(op) && mContext.checkPermission(Manifest.permission.MANAGE_APPOPS, 489 watcherPid, watcherUid) != PackageManager.PERMISSION_GRANTED; 490 } 491 492 @Override notifyOpChangedForAllPkgsInUid(int code, int uid, boolean onlyForeground, @Nullable OnOpModeChangedListener callbackToIgnore)493 public void notifyOpChangedForAllPkgsInUid(int code, int uid, boolean onlyForeground, 494 @Nullable OnOpModeChangedListener callbackToIgnore) { 495 String[] uidPackageNames = getPackagesForUid(uid); 496 ArrayMap<OnOpModeChangedListener, ArraySet<String>> callbackSpecs = null; 497 498 synchronized (mLock) { 499 ArraySet<OnOpModeChangedListener> callbacks = mOpModeWatchers.get(code); 500 if (callbacks != null) { 501 final int callbackCount = callbacks.size(); 502 for (int i = 0; i < callbackCount; i++) { 503 OnOpModeChangedListener callback = callbacks.valueAt(i); 504 505 if (onlyForeground && (callback.getFlags() 506 & WATCH_FOREGROUND_CHANGES) == 0) { 507 continue; 508 } 509 510 ArraySet<String> changedPackages = new ArraySet<>(); 511 Collections.addAll(changedPackages, uidPackageNames); 512 if (callbackSpecs == null) { 513 callbackSpecs = new ArrayMap<>(); 514 } 515 callbackSpecs.put(callback, changedPackages); 516 } 517 } 518 519 for (String uidPackageName : uidPackageNames) { 520 callbacks = mPackageModeWatchers.get(uidPackageName); 521 if (callbacks != null) { 522 if (callbackSpecs == null) { 523 callbackSpecs = new ArrayMap<>(); 524 } 525 final int callbackCount = callbacks.size(); 526 for (int i = 0; i < callbackCount; i++) { 527 OnOpModeChangedListener callback = callbacks.valueAt(i); 528 529 if (onlyForeground && (callback.getFlags() 530 & WATCH_FOREGROUND_CHANGES) == 0) { 531 continue; 532 } 533 534 ArraySet<String> changedPackages = callbackSpecs.get(callback); 535 if (changedPackages == null) { 536 changedPackages = new ArraySet<>(); 537 callbackSpecs.put(callback, changedPackages); 538 } 539 changedPackages.add(uidPackageName); 540 } 541 } 542 } 543 544 if (callbackSpecs != null && callbackToIgnore != null) { 545 callbackSpecs.remove(callbackToIgnore); 546 } 547 } 548 549 if (callbackSpecs == null) { 550 return; 551 } 552 553 for (int i = 0; i < callbackSpecs.size(); i++) { 554 final OnOpModeChangedListener callback = callbackSpecs.keyAt(i); 555 final ArraySet<String> reportedPackageNames = callbackSpecs.valueAt(i); 556 if (reportedPackageNames == null) { 557 mHandler.sendMessage(PooledLambda.obtainMessage( 558 AppOpsCheckingServiceImpl::notifyOpChanged, 559 this, callback, code, uid, (String) null)); 560 561 } else { 562 final int reportedPackageCount = reportedPackageNames.size(); 563 for (int j = 0; j < reportedPackageCount; j++) { 564 final String reportedPackageName = reportedPackageNames.valueAt(j); 565 mHandler.sendMessage(PooledLambda.obtainMessage( 566 AppOpsCheckingServiceImpl::notifyOpChanged, 567 this, callback, code, uid, reportedPackageName)); 568 } 569 } 570 } 571 } 572 getPackagesForUid(int uid)573 private static String[] getPackagesForUid(int uid) { 574 String[] packageNames = null; 575 576 // Very early during boot the package manager is not yet or not yet fully started. At this 577 // time there are no packages yet. 578 if (AppGlobals.getPackageManager() != null) { 579 try { 580 packageNames = AppGlobals.getPackageManager().getPackagesForUid(uid); 581 } catch (RemoteException e) { 582 /* ignore - local call */ 583 } 584 } 585 if (packageNames == null) { 586 return EmptyArray.STRING; 587 } 588 return packageNames; 589 } 590 591 @Override evalForegroundUidOps(int uid, SparseBooleanArray foregroundOps)592 public SparseBooleanArray evalForegroundUidOps(int uid, SparseBooleanArray foregroundOps) { 593 synchronized (mLock) { 594 return evalForegroundOps(mUidModes.get(uid), foregroundOps); 595 } 596 } 597 598 @Override evalForegroundPackageOps(String packageName, SparseBooleanArray foregroundOps, @UserIdInt int userId)599 public SparseBooleanArray evalForegroundPackageOps(String packageName, 600 SparseBooleanArray foregroundOps, @UserIdInt int userId) { 601 synchronized (mLock) { 602 ArrayMap<String, SparseIntArray> packageModes = mUserPackageModes.get(userId, null); 603 return evalForegroundOps(packageModes == null ? null : packageModes.get(packageName), 604 foregroundOps); 605 } 606 } 607 evalForegroundOps(SparseIntArray opModes, SparseBooleanArray foregroundOps)608 private SparseBooleanArray evalForegroundOps(SparseIntArray opModes, 609 SparseBooleanArray foregroundOps) { 610 SparseBooleanArray tempForegroundOps = foregroundOps; 611 if (opModes != null) { 612 for (int i = opModes.size() - 1; i >= 0; i--) { 613 if (opModes.valueAt(i) == AppOpsManager.MODE_FOREGROUND) { 614 if (tempForegroundOps == null) { 615 tempForegroundOps = new SparseBooleanArray(); 616 } 617 evalForegroundWatchers(opModes.keyAt(i), tempForegroundOps); 618 } 619 } 620 } 621 return tempForegroundOps; 622 } 623 evalForegroundWatchers(int op, SparseBooleanArray foregroundOps)624 private void evalForegroundWatchers(int op, SparseBooleanArray foregroundOps) { 625 boolean curValue = foregroundOps.get(op, false); 626 ArraySet<OnOpModeChangedListener> listenerSet = mOpModeWatchers.get(op); 627 if (listenerSet != null) { 628 for (int cbi = listenerSet.size() - 1; !curValue && cbi >= 0; cbi--) { 629 if ((listenerSet.valueAt(cbi).getFlags() 630 & AppOpsManager.WATCH_FOREGROUND_CHANGES) != 0) { 631 curValue = true; 632 } 633 } 634 } 635 foregroundOps.put(op, curValue); 636 } 637 638 @Override dumpListeners(int dumpOp, int dumpUid, String dumpPackage, PrintWriter printWriter)639 public boolean dumpListeners(int dumpOp, int dumpUid, String dumpPackage, 640 PrintWriter printWriter) { 641 boolean needSep = false; 642 if (mOpModeWatchers.size() > 0) { 643 boolean printedHeader = false; 644 for (int i = 0; i < mOpModeWatchers.size(); i++) { 645 if (dumpOp >= 0 && dumpOp != mOpModeWatchers.keyAt(i)) { 646 continue; 647 } 648 boolean printedOpHeader = false; 649 ArraySet<OnOpModeChangedListener> modeChangedListenerSet = 650 mOpModeWatchers.valueAt(i); 651 for (int j = 0; j < modeChangedListenerSet.size(); j++) { 652 final OnOpModeChangedListener listener = modeChangedListenerSet.valueAt(j); 653 if (dumpPackage != null 654 && dumpUid != UserHandle.getAppId(listener.getWatchingUid())) { 655 continue; 656 } 657 needSep = true; 658 if (!printedHeader) { 659 printWriter.println(" Op mode watchers:"); 660 printedHeader = true; 661 } 662 if (!printedOpHeader) { 663 printWriter.print(" Op "); 664 printWriter.print(AppOpsManager.opToName(mOpModeWatchers.keyAt(i))); 665 printWriter.println(":"); 666 printedOpHeader = true; 667 } 668 printWriter.print(" #"); printWriter.print(j); printWriter.print(": "); 669 printWriter.println(listener.toString()); 670 } 671 } 672 } 673 674 if (mPackageModeWatchers.size() > 0 && dumpOp < 0) { 675 boolean printedHeader = false; 676 for (int i = 0; i < mPackageModeWatchers.size(); i++) { 677 if (dumpPackage != null 678 && !dumpPackage.equals(mPackageModeWatchers.keyAt(i))) { 679 continue; 680 } 681 needSep = true; 682 if (!printedHeader) { 683 printWriter.println(" Package mode watchers:"); 684 printedHeader = true; 685 } 686 printWriter.print(" Pkg "); printWriter.print(mPackageModeWatchers.keyAt(i)); 687 printWriter.println(":"); 688 ArraySet<OnOpModeChangedListener> modeChangedListenerSet = 689 mPackageModeWatchers.valueAt(i); 690 691 for (int j = 0; j < modeChangedListenerSet.size(); j++) { 692 printWriter.print(" #"); printWriter.print(j); printWriter.print(": "); 693 printWriter.println(modeChangedListenerSet.valueAt(j).toString()); 694 } 695 } 696 } 697 return needSep; 698 } 699 scheduleWriteLocked()700 private void scheduleWriteLocked() { 701 if (!mWriteScheduled) { 702 mWriteScheduled = true; 703 mHandler.postDelayed(mWriteRunner, WRITE_DELAY); 704 } 705 } 706 scheduleFastWriteLocked()707 private void scheduleFastWriteLocked() { 708 if (!mFastWriteScheduled) { 709 mWriteScheduled = true; 710 mFastWriteScheduled = true; 711 mHandler.removeCallbacks(mWriteRunner); 712 mHandler.postDelayed(mWriteRunner, 10 * 1000); 713 } 714 } 715 716 @Override writeState()717 public void writeState() { 718 synchronized (mFile) { 719 FileOutputStream stream; 720 try { 721 stream = mFile.startWrite(); 722 } catch (IOException e) { 723 Slog.w(TAG, "Failed to write state: " + e); 724 return; 725 } 726 727 try { 728 TypedXmlSerializer out = Xml.resolveSerializer(stream); 729 out.startDocument(null, true); 730 out.startTag(null, "app-ops"); 731 out.attributeInt(null, "v", CURRENT_VERSION); 732 733 SparseArray<SparseIntArray> uidModesCopy = new SparseArray<>(); 734 SparseArray<ArrayMap<String, SparseIntArray>> userPackageModesCopy = 735 new SparseArray<>(); 736 int uidModesSize; 737 int usersSize; 738 synchronized (mLock) { 739 uidModesSize = mUidModes.size(); 740 for (int uidIdx = 0; uidIdx < uidModesSize; uidIdx++) { 741 int uid = mUidModes.keyAt(uidIdx); 742 SparseIntArray modes = mUidModes.valueAt(uidIdx); 743 uidModesCopy.put(uid, modes.clone()); 744 } 745 usersSize = mUserPackageModes.size(); 746 for (int userIdx = 0; userIdx < usersSize; userIdx++) { 747 int user = mUserPackageModes.keyAt(userIdx); 748 ArrayMap<String, SparseIntArray> packageModes = 749 mUserPackageModes.valueAt(userIdx); 750 ArrayMap<String, SparseIntArray> packageModesCopy = new ArrayMap<>(); 751 userPackageModesCopy.put(user, packageModesCopy); 752 for (int pkgIdx = 0, packageModesSize = packageModes.size(); 753 pkgIdx < packageModesSize; pkgIdx++) { 754 String pkg = packageModes.keyAt(pkgIdx); 755 SparseIntArray modes = packageModes.valueAt(pkgIdx); 756 packageModesCopy.put(pkg, modes.clone()); 757 } 758 } 759 } 760 761 for (int uidStateNum = 0; uidStateNum < uidModesSize; uidStateNum++) { 762 int uid = uidModesCopy.keyAt(uidStateNum); 763 SparseIntArray modes = uidModesCopy.valueAt(uidStateNum); 764 765 out.startTag(null, "uid"); 766 out.attributeInt(null, "n", uid); 767 768 final int modesSize = modes.size(); 769 for (int modeIdx = 0; modeIdx < modesSize; modeIdx++) { 770 final int op = modes.keyAt(modeIdx); 771 final int mode = modes.valueAt(modeIdx); 772 out.startTag(null, "op"); 773 out.attributeInt(null, "n", op); 774 out.attributeInt(null, "m", mode); 775 out.endTag(null, "op"); 776 } 777 out.endTag(null, "uid"); 778 } 779 780 for (int userIdx = 0; userIdx < usersSize; userIdx++) { 781 int userId = userPackageModesCopy.keyAt(userIdx); 782 ArrayMap<String, SparseIntArray> packageModes = 783 userPackageModesCopy.valueAt(userIdx); 784 785 out.startTag(null, "user"); 786 out.attributeInt(null, "n", userId); 787 788 int packageModesSize = packageModes.size(); 789 for (int pkgIdx = 0; pkgIdx < packageModesSize; pkgIdx++) { 790 String pkg = packageModes.keyAt(pkgIdx); 791 SparseIntArray modes = packageModes.valueAt(pkgIdx); 792 793 out.startTag(null, "pkg"); 794 out.attribute(null, "n", pkg); 795 796 final int modesSize = modes.size(); 797 for (int modeIdx = 0; modeIdx < modesSize; modeIdx++) { 798 final int op = modes.keyAt(modeIdx); 799 final int mode = modes.valueAt(modeIdx); 800 801 out.startTag(null, "op"); 802 out.attributeInt(null, "n", op); 803 out.attributeInt(null, "m", mode); 804 out.endTag(null, "op"); 805 } 806 out.endTag(null, "pkg"); 807 } 808 out.endTag(null, "user"); 809 } 810 811 out.endTag(null, "app-ops"); 812 out.endDocument(); 813 mFile.finishWrite(stream); 814 } catch (IOException e) { 815 Slog.w(TAG, "Failed to write state, restoring backup.", e); 816 mFile.failWrite(stream); 817 } 818 } 819 } 820 821 /* Current format 822 <uid> 823 <op> 824 </uid> 825 826 <user> 827 <pkg> 828 <op> 829 </pkg> 830 </user> 831 */ 832 833 @Override readState()834 public void readState() { 835 synchronized (mFile) { 836 synchronized (mLock) { 837 FileInputStream stream; 838 try { 839 stream = mFile.openRead(); 840 } catch (FileNotFoundException e) { 841 Slog.i(TAG, "No existing app ops " + mFile.getBaseFile() + "; starting empty"); 842 mVersionAtBoot = NO_FILE_VERSION; 843 return; 844 } 845 846 try { 847 TypedXmlPullParser parser = Xml.resolvePullParser(stream); 848 int type; 849 while ((type = parser.next()) != XmlPullParser.START_TAG 850 && type != XmlPullParser.END_DOCUMENT) { 851 // Parse next until we reach the start or end 852 } 853 854 if (type != XmlPullParser.START_TAG) { 855 throw new IllegalStateException("no start tag found"); 856 } 857 858 mVersionAtBoot = parser.getAttributeInt(null, "v", NO_VERSION); 859 860 int outerDepth = parser.getDepth(); 861 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 862 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 863 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 864 continue; 865 } 866 867 String tagName = parser.getName(); 868 if (tagName.equals("pkg")) { 869 // version 2 has the structure pkg -> uid -> op -> 870 // in version 3, since pkg and uid states are kept completely 871 // independent we switch to user -> pkg -> op 872 readPackage(parser); 873 } else if (tagName.equals("uid")) { 874 readUidOps(parser); 875 } else if (tagName.equals("user")) { 876 readUser(parser); 877 } else { 878 Slog.w(TAG, "Unknown element under <app-ops>: " 879 + parser.getName()); 880 XmlUtils.skipCurrentTag(parser); 881 } 882 } 883 return; 884 } catch (XmlPullParserException e) { 885 throw new RuntimeException(e); 886 } catch (IOException e) { 887 throw new RuntimeException(e); 888 } 889 } 890 } 891 } 892 893 @Override shutdown()894 public void shutdown() { 895 boolean doWrite = false; 896 synchronized (this) { 897 if (mWriteScheduled) { 898 mWriteScheduled = false; 899 mFastWriteScheduled = false; 900 mHandler.removeCallbacks(mWriteRunner); 901 doWrite = true; 902 } 903 } 904 if (doWrite) { 905 writeState(); 906 } 907 } 908 909 @GuardedBy("mLock") readUidOps(TypedXmlPullParser parser)910 private void readUidOps(TypedXmlPullParser parser) throws NumberFormatException, 911 XmlPullParserException, IOException { 912 final int uid = parser.getAttributeInt(null, "n"); 913 SparseIntArray modes = mUidModes.get(uid); 914 if (modes == null) { 915 modes = new SparseIntArray(); 916 mUidModes.put(uid, modes); 917 } 918 919 int outerDepth = parser.getDepth(); 920 int type; 921 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 922 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 923 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 924 continue; 925 } 926 927 String tagName = parser.getName(); 928 if (tagName.equals("op")) { 929 final int code = parser.getAttributeInt(null, "n"); 930 final int mode = parser.getAttributeInt(null, "m"); 931 932 if (mode != opToDefaultMode(code)) { 933 modes.put(code, mode); 934 } 935 } else { 936 Slog.w(TAG, "Unknown element under <uid>: " 937 + parser.getName()); 938 XmlUtils.skipCurrentTag(parser); 939 } 940 } 941 } 942 943 /* 944 * Used for migration when pkg is the depth=1 tag 945 */ 946 @GuardedBy("mLock") readPackage(TypedXmlPullParser parser)947 private void readPackage(TypedXmlPullParser parser) 948 throws NumberFormatException, XmlPullParserException, IOException { 949 String pkgName = parser.getAttributeValue(null, "n"); 950 int outerDepth = parser.getDepth(); 951 int type; 952 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 953 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 954 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 955 continue; 956 } 957 958 String tagName = parser.getName(); 959 if (tagName.equals("uid")) { 960 readUid(parser, pkgName); 961 } else { 962 Slog.w(TAG, "Unknown element under <pkg>: " 963 + parser.getName()); 964 XmlUtils.skipCurrentTag(parser); 965 } 966 } 967 } 968 969 /* 970 * Used for migration when uid is the depth=2 tag 971 */ 972 @GuardedBy("mLock") readUid(TypedXmlPullParser parser, String pkgName)973 private void readUid(TypedXmlPullParser parser, String pkgName) 974 throws NumberFormatException, XmlPullParserException, IOException { 975 int userId = UserHandle.getUserId(parser.getAttributeInt(null, "n")); 976 int outerDepth = parser.getDepth(); 977 int type; 978 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 979 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 980 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 981 continue; 982 } 983 984 String tagName = parser.getName(); 985 if (tagName.equals("op")) { 986 readOp(parser, userId, pkgName); 987 } else { 988 Slog.w(TAG, "Unknown element under <pkg>: " 989 + parser.getName()); 990 XmlUtils.skipCurrentTag(parser); 991 } 992 } 993 } 994 995 @GuardedBy("mLock") readUser(TypedXmlPullParser parser)996 private void readUser(TypedXmlPullParser parser) 997 throws NumberFormatException, XmlPullParserException, IOException { 998 int userId = parser.getAttributeInt(null, "n"); 999 int outerDepth = parser.getDepth(); 1000 int type; 1001 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 1002 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 1003 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 1004 continue; 1005 } 1006 1007 String tagName = parser.getName(); 1008 if (tagName.equals("pkg")) { 1009 readPackage(parser, userId); 1010 } else { 1011 Slog.w(TAG, "Unknown element under <user>: " 1012 + parser.getName()); 1013 XmlUtils.skipCurrentTag(parser); 1014 } 1015 } 1016 } 1017 1018 @GuardedBy("mLock") readPackage(TypedXmlPullParser parser, int userId)1019 private void readPackage(TypedXmlPullParser parser, int userId) 1020 throws NumberFormatException, XmlPullParserException, IOException { 1021 String pkgName = parser.getAttributeValue(null, "n"); 1022 int outerDepth = parser.getDepth(); 1023 int type; 1024 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 1025 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 1026 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 1027 continue; 1028 } 1029 1030 String tagName = parser.getName(); 1031 if (tagName.equals("op")) { 1032 readOp(parser, userId, pkgName); 1033 } else { 1034 Slog.w(TAG, "Unknown element under <pkg>: " 1035 + parser.getName()); 1036 XmlUtils.skipCurrentTag(parser); 1037 } 1038 } 1039 } 1040 1041 @GuardedBy("mLock") readOp(TypedXmlPullParser parser, int userId, @NonNull String pkgName)1042 private void readOp(TypedXmlPullParser parser, int userId, @NonNull String pkgName) 1043 throws NumberFormatException, XmlPullParserException { 1044 final int opCode = parser.getAttributeInt(null, "n"); 1045 final int defaultMode = AppOpsManager.opToDefaultMode(opCode); 1046 final int mode = parser.getAttributeInt(null, "m", defaultMode); 1047 1048 if (mode != defaultMode) { 1049 ArrayMap<String, SparseIntArray> packageModes = mUserPackageModes.get(userId); 1050 if (packageModes == null) { 1051 packageModes = new ArrayMap<>(); 1052 mUserPackageModes.put(userId, packageModes); 1053 } 1054 1055 SparseIntArray modes = packageModes.get(pkgName); 1056 if (modes == null) { 1057 modes = new SparseIntArray(); 1058 packageModes.put(pkgName, modes); 1059 } 1060 1061 modes.put(opCode, mode); 1062 } 1063 } 1064 1065 @GuardedBy("mLock") upgradeLocked(int oldVersion)1066 private void upgradeLocked(int oldVersion) { 1067 if (oldVersion == NO_FILE_VERSION || oldVersion >= CURRENT_VERSION) { 1068 return; 1069 } 1070 Slog.d(TAG, "Upgrading app-ops xml from version " + oldVersion + " to " + CURRENT_VERSION); 1071 switch (oldVersion) { 1072 case NO_VERSION: 1073 upgradeRunAnyInBackgroundLocked(); 1074 // fall through 1075 case 1: 1076 upgradeScheduleExactAlarmLocked(); 1077 // fall through 1078 case 2: 1079 // split the appops.xml into appops.xml to store appop state and apppops_access.xml 1080 // to store app-op access. 1081 // fall through 1082 case 3: 1083 resetUseFullScreenIntentLocked(); 1084 // fall through 1085 } 1086 scheduleFastWriteLocked(); 1087 } 1088 1089 /** 1090 * For all installed apps at time of upgrade, OP_RUN_ANY_IN_BACKGROUND will inherit the mode 1091 * from RUN_IN_BACKGROUND. 1092 */ 1093 @VisibleForTesting 1094 @GuardedBy("mLock") upgradeRunAnyInBackgroundLocked()1095 void upgradeRunAnyInBackgroundLocked() { 1096 final int uidModesSize = mUidModes.size(); 1097 for (int uidIdx = 0; uidIdx < uidModesSize; uidIdx++) { 1098 SparseIntArray modesForUid = mUidModes.valueAt(uidIdx); 1099 1100 final int idx = modesForUid.indexOfKey(AppOpsManager.OP_RUN_IN_BACKGROUND); 1101 if (idx >= 0) { 1102 // Only non-default should exist in the map 1103 modesForUid.put(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, modesForUid.valueAt(idx)); 1104 } 1105 } 1106 1107 final int usersSize = mUserPackageModes.size(); 1108 for (int userIdx = 0; userIdx < usersSize; userIdx++) { 1109 ArrayMap<String, SparseIntArray> packageModes = 1110 mUserPackageModes.valueAt(userIdx); 1111 1112 for (int pkgIdx = 0, packageModesSize = packageModes.size(); 1113 pkgIdx < packageModesSize; pkgIdx++) { 1114 SparseIntArray modes = packageModes.valueAt(pkgIdx); 1115 1116 final int idx = modes.indexOfKey(AppOpsManager.OP_RUN_IN_BACKGROUND); 1117 if (idx >= 0) { 1118 // Only non-default should exist in the map 1119 modes.put(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, modes.valueAt(idx)); 1120 } 1121 } 1122 } 1123 } 1124 1125 /** 1126 * The interpretation of the default mode - MODE_DEFAULT - for OP_SCHEDULE_EXACT_ALARM is 1127 * changing. Simultaneously, we want to change this op's mode from MODE_DEFAULT to MODE_ALLOWED 1128 * for already installed apps. For newer apps, it will stay as MODE_DEFAULT. 1129 */ 1130 @VisibleForTesting 1131 @GuardedBy("mLock") upgradeScheduleExactAlarmLocked()1132 void upgradeScheduleExactAlarmLocked() { 1133 final PermissionManagerServiceInternal pmsi = LocalServices.getService( 1134 PermissionManagerServiceInternal.class); 1135 final UserManagerInternal umi = LocalServices.getService(UserManagerInternal.class); 1136 final PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class); 1137 1138 final String[] packagesDeclaringPermission = pmsi.getAppOpPermissionPackages( 1139 AppOpsManager.opToPermission(OP_SCHEDULE_EXACT_ALARM)); 1140 final int[] userIds = umi.getUserIds(); 1141 1142 for (final String pkg : packagesDeclaringPermission) { 1143 for (int userId : userIds) { 1144 final int uid = pmi.getPackageUid(pkg, 0, userId); 1145 final int oldMode = getUidMode(uid, OP_SCHEDULE_EXACT_ALARM); 1146 if (oldMode == AppOpsManager.opToDefaultMode(OP_SCHEDULE_EXACT_ALARM)) { 1147 setUidMode(uid, OP_SCHEDULE_EXACT_ALARM, MODE_ALLOWED); 1148 } 1149 } 1150 // This appop is meant to be controlled at a uid level. So we leave package modes as 1151 // they are. 1152 } 1153 } 1154 1155 /** 1156 * A cleanup step for U Beta 2 that reverts the OP_USE_FULL_SCREEN_INTENT's mode to MODE_DEFAULT 1157 * if the permission flags for the USE_FULL_SCREEN_INTENT permission does not have USER_SET. 1158 */ 1159 @VisibleForTesting 1160 @GuardedBy("mLock") resetUseFullScreenIntentLocked()1161 void resetUseFullScreenIntentLocked() { 1162 final PermissionManagerServiceInternal pmsi = LocalServices.getService( 1163 PermissionManagerServiceInternal.class); 1164 final UserManagerInternal umi = LocalServices.getService(UserManagerInternal.class); 1165 final PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class); 1166 final PermissionManager permissionManager = 1167 mContext.getSystemService(PermissionManager.class); 1168 1169 final String permissionName = AppOpsManager.opToPermission(OP_USE_FULL_SCREEN_INTENT); 1170 final String[] packagesDeclaringPermission = 1171 pmsi.getAppOpPermissionPackages(permissionName); 1172 final int[] userIds = umi.getUserIds(); 1173 1174 for (final String pkg : packagesDeclaringPermission) { 1175 for (int userId : userIds) { 1176 final int uid = pmi.getPackageUid(pkg, 0, userId); 1177 final int flags = permissionManager.getPermissionFlags(pkg, permissionName, 1178 UserHandle.of(userId)); 1179 if ((flags & PackageManager.FLAG_PERMISSION_USER_SET) == 0) { 1180 setUidMode(uid, OP_USE_FULL_SCREEN_INTENT, 1181 AppOpsManager.opToDefaultMode(OP_USE_FULL_SCREEN_INTENT)); 1182 } 1183 } 1184 } 1185 } 1186 1187 @VisibleForTesting getUidsWithNonDefaultModes()1188 List<Integer> getUidsWithNonDefaultModes() { 1189 List<Integer> result = new ArrayList<>(); 1190 synchronized (mLock) { 1191 for (int i = 0; i < mUidModes.size(); i++) { 1192 SparseIntArray modes = mUidModes.valueAt(i); 1193 if (modes.size() > 0) { 1194 result.add(mUidModes.keyAt(i)); 1195 } 1196 } 1197 } 1198 1199 return result; 1200 } 1201 1202 @VisibleForTesting getPackagesWithNonDefaultModes()1203 List<UserPackage> getPackagesWithNonDefaultModes() { 1204 List<UserPackage> result = new ArrayList<>(); 1205 synchronized (mLock) { 1206 for (int i = 0; i < mUserPackageModes.size(); i++) { 1207 ArrayMap<String, SparseIntArray> packageModes = mUserPackageModes.valueAt(i); 1208 for (int j = 0; j < packageModes.size(); j++) { 1209 SparseIntArray modes = packageModes.valueAt(j); 1210 if (modes.size() > 0) { 1211 result.add( 1212 UserPackage.of(mUserPackageModes.keyAt(i), packageModes.keyAt(j))); 1213 } 1214 } 1215 } 1216 } 1217 1218 return result; 1219 } 1220 }