1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.appop; 18 19 import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_CAMERA; 20 import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION; 21 import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_MICROPHONE; 22 import static android.app.AppOpsManager.CALL_BACK_ON_SWITCHED_OP; 23 import static android.app.AppOpsManager.FILTER_BY_ATTRIBUTION_TAG; 24 import static android.app.AppOpsManager.FILTER_BY_OP_NAMES; 25 import static android.app.AppOpsManager.FILTER_BY_PACKAGE_NAME; 26 import static android.app.AppOpsManager.FILTER_BY_UID; 27 import static android.app.AppOpsManager.HistoricalOpsRequestFilter; 28 import static android.app.AppOpsManager.KEY_BG_STATE_SETTLE_TIME; 29 import static android.app.AppOpsManager.KEY_FG_SERVICE_STATE_SETTLE_TIME; 30 import static android.app.AppOpsManager.KEY_TOP_STATE_SETTLE_TIME; 31 import static android.app.AppOpsManager.MODE_ALLOWED; 32 import static android.app.AppOpsManager.MODE_FOREGROUND; 33 import static android.app.AppOpsManager.MODE_IGNORED; 34 import static android.app.AppOpsManager.NoteOpEvent; 35 import static android.app.AppOpsManager.OP_CAMERA; 36 import static android.app.AppOpsManager.OP_FLAGS_ALL; 37 import static android.app.AppOpsManager.OP_FLAG_SELF; 38 import static android.app.AppOpsManager.OP_FLAG_TRUSTED_PROXIED; 39 import static android.app.AppOpsManager.OP_NONE; 40 import static android.app.AppOpsManager.OP_PLAY_AUDIO; 41 import static android.app.AppOpsManager.OP_RECORD_AUDIO; 42 import static android.app.AppOpsManager.OpEventProxyInfo; 43 import static android.app.AppOpsManager.RestrictionBypass; 44 import static android.app.AppOpsManager.SAMPLING_STRATEGY_BOOT_TIME_SAMPLING; 45 import static android.app.AppOpsManager.SAMPLING_STRATEGY_RARELY_USED; 46 import static android.app.AppOpsManager.SAMPLING_STRATEGY_UNIFORM; 47 import static android.app.AppOpsManager.UID_STATE_BACKGROUND; 48 import static android.app.AppOpsManager.UID_STATE_CACHED; 49 import static android.app.AppOpsManager.UID_STATE_FOREGROUND; 50 import static android.app.AppOpsManager.UID_STATE_FOREGROUND_SERVICE; 51 import static android.app.AppOpsManager.UID_STATE_MAX_LAST_NON_RESTRICTED; 52 import static android.app.AppOpsManager.UID_STATE_PERSISTENT; 53 import static android.app.AppOpsManager.UID_STATE_TOP; 54 import static android.app.AppOpsManager.WATCH_FOREGROUND_CHANGES; 55 import static android.app.AppOpsManager._NUM_OP; 56 import static android.app.AppOpsManager.extractFlagsFromKey; 57 import static android.app.AppOpsManager.extractUidStateFromKey; 58 import static android.app.AppOpsManager.makeKey; 59 import static android.app.AppOpsManager.modeToName; 60 import static android.app.AppOpsManager.opAllowSystemBypassRestriction; 61 import static android.app.AppOpsManager.opToName; 62 import static android.app.AppOpsManager.opToPublicName; 63 import static android.app.AppOpsManager.resolveFirstUnrestrictedUidState; 64 import static android.content.Intent.ACTION_PACKAGE_REMOVED; 65 import static android.content.Intent.EXTRA_REPLACING; 66 import static android.content.pm.PermissionInfo.PROTECTION_DANGEROUS; 67 import static android.content.pm.PermissionInfo.PROTECTION_FLAG_APPOP; 68 69 import static com.android.server.appop.AppOpsService.ModeCallback.ALL_OPS; 70 71 import static java.lang.Long.max; 72 73 import android.Manifest; 74 import android.annotation.IntRange; 75 import android.annotation.NonNull; 76 import android.annotation.Nullable; 77 import android.app.ActivityManager; 78 import android.app.ActivityManagerInternal; 79 import android.app.AppGlobals; 80 import android.app.AppOpsManager; 81 import android.app.AppOpsManager.AttributedOpEntry; 82 import android.app.AppOpsManager.HistoricalOps; 83 import android.app.AppOpsManager.Mode; 84 import android.app.AppOpsManager.OpEntry; 85 import android.app.AppOpsManager.OpFlags; 86 import android.app.AppOpsManagerInternal; 87 import android.app.AppOpsManagerInternal.CheckOpsDelegate; 88 import android.app.AsyncNotedAppOp; 89 import android.app.RuntimeAppOpAccessMessage; 90 import android.app.SyncNotedAppOp; 91 import android.content.BroadcastReceiver; 92 import android.content.ContentResolver; 93 import android.content.Context; 94 import android.content.Intent; 95 import android.content.IntentFilter; 96 import android.content.pm.PackageInfo; 97 import android.content.pm.PackageManager; 98 import android.content.pm.PackageManagerInternal; 99 import android.content.pm.PermissionInfo; 100 import android.content.pm.UserInfo; 101 import android.content.pm.parsing.component.ParsedAttribution; 102 import android.database.ContentObserver; 103 import android.hardware.camera2.CameraDevice.CAMERA_AUDIO_RESTRICTION; 104 import android.net.Uri; 105 import android.os.AsyncTask; 106 import android.os.Binder; 107 import android.os.Build; 108 import android.os.Bundle; 109 import android.os.Handler; 110 import android.os.IBinder; 111 import android.os.Process; 112 import android.os.RemoteCallback; 113 import android.os.RemoteCallbackList; 114 import android.os.RemoteException; 115 import android.os.ResultReceiver; 116 import android.os.ServiceManager; 117 import android.os.ShellCallback; 118 import android.os.ShellCommand; 119 import android.os.SystemClock; 120 import android.os.UserHandle; 121 import android.os.UserManager; 122 import android.os.storage.StorageManager; 123 import android.os.storage.StorageManagerInternal; 124 import android.provider.Settings; 125 import android.util.ArrayMap; 126 import android.util.ArraySet; 127 import android.util.AtomicFile; 128 import android.util.KeyValueListParser; 129 import android.util.LongSparseArray; 130 import android.util.Pair; 131 import android.util.Pools.SimplePool; 132 import android.util.Slog; 133 import android.util.SparseArray; 134 import android.util.SparseBooleanArray; 135 import android.util.SparseIntArray; 136 import android.util.TimeUtils; 137 import android.util.Xml; 138 139 import com.android.internal.annotations.GuardedBy; 140 import com.android.internal.annotations.Immutable; 141 import com.android.internal.annotations.VisibleForTesting; 142 import com.android.internal.app.IAppOpsActiveCallback; 143 import com.android.internal.app.IAppOpsAsyncNotedCallback; 144 import com.android.internal.app.IAppOpsCallback; 145 import com.android.internal.app.IAppOpsNotedCallback; 146 import com.android.internal.app.IAppOpsService; 147 import com.android.internal.app.IAppOpsStartedCallback; 148 import com.android.internal.app.MessageSamplingConfig; 149 import com.android.internal.os.Zygote; 150 import com.android.internal.util.ArrayUtils; 151 import com.android.internal.util.DumpUtils; 152 import com.android.internal.util.FastXmlSerializer; 153 import com.android.internal.util.Preconditions; 154 import com.android.internal.util.XmlUtils; 155 import com.android.internal.util.function.pooled.PooledLambda; 156 import com.android.server.LocalServices; 157 import com.android.server.LockGuard; 158 import com.android.server.SystemServerInitThreadPool; 159 import com.android.server.SystemServiceManager; 160 import com.android.server.pm.PackageList; 161 import com.android.server.pm.parsing.pkg.AndroidPackage; 162 163 import libcore.util.EmptyArray; 164 165 import org.json.JSONException; 166 import org.json.JSONObject; 167 import org.xmlpull.v1.XmlPullParser; 168 import org.xmlpull.v1.XmlPullParserException; 169 import org.xmlpull.v1.XmlSerializer; 170 171 import java.io.File; 172 import java.io.FileDescriptor; 173 import java.io.FileInputStream; 174 import java.io.FileNotFoundException; 175 import java.io.FileOutputStream; 176 import java.io.FileWriter; 177 import java.io.IOException; 178 import java.io.PrintWriter; 179 import java.nio.charset.StandardCharsets; 180 import java.text.SimpleDateFormat; 181 import java.time.Instant; 182 import java.time.temporal.ChronoUnit; 183 import java.util.ArrayList; 184 import java.util.Arrays; 185 import java.util.Collections; 186 import java.util.Date; 187 import java.util.HashMap; 188 import java.util.Iterator; 189 import java.util.List; 190 import java.util.Map; 191 import java.util.Objects; 192 import java.util.Scanner; 193 import java.util.concurrent.ThreadLocalRandom; 194 import java.util.function.Consumer; 195 196 public class AppOpsService extends IAppOpsService.Stub { 197 static final String TAG = "AppOps"; 198 static final boolean DEBUG = false; 199 200 /** 201 * Used for data access validation collection, we wish to only log a specific access once 202 */ 203 private final ArraySet<NoteOpTrace> mNoteOpCallerStacktraces = new ArraySet<>(); 204 205 private static final int NO_VERSION = -1; 206 /** Increment by one every time and add the corresponding upgrade logic in 207 * {@link #upgradeLocked(int)} below. The first version was 1 */ 208 private static final int CURRENT_VERSION = 1; 209 210 // Write at most every 30 minutes. 211 static final long WRITE_DELAY = DEBUG ? 1000 : 30*60*1000; 212 213 // Constant meaning that any UID should be matched when dispatching callbacks 214 private static final int UID_ANY = -2; 215 216 // Map from process states to the uid states we track. 217 private static final int[] PROCESS_STATE_TO_UID_STATE = new int[] { 218 UID_STATE_PERSISTENT, // ActivityManager.PROCESS_STATE_PERSISTENT 219 UID_STATE_PERSISTENT, // ActivityManager.PROCESS_STATE_PERSISTENT_UI 220 UID_STATE_TOP, // ActivityManager.PROCESS_STATE_TOP 221 UID_STATE_FOREGROUND, // ActivityManager.PROCESS_STATE_BOUND_TOP 222 UID_STATE_FOREGROUND_SERVICE, // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE 223 UID_STATE_FOREGROUND, // ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE 224 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND 225 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND 226 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND 227 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_BACKUP 228 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_SERVICE 229 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_RECEIVER 230 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_TOP_SLEEPING 231 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT 232 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_HOME 233 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_LAST_ACTIVITY 234 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY 235 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT 236 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_CACHED_RECENT 237 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_CACHED_EMPTY 238 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_NONEXISTENT 239 }; 240 241 private static final int[] OPS_RESTRICTED_ON_SUSPEND = { 242 OP_PLAY_AUDIO, 243 OP_RECORD_AUDIO, 244 OP_CAMERA, 245 }; 246 247 private static final int MAX_UNFORWARDED_OPS = 10; 248 private static final int MAX_UNUSED_POOLED_OBJECTS = 3; 249 private static final int RARELY_USED_PACKAGES_INITIALIZATION_DELAY_MILLIS = 300000; 250 251 //TODO: remove this when development is done. 252 private static final int DEBUG_FGS_ALLOW_WHILE_IN_USE = 0; 253 private static final int DEBUG_FGS_ENFORCE_TYPE = 1; 254 255 256 final Context mContext; 257 final AtomicFile mFile; 258 private final @Nullable File mNoteOpCallerStacktracesFile; 259 final Handler mHandler; 260 261 /** Pool for {@link OpEventProxyInfoPool} to avoid to constantly reallocate new objects */ 262 @GuardedBy("this") 263 private final OpEventProxyInfoPool mOpEventProxyInfoPool = new OpEventProxyInfoPool(); 264 265 /** Pool for {@link InProgressStartOpEventPool} to avoid to constantly reallocate new objects */ 266 @GuardedBy("this") 267 private final InProgressStartOpEventPool mInProgressStartOpEventPool = 268 new InProgressStartOpEventPool(); 269 270 private final AppOpsManagerInternalImpl mAppOpsManagerInternal 271 = new AppOpsManagerInternalImpl(); 272 273 /** 274 * Registered callbacks, called from {@link #collectAsyncNotedOp}. 275 * 276 * <p>(package name, uid) -> callbacks 277 * 278 * @see #getAsyncNotedOpsKey(String, int) 279 */ 280 @GuardedBy("this") 281 private final ArrayMap<Pair<String, Integer>, RemoteCallbackList<IAppOpsAsyncNotedCallback>> 282 mAsyncOpWatchers = new ArrayMap<>(); 283 284 /** 285 * Async note-ops collected from {@link #collectAsyncNotedOp} that have not been delivered to a 286 * callback yet. 287 * 288 * <p>(package name, uid) -> list<ops> 289 * 290 * @see #getAsyncNotedOpsKey(String, int) 291 */ 292 @GuardedBy("this") 293 private final ArrayMap<Pair<String, Integer>, ArrayList<AsyncNotedAppOp>> 294 mUnforwardedAsyncNotedOps = new ArrayMap<>(); 295 296 boolean mWriteNoteOpsScheduled; 297 298 boolean mWriteScheduled; 299 boolean mFastWriteScheduled; 300 final Runnable mWriteRunner = new Runnable() { 301 public void run() { 302 synchronized (AppOpsService.this) { 303 mWriteScheduled = false; 304 mFastWriteScheduled = false; 305 AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() { 306 @Override protected Void doInBackground(Void... params) { 307 writeState(); 308 return null; 309 } 310 }; 311 task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[])null); 312 } 313 } 314 }; 315 316 @GuardedBy("this") 317 @VisibleForTesting 318 final SparseArray<UidState> mUidStates = new SparseArray<>(); 319 320 volatile @NonNull HistoricalRegistry mHistoricalRegistry = new HistoricalRegistry(this); 321 322 long mLastRealtime; 323 324 /* 325 * These are app op restrictions imposed per user from various parties. 326 */ 327 private final ArrayMap<IBinder, ClientRestrictionState> mOpUserRestrictions = new ArrayMap<>(); 328 329 SparseIntArray mProfileOwners; 330 331 @GuardedBy("this") 332 private CheckOpsDelegate mCheckOpsDelegate; 333 334 /** 335 * Reverse lookup for {@link AppOpsManager#opToSwitch(int)}. Initialized once and never 336 * changed 337 */ 338 private final SparseArray<int[]> mSwitchedOps = new SparseArray<>(); 339 340 private ActivityManagerInternal mActivityManagerInternal; 341 342 /** Package sampled for message collection in the current session */ 343 @GuardedBy("this") 344 private String mSampledPackage = null; 345 346 /** Appop sampled for message collection in the current session */ 347 @GuardedBy("this") 348 private int mSampledAppOpCode = OP_NONE; 349 350 /** Maximum distance for appop to be considered for message collection in the current session */ 351 @GuardedBy("this") 352 private int mAcceptableLeftDistance = 0; 353 354 /** Number of messages collected for sampled package and appop in the current session */ 355 @GuardedBy("this") 356 private float mMessagesCollectedCount; 357 358 /** List of rarely used packages priorities for message collection */ 359 @GuardedBy("this") 360 private ArraySet<String> mRarelyUsedPackages = new ArraySet<>(); 361 362 /** Sampling strategy used for current session */ 363 @GuardedBy("this") 364 @AppOpsManager.SamplingStrategy 365 private int mSamplingStrategy; 366 367 /** Last runtime permission access message collected and ready for reporting */ 368 @GuardedBy("this") 369 private RuntimeAppOpAccessMessage mCollectedRuntimePermissionMessage; 370 /** 371 * An unsynchronized pool of {@link OpEventProxyInfo} objects. 372 */ 373 private class OpEventProxyInfoPool extends SimplePool<OpEventProxyInfo> { OpEventProxyInfoPool()374 OpEventProxyInfoPool() { 375 super(MAX_UNUSED_POOLED_OBJECTS); 376 } 377 acquire(@ntRangefrom = 0) int uid, @Nullable String packageName, @Nullable String attributionTag)378 OpEventProxyInfo acquire(@IntRange(from = 0) int uid, @Nullable String packageName, 379 @Nullable String attributionTag) { 380 OpEventProxyInfo recycled = acquire(); 381 if (recycled != null) { 382 recycled.reinit(uid, packageName, attributionTag); 383 return recycled; 384 } 385 386 return new OpEventProxyInfo(uid, packageName, attributionTag); 387 } 388 } 389 390 /** 391 * An unsynchronized pool of {@link InProgressStartOpEvent} objects. 392 */ 393 private class InProgressStartOpEventPool extends SimplePool<InProgressStartOpEvent> { InProgressStartOpEventPool()394 InProgressStartOpEventPool() { 395 super(MAX_UNUSED_POOLED_OBJECTS); 396 } 397 acquire(long startTime, long elapsedTime, @NonNull IBinder clientId, @NonNull Runnable onDeath, int uidState)398 InProgressStartOpEvent acquire(long startTime, long elapsedTime, @NonNull IBinder clientId, 399 @NonNull Runnable onDeath, int uidState) throws RemoteException { 400 InProgressStartOpEvent recycled = acquire(); 401 if (recycled != null) { 402 recycled.reinit(startTime, elapsedTime, clientId, onDeath, uidState); 403 return recycled; 404 } 405 406 return new InProgressStartOpEvent(startTime, elapsedTime, clientId, onDeath, uidState); 407 } 408 } 409 410 /** 411 * All times are in milliseconds. These constants are kept synchronized with the system 412 * global Settings. Any access to this class or its fields should be done while 413 * holding the AppOpsService lock. 414 */ 415 @VisibleForTesting 416 final class Constants extends ContentObserver { 417 418 /** 419 * How long we want for a drop in uid state from top to settle before applying it. 420 * @see Settings.Global#APP_OPS_CONSTANTS 421 * @see AppOpsManager#KEY_TOP_STATE_SETTLE_TIME 422 */ 423 public long TOP_STATE_SETTLE_TIME; 424 425 /** 426 * How long we want for a drop in uid state from foreground to settle before applying it. 427 * @see Settings.Global#APP_OPS_CONSTANTS 428 * @see AppOpsManager#KEY_FG_SERVICE_STATE_SETTLE_TIME 429 */ 430 public long FG_SERVICE_STATE_SETTLE_TIME; 431 432 /** 433 * How long we want for a drop in uid state from background to settle before applying it. 434 * @see Settings.Global#APP_OPS_CONSTANTS 435 * @see AppOpsManager#KEY_BG_STATE_SETTLE_TIME 436 */ 437 public long BG_STATE_SETTLE_TIME; 438 439 private final KeyValueListParser mParser = new KeyValueListParser(','); 440 private ContentResolver mResolver; 441 Constants(Handler handler)442 public Constants(Handler handler) { 443 super(handler); 444 updateConstants(); 445 } 446 startMonitoring(ContentResolver resolver)447 public void startMonitoring(ContentResolver resolver) { 448 mResolver = resolver; 449 mResolver.registerContentObserver( 450 Settings.Global.getUriFor(Settings.Global.APP_OPS_CONSTANTS), 451 false, this); 452 updateConstants(); 453 } 454 455 @Override onChange(boolean selfChange, Uri uri)456 public void onChange(boolean selfChange, Uri uri) { 457 updateConstants(); 458 } 459 updateConstants()460 private void updateConstants() { 461 String value = mResolver != null ? Settings.Global.getString(mResolver, 462 Settings.Global.APP_OPS_CONSTANTS) : ""; 463 464 synchronized (AppOpsService.this) { 465 try { 466 mParser.setString(value); 467 } catch (IllegalArgumentException e) { 468 // Failed to parse the settings string, log this and move on 469 // with defaults. 470 Slog.e(TAG, "Bad app ops settings", e); 471 } 472 TOP_STATE_SETTLE_TIME = mParser.getDurationMillis( 473 KEY_TOP_STATE_SETTLE_TIME, 5 * 1000L); 474 FG_SERVICE_STATE_SETTLE_TIME = mParser.getDurationMillis( 475 KEY_FG_SERVICE_STATE_SETTLE_TIME, 5 * 1000L); 476 BG_STATE_SETTLE_TIME = mParser.getDurationMillis( 477 KEY_BG_STATE_SETTLE_TIME, 1 * 1000L); 478 } 479 } 480 dump(PrintWriter pw)481 void dump(PrintWriter pw) { 482 pw.println(" Settings:"); 483 484 pw.print(" "); pw.print(KEY_TOP_STATE_SETTLE_TIME); pw.print("="); 485 TimeUtils.formatDuration(TOP_STATE_SETTLE_TIME, pw); 486 pw.println(); 487 pw.print(" "); pw.print(KEY_FG_SERVICE_STATE_SETTLE_TIME); pw.print("="); 488 TimeUtils.formatDuration(FG_SERVICE_STATE_SETTLE_TIME, pw); 489 pw.println(); 490 pw.print(" "); pw.print(KEY_BG_STATE_SETTLE_TIME); pw.print("="); 491 TimeUtils.formatDuration(BG_STATE_SETTLE_TIME, pw); 492 pw.println(); 493 } 494 } 495 496 @VisibleForTesting 497 final Constants mConstants; 498 499 @VisibleForTesting 500 final class UidState { 501 public final int uid; 502 503 public int state = UID_STATE_CACHED; 504 public int pendingState = UID_STATE_CACHED; 505 public long pendingStateCommitTime; 506 public int capability; 507 public int pendingCapability; 508 public boolean appWidgetVisible; 509 public boolean pendingAppWidgetVisible; 510 511 public ArrayMap<String, Ops> pkgOps; 512 public SparseIntArray opModes; 513 514 // true indicates there is an interested observer, false there isn't but it has such an op 515 public SparseBooleanArray foregroundOps; 516 public boolean hasForegroundWatchers; 517 UidState(int uid)518 public UidState(int uid) { 519 this.uid = uid; 520 } 521 clear()522 public void clear() { 523 pkgOps = null; 524 opModes = null; 525 } 526 isDefault()527 public boolean isDefault() { 528 return (pkgOps == null || pkgOps.isEmpty()) 529 && (opModes == null || opModes.size() <= 0) 530 && (state == UID_STATE_CACHED 531 && (pendingState == UID_STATE_CACHED)); 532 } 533 evalMode(int op, int mode)534 int evalMode(int op, int mode) { 535 if (mode == MODE_FOREGROUND) { 536 if (appWidgetVisible) { 537 return MODE_ALLOWED; 538 } else if (mActivityManagerInternal != null 539 && mActivityManagerInternal.isPendingTopUid(uid)) { 540 return MODE_ALLOWED; 541 } else if (state <= UID_STATE_TOP) { 542 // process is in TOP. 543 return MODE_ALLOWED; 544 } else if (state <= AppOpsManager.resolveFirstUnrestrictedUidState(op)) { 545 // process is in foreground, check its capability. 546 switch (op) { 547 case AppOpsManager.OP_FINE_LOCATION: 548 case AppOpsManager.OP_COARSE_LOCATION: 549 case AppOpsManager.OP_MONITOR_LOCATION: 550 case AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION: 551 if ((capability & PROCESS_CAPABILITY_FOREGROUND_LOCATION) != 0) { 552 return MODE_ALLOWED; 553 } else { 554 return MODE_IGNORED; 555 } 556 case OP_CAMERA: 557 if ((capability & PROCESS_CAPABILITY_FOREGROUND_CAMERA) != 0) { 558 return MODE_ALLOWED; 559 } else { 560 return MODE_IGNORED; 561 } 562 case OP_RECORD_AUDIO: 563 if ((capability & PROCESS_CAPABILITY_FOREGROUND_MICROPHONE) != 0) { 564 return MODE_ALLOWED; 565 } else { 566 return MODE_IGNORED; 567 } 568 default: 569 return MODE_ALLOWED; 570 } 571 } else { 572 // process is not in foreground. 573 return MODE_IGNORED; 574 } 575 } else if (mode == MODE_ALLOWED) { 576 switch (op) { 577 case OP_CAMERA: 578 if (mActivityManagerInternal != null 579 && mActivityManagerInternal.isPendingTopUid(uid)) { 580 return MODE_ALLOWED; 581 } else if ((capability & PROCESS_CAPABILITY_FOREGROUND_CAMERA) != 0) { 582 return MODE_ALLOWED; 583 } else { 584 return MODE_IGNORED; 585 } 586 case OP_RECORD_AUDIO: 587 if (mActivityManagerInternal != null 588 && mActivityManagerInternal.isPendingTopUid(uid)) { 589 return MODE_ALLOWED; 590 } else if ((capability & PROCESS_CAPABILITY_FOREGROUND_MICROPHONE) != 0) { 591 return MODE_ALLOWED; 592 } else { 593 return MODE_IGNORED; 594 } 595 default: 596 return MODE_ALLOWED; 597 } 598 } 599 return mode; 600 } 601 evalForegroundWatchers(int op, SparseArray<ArraySet<ModeCallback>> watchers, SparseBooleanArray which)602 private void evalForegroundWatchers(int op, SparseArray<ArraySet<ModeCallback>> watchers, 603 SparseBooleanArray which) { 604 boolean curValue = which.get(op, false); 605 ArraySet<ModeCallback> callbacks = watchers.get(op); 606 if (callbacks != null) { 607 for (int cbi = callbacks.size() - 1; !curValue && cbi >= 0; cbi--) { 608 if ((callbacks.valueAt(cbi).mFlags 609 & AppOpsManager.WATCH_FOREGROUND_CHANGES) != 0) { 610 hasForegroundWatchers = true; 611 curValue = true; 612 } 613 } 614 } 615 which.put(op, curValue); 616 } 617 evalForegroundOps(SparseArray<ArraySet<ModeCallback>> watchers)618 public void evalForegroundOps(SparseArray<ArraySet<ModeCallback>> watchers) { 619 SparseBooleanArray which = null; 620 hasForegroundWatchers = false; 621 if (opModes != null) { 622 for (int i = opModes.size() - 1; i >= 0; i--) { 623 if (opModes.valueAt(i) == AppOpsManager.MODE_FOREGROUND) { 624 if (which == null) { 625 which = new SparseBooleanArray(); 626 } 627 evalForegroundWatchers(opModes.keyAt(i), watchers, which); 628 } 629 } 630 } 631 if (pkgOps != null) { 632 for (int i = pkgOps.size() - 1; i >= 0; i--) { 633 Ops ops = pkgOps.valueAt(i); 634 for (int j = ops.size() - 1; j >= 0; j--) { 635 if (ops.valueAt(j).mode == AppOpsManager.MODE_FOREGROUND) { 636 if (which == null) { 637 which = new SparseBooleanArray(); 638 } 639 evalForegroundWatchers(ops.keyAt(j), watchers, which); 640 } 641 } 642 } 643 } 644 foregroundOps = which; 645 } 646 } 647 648 final static class Ops extends SparseArray<Op> { 649 final String packageName; 650 final UidState uidState; 651 652 /** 653 * The restriction properties of the package. If {@code null} it could not have been read 654 * yet and has to be refreshed. 655 */ 656 @Nullable RestrictionBypass bypass; 657 658 /** Lazily populated cache of attributionTags of this package */ 659 final @NonNull ArraySet<String> knownAttributionTags = new ArraySet<>(); 660 Ops(String _packageName, UidState _uidState)661 Ops(String _packageName, UidState _uidState) { 662 packageName = _packageName; 663 uidState = _uidState; 664 } 665 } 666 667 /** A in progress startOp->finishOp event */ 668 private static final class InProgressStartOpEvent implements IBinder.DeathRecipient { 669 /** Wall clock time of startOp event (not monotonic) */ 670 private long mStartTime; 671 672 /** Elapsed time since boot of startOp event */ 673 private long mStartElapsedTime; 674 675 /** Id of the client that started the event */ 676 private @NonNull IBinder mClientId; 677 678 /** To call when client dies */ 679 private @NonNull Runnable mOnDeath; 680 681 /** uidstate used when calling startOp */ 682 private @AppOpsManager.UidState int mUidState; 683 684 /** How many times the op was started but not finished yet */ 685 int numUnfinishedStarts; 686 687 /** 688 * Create a new {@link InProgressStartOpEvent}. 689 * 690 * @param startTime The time {@link #startOperation} was called 691 * @param startElapsedTime The elapsed time when {@link #startOperation} was called 692 * @param clientId The client id of the caller of {@link #startOperation} 693 * @param onDeath The code to execute on client death 694 * @param uidState The uidstate of the app {@link #startOperation} was called for 695 * 696 * @throws RemoteException If the client is dying 697 */ InProgressStartOpEvent(long startTime, long startElapsedTime, @NonNull IBinder clientId, @NonNull Runnable onDeath, int uidState)698 private InProgressStartOpEvent(long startTime, long startElapsedTime, 699 @NonNull IBinder clientId, @NonNull Runnable onDeath, int uidState) 700 throws RemoteException { 701 mStartTime = startTime; 702 mStartElapsedTime = startElapsedTime; 703 mClientId = clientId; 704 mOnDeath = onDeath; 705 mUidState = uidState; 706 707 clientId.linkToDeath(this, 0); 708 } 709 710 /** Clean up event */ finish()711 public void finish() { 712 mClientId.unlinkToDeath(this, 0); 713 } 714 715 @Override binderDied()716 public void binderDied() { 717 mOnDeath.run(); 718 } 719 720 /** 721 * Reinit existing object with new state. 722 * 723 * @param startTime The time {@link #startOperation} was called 724 * @param startElapsedTime The elapsed time when {@link #startOperation} was called 725 * @param clientId The client id of the caller of {@link #startOperation} 726 * @param onDeath The code to execute on client death 727 * @param uidState The uidstate of the app {@link #startOperation} was called for 728 * 729 * @throws RemoteException If the client is dying 730 */ reinit(long startTime, long startElapsedTime, @NonNull IBinder clientId, @NonNull Runnable onDeath, int uidState)731 public void reinit(long startTime, long startElapsedTime, @NonNull IBinder clientId, 732 @NonNull Runnable onDeath, int uidState) throws RemoteException { 733 mStartTime = startTime; 734 mStartElapsedTime = startElapsedTime; 735 mClientId = clientId; 736 mOnDeath = onDeath; 737 mUidState = uidState; 738 739 clientId.linkToDeath(this, 0); 740 } 741 742 /** @return Wall clock time of startOp event */ getStartTime()743 public long getStartTime() { 744 return mStartTime; 745 } 746 747 /** @return Elapsed time since boot of startOp event */ getStartElapsedTime()748 public long getStartElapsedTime() { 749 return mStartElapsedTime; 750 } 751 752 /** @return Id of the client that started the event */ getClientId()753 public @NonNull IBinder getClientId() { 754 return mClientId; 755 } 756 757 /** @return uidstate used when calling startOp */ getUidState()758 public int getUidState() { 759 return mUidState; 760 } 761 } 762 763 private final class AttributedOp { 764 public final @Nullable String tag; 765 public final @NonNull Op parent; 766 767 /** 768 * Last successful accesses (noteOp + finished startOp) for each uidState/opFlag combination 769 * 770 * <p>Key is {@link AppOpsManager#makeKey} 771 */ 772 @GuardedBy("AppOpsService.this") 773 private @Nullable LongSparseArray<NoteOpEvent> mAccessEvents; 774 775 /** 776 * Last rejected accesses for each uidState/opFlag combination 777 * 778 * <p>Key is {@link AppOpsManager#makeKey} 779 */ 780 @GuardedBy("AppOpsService.this") 781 private @Nullable LongSparseArray<NoteOpEvent> mRejectEvents; 782 783 /** 784 * Currently in progress startOp events 785 * 786 * <p>Key is clientId 787 */ 788 @GuardedBy("AppOpsService.this") 789 private @Nullable ArrayMap<IBinder, InProgressStartOpEvent> mInProgressEvents; 790 AttributedOp(@ullable String tag, @NonNull Op parent)791 AttributedOp(@Nullable String tag, @NonNull Op parent) { 792 this.tag = tag; 793 this.parent = parent; 794 } 795 796 /** 797 * Update state when noteOp was rejected or startOp->finishOp event finished 798 * 799 * @param proxyUid The uid of the proxy 800 * @param proxyPackageName The package name of the proxy 801 * @param proxyAttributionTag the attributionTag in the proxies package 802 * @param uidState UID state of the app noteOp/startOp was called for 803 * @param flags OpFlags of the call 804 */ accessed(int proxyUid, @Nullable String proxyPackageName, @Nullable String proxyAttributionTag, @AppOpsManager.UidState int uidState, @OpFlags int flags)805 public void accessed(int proxyUid, @Nullable String proxyPackageName, 806 @Nullable String proxyAttributionTag, @AppOpsManager.UidState int uidState, 807 @OpFlags int flags) { 808 accessed(System.currentTimeMillis(), -1, proxyUid, proxyPackageName, 809 proxyAttributionTag, uidState, flags); 810 811 mHistoricalRegistry.incrementOpAccessedCount(parent.op, parent.uid, parent.packageName, 812 tag, uidState, flags); 813 } 814 815 /** 816 * Add an access that was previously collected. 817 * 818 * @param noteTime The time of the event 819 * @param duration The duration of the event 820 * @param proxyUid The uid of the proxy 821 * @param proxyPackageName The package name of the proxy 822 * @param proxyAttributionTag the attributionTag in the proxies package 823 * @param uidState UID state of the app noteOp/startOp was called for 824 * @param flags OpFlags of the call 825 */ accessed(long noteTime, long duration, int proxyUid, @Nullable String proxyPackageName, @Nullable String proxyAttributionTag, @AppOpsManager.UidState int uidState, @OpFlags int flags)826 public void accessed(long noteTime, long duration, int proxyUid, 827 @Nullable String proxyPackageName, @Nullable String proxyAttributionTag, 828 @AppOpsManager.UidState int uidState, @OpFlags int flags) { 829 long key = makeKey(uidState, flags); 830 831 if (mAccessEvents == null) { 832 mAccessEvents = new LongSparseArray<>(1); 833 } 834 835 OpEventProxyInfo proxyInfo = null; 836 if (proxyUid != Process.INVALID_UID) { 837 proxyInfo = mOpEventProxyInfoPool.acquire(proxyUid, proxyPackageName, 838 proxyAttributionTag); 839 } 840 841 NoteOpEvent existingEvent = mAccessEvents.get(key); 842 if (existingEvent != null) { 843 existingEvent.reinit(noteTime, duration, proxyInfo, mOpEventProxyInfoPool); 844 } else { 845 mAccessEvents.put(key, new NoteOpEvent(noteTime, duration, proxyInfo)); 846 } 847 } 848 849 /** 850 * Update state when noteOp/startOp was rejected. 851 * 852 * @param uidState UID state of the app noteOp is called for 853 * @param flags OpFlags of the call 854 */ rejected(@ppOpsManager.UidState int uidState, @OpFlags int flags)855 public void rejected(@AppOpsManager.UidState int uidState, @OpFlags int flags) { 856 rejected(System.currentTimeMillis(), uidState, flags); 857 858 mHistoricalRegistry.incrementOpRejected(parent.op, parent.uid, parent.packageName, 859 tag, uidState, flags); 860 } 861 862 /** 863 * Add an rejection that was previously collected 864 * 865 * @param noteTime The time of the event 866 * @param uidState UID state of the app noteOp/startOp was called for 867 * @param flags OpFlags of the call 868 */ rejected(long noteTime, @AppOpsManager.UidState int uidState, @OpFlags int flags)869 public void rejected(long noteTime, @AppOpsManager.UidState int uidState, 870 @OpFlags int flags) { 871 long key = makeKey(uidState, flags); 872 873 if (mRejectEvents == null) { 874 mRejectEvents = new LongSparseArray<>(1); 875 } 876 877 // We do not collect proxy information for rejections yet 878 NoteOpEvent existingEvent = mRejectEvents.get(key); 879 if (existingEvent != null) { 880 existingEvent.reinit(noteTime, -1, null, mOpEventProxyInfoPool); 881 } else { 882 mRejectEvents.put(key, new NoteOpEvent(noteTime, -1, null)); 883 } 884 } 885 886 /** 887 * Update state when start was called 888 * 889 * @param clientId Id of the startOp caller 890 * @param uidState UID state of the app startOp is called for 891 */ started(@onNull IBinder clientId, @AppOpsManager.UidState int uidState)892 public void started(@NonNull IBinder clientId, @AppOpsManager.UidState int uidState) 893 throws RemoteException { 894 started(clientId, uidState, true); 895 } 896 started(@onNull IBinder clientId, @AppOpsManager.UidState int uidState, boolean triggerCallbackIfNeeded)897 private void started(@NonNull IBinder clientId, @AppOpsManager.UidState int uidState, 898 boolean triggerCallbackIfNeeded) throws RemoteException { 899 if (triggerCallbackIfNeeded && !parent.isRunning()) { 900 scheduleOpActiveChangedIfNeededLocked(parent.op, parent.uid, 901 parent.packageName, true); 902 } 903 904 if (mInProgressEvents == null) { 905 mInProgressEvents = new ArrayMap<>(1); 906 } 907 908 InProgressStartOpEvent event = mInProgressEvents.get(clientId); 909 if (event == null) { 910 event = mInProgressStartOpEventPool.acquire(System.currentTimeMillis(), 911 SystemClock.elapsedRealtime(), clientId, 912 PooledLambda.obtainRunnable(AppOpsService::onClientDeath, this, clientId), 913 uidState); 914 mInProgressEvents.put(clientId, event); 915 } else { 916 if (uidState != event.mUidState) { 917 onUidStateChanged(uidState); 918 } 919 } 920 921 event.numUnfinishedStarts++; 922 923 // startOp events don't support proxy, hence use flags==SELF 924 mHistoricalRegistry.incrementOpAccessedCount(parent.op, parent.uid, parent.packageName, 925 tag, uidState, OP_FLAG_SELF); 926 } 927 928 /** 929 * Update state when finishOp was called 930 * 931 * @param clientId Id of the finishOp caller 932 */ finished(@onNull IBinder clientId)933 public void finished(@NonNull IBinder clientId) { 934 finished(clientId, true); 935 } 936 finished(@onNull IBinder clientId, boolean triggerCallbackIfNeeded)937 private void finished(@NonNull IBinder clientId, boolean triggerCallbackIfNeeded) { 938 if (mInProgressEvents == null) { 939 Slog.wtf(TAG, "No ops running"); 940 return; 941 } 942 943 int indexOfToken = mInProgressEvents.indexOfKey(clientId); 944 if (indexOfToken < 0) { 945 Slog.wtf(TAG, "No op running for the client"); 946 return; 947 } 948 949 InProgressStartOpEvent event = mInProgressEvents.valueAt(indexOfToken); 950 event.numUnfinishedStarts--; 951 if (event.numUnfinishedStarts == 0) { 952 event.finish(); 953 mInProgressEvents.removeAt(indexOfToken); 954 955 if (mAccessEvents == null) { 956 mAccessEvents = new LongSparseArray<>(1); 957 } 958 959 // startOp events don't support proxy, hence use flags==SELF 960 NoteOpEvent finishedEvent = new NoteOpEvent(event.getStartTime(), 961 SystemClock.elapsedRealtime() - event.getStartElapsedTime(), null); 962 mAccessEvents.put(makeKey(event.getUidState(), OP_FLAG_SELF), finishedEvent); 963 964 mHistoricalRegistry.increaseOpAccessDuration(parent.op, parent.uid, 965 parent.packageName, tag, event.getUidState(), 966 AppOpsManager.OP_FLAG_SELF, finishedEvent.getDuration()); 967 968 mInProgressStartOpEventPool.release(event); 969 970 if (mInProgressEvents.isEmpty()) { 971 mInProgressEvents = null; 972 973 // TODO moltmann: Also callback for single attribution tag activity changes 974 if (triggerCallbackIfNeeded && !parent.isRunning()) { 975 scheduleOpActiveChangedIfNeededLocked(parent.op, parent.uid, 976 parent.packageName, false); 977 } 978 } 979 } 980 } 981 982 /** 983 * Called in the case the client dies without calling finish first 984 * 985 * @param clientId The client that died 986 */ onClientDeath(@onNull IBinder clientId)987 void onClientDeath(@NonNull IBinder clientId) { 988 synchronized (AppOpsService.this) { 989 if (mInProgressEvents == null) { 990 return; 991 } 992 993 InProgressStartOpEvent deadEvent = mInProgressEvents.get(clientId); 994 if (deadEvent != null) { 995 deadEvent.numUnfinishedStarts = 1; 996 } 997 998 finished(clientId); 999 } 1000 } 1001 1002 /** 1003 * Notify that the state of the uid changed 1004 * 1005 * @param newState The new state 1006 */ onUidStateChanged(@ppOpsManager.UidState int newState)1007 public void onUidStateChanged(@AppOpsManager.UidState int newState) { 1008 if (mInProgressEvents == null) { 1009 return; 1010 } 1011 1012 int numInProgressEvents = mInProgressEvents.size(); 1013 for (int i = 0; i < numInProgressEvents; i++) { 1014 InProgressStartOpEvent event = mInProgressEvents.valueAt(i); 1015 1016 if (event.getUidState() != newState) { 1017 try { 1018 // Remove all but one unfinished start count and then call finished() to 1019 // remove start event object 1020 int numPreviousUnfinishedStarts = event.numUnfinishedStarts; 1021 event.numUnfinishedStarts = 1; 1022 finished(event.getClientId(), false); 1023 1024 // Call started() to add a new start event object and then add the 1025 // previously removed unfinished start counts back 1026 started(event.getClientId(), newState, false); 1027 event.numUnfinishedStarts += numPreviousUnfinishedStarts - 1; 1028 } catch (RemoteException e) { 1029 if (DEBUG) Slog.e(TAG, "Cannot switch to new uidState " + newState); 1030 } 1031 } 1032 } 1033 } 1034 1035 /** 1036 * Combine {@code a} and {@code b} and return the result. The result might be {@code a} 1037 * or {@code b}. If there is an event for the same key in both the later event is retained. 1038 */ add(@ullable LongSparseArray<NoteOpEvent> a, @Nullable LongSparseArray<NoteOpEvent> b)1039 private @Nullable LongSparseArray<NoteOpEvent> add(@Nullable LongSparseArray<NoteOpEvent> a, 1040 @Nullable LongSparseArray<NoteOpEvent> b) { 1041 if (a == null) { 1042 return b; 1043 } 1044 1045 if (b == null) { 1046 return a; 1047 } 1048 1049 int numEventsToAdd = b.size(); 1050 for (int i = 0; i < numEventsToAdd; i++) { 1051 long keyOfEventToAdd = b.keyAt(i); 1052 NoteOpEvent bEvent = b.valueAt(i); 1053 NoteOpEvent aEvent = a.get(keyOfEventToAdd); 1054 1055 if (aEvent == null || bEvent.getNoteTime() > aEvent.getNoteTime()) { 1056 a.put(keyOfEventToAdd, bEvent); 1057 } 1058 } 1059 1060 return a; 1061 } 1062 1063 /** 1064 * Add all data from the {@code opToAdd} to this op. 1065 * 1066 * <p>If there is an event for the same key in both the later event is retained. 1067 * <p>{@code opToAdd} should not be used after this method is called. 1068 * 1069 * @param opToAdd The op to add 1070 */ add(@onNull AttributedOp opToAdd)1071 public void add(@NonNull AttributedOp opToAdd) { 1072 if (opToAdd.mInProgressEvents != null) { 1073 Slog.w(TAG, "Ignoring " + opToAdd.mInProgressEvents.size() + " running app-ops"); 1074 1075 int numInProgressEvents = opToAdd.mInProgressEvents.size(); 1076 for (int i = 0; i < numInProgressEvents; i++) { 1077 InProgressStartOpEvent event = opToAdd.mInProgressEvents.valueAt(i); 1078 1079 event.finish(); 1080 mInProgressStartOpEventPool.release(event); 1081 } 1082 } 1083 1084 mAccessEvents = add(mAccessEvents, opToAdd.mAccessEvents); 1085 mRejectEvents = add(mRejectEvents, opToAdd.mRejectEvents); 1086 } 1087 isRunning()1088 public boolean isRunning() { 1089 return mInProgressEvents != null; 1090 } 1091 hasAnyTime()1092 boolean hasAnyTime() { 1093 return (mAccessEvents != null && mAccessEvents.size() > 0) 1094 || (mRejectEvents != null && mRejectEvents.size() > 0); 1095 } 1096 1097 /** 1098 * Clone a {@link LongSparseArray} and clone all values. 1099 */ deepClone( @ullable LongSparseArray<NoteOpEvent> original)1100 private @Nullable LongSparseArray<NoteOpEvent> deepClone( 1101 @Nullable LongSparseArray<NoteOpEvent> original) { 1102 if (original == null) { 1103 return original; 1104 } 1105 1106 int size = original.size(); 1107 LongSparseArray<NoteOpEvent> clone = new LongSparseArray<>(size); 1108 for (int i = 0; i < size; i++) { 1109 clone.put(original.keyAt(i), new NoteOpEvent(original.valueAt(i))); 1110 } 1111 1112 return clone; 1113 } 1114 createAttributedOpEntryLocked()1115 @NonNull AttributedOpEntry createAttributedOpEntryLocked() { 1116 LongSparseArray<NoteOpEvent> accessEvents = deepClone(mAccessEvents); 1117 1118 // Add in progress events as access events 1119 if (mInProgressEvents != null) { 1120 long now = SystemClock.elapsedRealtime(); 1121 int numInProgressEvents = mInProgressEvents.size(); 1122 1123 if (accessEvents == null) { 1124 accessEvents = new LongSparseArray<>(numInProgressEvents); 1125 } 1126 1127 for (int i = 0; i < numInProgressEvents; i++) { 1128 InProgressStartOpEvent event = mInProgressEvents.valueAt(i); 1129 1130 // startOp events don't support proxy 1131 accessEvents.append(makeKey(event.getUidState(), OP_FLAG_SELF), 1132 new NoteOpEvent(event.getStartTime(), now - event.getStartElapsedTime(), 1133 null)); 1134 } 1135 } 1136 1137 LongSparseArray<NoteOpEvent> rejectEvents = deepClone(mRejectEvents); 1138 1139 return new AttributedOpEntry(parent.op, isRunning(), accessEvents, rejectEvents); 1140 } 1141 } 1142 1143 final class Op { 1144 int op; 1145 int uid; 1146 final UidState uidState; 1147 final @NonNull String packageName; 1148 1149 private @Mode int mode; 1150 1151 /** attributionTag -> AttributedOp */ 1152 final ArrayMap<String, AttributedOp> mAttributions = new ArrayMap<>(1); 1153 Op(UidState uidState, String packageName, int op, int uid)1154 Op(UidState uidState, String packageName, int op, int uid) { 1155 this.op = op; 1156 this.uid = uid; 1157 this.uidState = uidState; 1158 this.packageName = packageName; 1159 this.mode = AppOpsManager.opToDefaultMode(op); 1160 } 1161 getMode()1162 int getMode() { 1163 return mode; 1164 } 1165 evalMode()1166 int evalMode() { 1167 return uidState.evalMode(op, mode); 1168 } 1169 removeAttributionsWithNoTime()1170 void removeAttributionsWithNoTime() { 1171 for (int i = mAttributions.size() - 1; i >= 0; i--) { 1172 if (!mAttributions.valueAt(i).hasAnyTime()) { 1173 mAttributions.removeAt(i); 1174 } 1175 } 1176 } 1177 getOrCreateAttribution(@onNull Op parent, @Nullable String attributionTag)1178 private @NonNull AttributedOp getOrCreateAttribution(@NonNull Op parent, 1179 @Nullable String attributionTag) { 1180 AttributedOp attributedOp; 1181 1182 attributedOp = mAttributions.get(attributionTag); 1183 if (attributedOp == null) { 1184 attributedOp = new AttributedOp(attributionTag, parent); 1185 mAttributions.put(attributionTag, attributedOp); 1186 } 1187 1188 return attributedOp; 1189 } 1190 createEntryLocked()1191 @NonNull OpEntry createEntryLocked() { 1192 final int numAttributions = mAttributions.size(); 1193 1194 final ArrayMap<String, AppOpsManager.AttributedOpEntry> attributionEntries = 1195 new ArrayMap<>(numAttributions); 1196 for (int i = 0; i < numAttributions; i++) { 1197 attributionEntries.put(mAttributions.keyAt(i), 1198 mAttributions.valueAt(i).createAttributedOpEntryLocked()); 1199 } 1200 1201 return new OpEntry(op, mode, attributionEntries); 1202 } 1203 createSingleAttributionEntryLocked(@ullable String attributionTag)1204 @NonNull OpEntry createSingleAttributionEntryLocked(@Nullable String attributionTag) { 1205 final int numAttributions = mAttributions.size(); 1206 1207 final ArrayMap<String, AttributedOpEntry> attributionEntries = new ArrayMap<>(1); 1208 for (int i = 0; i < numAttributions; i++) { 1209 if (Objects.equals(mAttributions.keyAt(i), attributionTag)) { 1210 attributionEntries.put(mAttributions.keyAt(i), 1211 mAttributions.valueAt(i).createAttributedOpEntryLocked()); 1212 break; 1213 } 1214 } 1215 1216 return new OpEntry(op, mode, attributionEntries); 1217 } 1218 isRunning()1219 boolean isRunning() { 1220 final int numAttributions = mAttributions.size(); 1221 for (int i = 0; i < numAttributions; i++) { 1222 if (mAttributions.valueAt(i).isRunning()) { 1223 return true; 1224 } 1225 } 1226 1227 return false; 1228 } 1229 } 1230 1231 final SparseArray<ArraySet<ModeCallback>> mOpModeWatchers = new SparseArray<>(); 1232 final ArrayMap<String, ArraySet<ModeCallback>> mPackageModeWatchers = new ArrayMap<>(); 1233 final ArrayMap<IBinder, ModeCallback> mModeWatchers = new ArrayMap<>(); 1234 final ArrayMap<IBinder, SparseArray<ActiveCallback>> mActiveWatchers = new ArrayMap<>(); 1235 final ArrayMap<IBinder, SparseArray<StartedCallback>> mStartedWatchers = new ArrayMap<>(); 1236 final ArrayMap<IBinder, SparseArray<NotedCallback>> mNotedWatchers = new ArrayMap<>(); 1237 final AudioRestrictionManager mAudioRestrictionManager = new AudioRestrictionManager(); 1238 1239 final class ModeCallback implements DeathRecipient { 1240 /** If mWatchedOpCode==ALL_OPS notify for ops affected by the switch-op */ 1241 public static final int ALL_OPS = -2; 1242 1243 final IAppOpsCallback mCallback; 1244 final int mWatchingUid; 1245 final int mFlags; 1246 final int mWatchedOpCode; 1247 final int mCallingUid; 1248 final int mCallingPid; 1249 ModeCallback(IAppOpsCallback callback, int watchingUid, int flags, int watchedOp, int callingUid, int callingPid)1250 ModeCallback(IAppOpsCallback callback, int watchingUid, int flags, int watchedOp, 1251 int callingUid, int callingPid) { 1252 mCallback = callback; 1253 mWatchingUid = watchingUid; 1254 mFlags = flags; 1255 mWatchedOpCode = watchedOp; 1256 mCallingUid = callingUid; 1257 mCallingPid = callingPid; 1258 try { 1259 mCallback.asBinder().linkToDeath(this, 0); 1260 } catch (RemoteException e) { 1261 /*ignored*/ 1262 } 1263 } 1264 isWatchingUid(int uid)1265 public boolean isWatchingUid(int uid) { 1266 return uid == UID_ANY || mWatchingUid < 0 || mWatchingUid == uid; 1267 } 1268 1269 @Override toString()1270 public String toString() { 1271 StringBuilder sb = new StringBuilder(128); 1272 sb.append("ModeCallback{"); 1273 sb.append(Integer.toHexString(System.identityHashCode(this))); 1274 sb.append(" watchinguid="); 1275 UserHandle.formatUid(sb, mWatchingUid); 1276 sb.append(" flags=0x"); 1277 sb.append(Integer.toHexString(mFlags)); 1278 switch (mWatchedOpCode) { 1279 case OP_NONE: 1280 break; 1281 case ALL_OPS: 1282 sb.append(" op=(all)"); 1283 break; 1284 default: 1285 sb.append(" op="); 1286 sb.append(opToName(mWatchedOpCode)); 1287 break; 1288 } 1289 sb.append(" from uid="); 1290 UserHandle.formatUid(sb, mCallingUid); 1291 sb.append(" pid="); 1292 sb.append(mCallingPid); 1293 sb.append('}'); 1294 return sb.toString(); 1295 } 1296 unlinkToDeath()1297 void unlinkToDeath() { 1298 mCallback.asBinder().unlinkToDeath(this, 0); 1299 } 1300 1301 @Override binderDied()1302 public void binderDied() { 1303 stopWatchingMode(mCallback); 1304 } 1305 } 1306 1307 final class ActiveCallback implements DeathRecipient { 1308 final IAppOpsActiveCallback mCallback; 1309 final int mWatchingUid; 1310 final int mCallingUid; 1311 final int mCallingPid; 1312 ActiveCallback(IAppOpsActiveCallback callback, int watchingUid, int callingUid, int callingPid)1313 ActiveCallback(IAppOpsActiveCallback callback, int watchingUid, int callingUid, 1314 int callingPid) { 1315 mCallback = callback; 1316 mWatchingUid = watchingUid; 1317 mCallingUid = callingUid; 1318 mCallingPid = callingPid; 1319 try { 1320 mCallback.asBinder().linkToDeath(this, 0); 1321 } catch (RemoteException e) { 1322 /*ignored*/ 1323 } 1324 } 1325 1326 @Override toString()1327 public String toString() { 1328 StringBuilder sb = new StringBuilder(128); 1329 sb.append("ActiveCallback{"); 1330 sb.append(Integer.toHexString(System.identityHashCode(this))); 1331 sb.append(" watchinguid="); 1332 UserHandle.formatUid(sb, mWatchingUid); 1333 sb.append(" from uid="); 1334 UserHandle.formatUid(sb, mCallingUid); 1335 sb.append(" pid="); 1336 sb.append(mCallingPid); 1337 sb.append('}'); 1338 return sb.toString(); 1339 } 1340 destroy()1341 void destroy() { 1342 mCallback.asBinder().unlinkToDeath(this, 0); 1343 } 1344 1345 @Override binderDied()1346 public void binderDied() { 1347 stopWatchingActive(mCallback); 1348 } 1349 } 1350 1351 final class StartedCallback implements DeathRecipient { 1352 final IAppOpsStartedCallback mCallback; 1353 final int mWatchingUid; 1354 final int mCallingUid; 1355 final int mCallingPid; 1356 StartedCallback(IAppOpsStartedCallback callback, int watchingUid, int callingUid, int callingPid)1357 StartedCallback(IAppOpsStartedCallback callback, int watchingUid, int callingUid, 1358 int callingPid) { 1359 mCallback = callback; 1360 mWatchingUid = watchingUid; 1361 mCallingUid = callingUid; 1362 mCallingPid = callingPid; 1363 try { 1364 mCallback.asBinder().linkToDeath(this, 0); 1365 } catch (RemoteException e) { 1366 /*ignored*/ 1367 } 1368 } 1369 1370 @Override toString()1371 public String toString() { 1372 StringBuilder sb = new StringBuilder(128); 1373 sb.append("StartedCallback{"); 1374 sb.append(Integer.toHexString(System.identityHashCode(this))); 1375 sb.append(" watchinguid="); 1376 UserHandle.formatUid(sb, mWatchingUid); 1377 sb.append(" from uid="); 1378 UserHandle.formatUid(sb, mCallingUid); 1379 sb.append(" pid="); 1380 sb.append(mCallingPid); 1381 sb.append('}'); 1382 return sb.toString(); 1383 } 1384 destroy()1385 void destroy() { 1386 mCallback.asBinder().unlinkToDeath(this, 0); 1387 } 1388 1389 @Override binderDied()1390 public void binderDied() { 1391 stopWatchingStarted(mCallback); 1392 } 1393 } 1394 1395 final class NotedCallback implements DeathRecipient { 1396 final IAppOpsNotedCallback mCallback; 1397 final int mWatchingUid; 1398 final int mCallingUid; 1399 final int mCallingPid; 1400 NotedCallback(IAppOpsNotedCallback callback, int watchingUid, int callingUid, int callingPid)1401 NotedCallback(IAppOpsNotedCallback callback, int watchingUid, int callingUid, 1402 int callingPid) { 1403 mCallback = callback; 1404 mWatchingUid = watchingUid; 1405 mCallingUid = callingUid; 1406 mCallingPid = callingPid; 1407 try { 1408 mCallback.asBinder().linkToDeath(this, 0); 1409 } catch (RemoteException e) { 1410 /*ignored*/ 1411 } 1412 } 1413 1414 @Override toString()1415 public String toString() { 1416 StringBuilder sb = new StringBuilder(128); 1417 sb.append("NotedCallback{"); 1418 sb.append(Integer.toHexString(System.identityHashCode(this))); 1419 sb.append(" watchinguid="); 1420 UserHandle.formatUid(sb, mWatchingUid); 1421 sb.append(" from uid="); 1422 UserHandle.formatUid(sb, mCallingUid); 1423 sb.append(" pid="); 1424 sb.append(mCallingPid); 1425 sb.append('}'); 1426 return sb.toString(); 1427 } 1428 destroy()1429 void destroy() { 1430 mCallback.asBinder().unlinkToDeath(this, 0); 1431 } 1432 1433 @Override binderDied()1434 public void binderDied() { 1435 stopWatchingNoted(mCallback); 1436 } 1437 } 1438 1439 /** 1440 * Call {@link AttributedOp#onClientDeath attributedOp.onClientDeath(clientId)}. 1441 */ onClientDeath(@onNull AttributedOp attributedOp, @NonNull IBinder clientId)1442 private static void onClientDeath(@NonNull AttributedOp attributedOp, 1443 @NonNull IBinder clientId) { 1444 attributedOp.onClientDeath(clientId); 1445 } 1446 1447 1448 /** 1449 * Loads the OpsValidation file results into a hashmap {@link #mNoteOpCallerStacktraces} 1450 * so that we do not log the same operation twice between instances 1451 */ readNoteOpCallerStackTraces()1452 private void readNoteOpCallerStackTraces() { 1453 try { 1454 if (!mNoteOpCallerStacktracesFile.exists()) { 1455 mNoteOpCallerStacktracesFile.createNewFile(); 1456 return; 1457 } 1458 1459 try (Scanner read = new Scanner(mNoteOpCallerStacktracesFile)) { 1460 read.useDelimiter("\\},"); 1461 while (read.hasNext()) { 1462 String jsonOps = read.next(); 1463 mNoteOpCallerStacktraces.add(NoteOpTrace.fromJson(jsonOps)); 1464 } 1465 } 1466 } catch (Exception e) { 1467 Slog.e(TAG, "Cannot parse traces noteOps", e); 1468 } 1469 } 1470 AppOpsService(File storagePath, Handler handler, Context context)1471 public AppOpsService(File storagePath, Handler handler, Context context) { 1472 mContext = context; 1473 1474 LockGuard.installLock(this, LockGuard.INDEX_APP_OPS); 1475 mFile = new AtomicFile(storagePath, "appops"); 1476 if (AppOpsManager.NOTE_OP_COLLECTION_ENABLED) { 1477 mNoteOpCallerStacktracesFile = new File(SystemServiceManager.ensureSystemDir(), 1478 "noteOpStackTraces.json"); 1479 readNoteOpCallerStackTraces(); 1480 } else { 1481 mNoteOpCallerStacktracesFile = null; 1482 } 1483 mHandler = handler; 1484 mConstants = new Constants(mHandler); 1485 readState(); 1486 1487 for (int switchedCode = 0; switchedCode < _NUM_OP; switchedCode++) { 1488 int switchCode = AppOpsManager.opToSwitch(switchedCode); 1489 mSwitchedOps.put(switchCode, 1490 ArrayUtils.appendInt(mSwitchedOps.get(switchCode), switchedCode)); 1491 } 1492 } 1493 publish()1494 public void publish() { 1495 ServiceManager.addService(Context.APP_OPS_SERVICE, asBinder()); 1496 LocalServices.addService(AppOpsManagerInternal.class, mAppOpsManagerInternal); 1497 } 1498 1499 /** Handler for work when packages are removed or updated */ 1500 private BroadcastReceiver mOnPackageUpdatedReceiver = new BroadcastReceiver() { 1501 @Override 1502 public void onReceive(Context context, Intent intent) { 1503 String action = intent.getAction(); 1504 String pkgName = intent.getData().getEncodedSchemeSpecificPart(); 1505 int uid = intent.getIntExtra(Intent.EXTRA_UID, Process.INVALID_UID); 1506 1507 if (action.equals(ACTION_PACKAGE_REMOVED) && !intent.hasExtra(EXTRA_REPLACING)) { 1508 synchronized (AppOpsService.this) { 1509 UidState uidState = mUidStates.get(uid); 1510 if (uidState == null || uidState.pkgOps == null) { 1511 return; 1512 } 1513 1514 Ops removedOps = uidState.pkgOps.remove(pkgName); 1515 if (removedOps != null) { 1516 scheduleFastWriteLocked(); 1517 } 1518 } 1519 } else if (action.equals(Intent.ACTION_PACKAGE_REPLACED)) { 1520 AndroidPackage pkg = LocalServices.getService( 1521 PackageManagerInternal.class).getPackage(pkgName); 1522 if (pkg == null) { 1523 return; 1524 } 1525 1526 ArrayMap<String, String> dstAttributionTags = new ArrayMap<>(); 1527 ArraySet<String> attributionTags = new ArraySet<>(); 1528 attributionTags.add(null); 1529 if (pkg.getAttributions() != null) { 1530 int numAttributions = pkg.getAttributions().size(); 1531 for (int attributionNum = 0; attributionNum < numAttributions; 1532 attributionNum++) { 1533 ParsedAttribution attribution = pkg.getAttributions().get(attributionNum); 1534 attributionTags.add(attribution.tag); 1535 1536 int numInheritFrom = attribution.inheritFrom.size(); 1537 for (int inheritFromNum = 0; inheritFromNum < numInheritFrom; 1538 inheritFromNum++) { 1539 dstAttributionTags.put(attribution.inheritFrom.get(inheritFromNum), 1540 attribution.tag); 1541 } 1542 } 1543 } 1544 1545 synchronized (AppOpsService.this) { 1546 UidState uidState = mUidStates.get(uid); 1547 if (uidState == null || uidState.pkgOps == null) { 1548 return; 1549 } 1550 1551 Ops ops = uidState.pkgOps.get(pkgName); 1552 if (ops == null) { 1553 return; 1554 } 1555 1556 // Reset cached package properties to re-initialize when needed 1557 ops.bypass = null; 1558 ops.knownAttributionTags.clear(); 1559 1560 // Merge data collected for removed attributions into their successor 1561 // attributions 1562 int numOps = ops.size(); 1563 for (int opNum = 0; opNum < numOps; opNum++) { 1564 Op op = ops.valueAt(opNum); 1565 1566 int numAttributions = op.mAttributions.size(); 1567 for (int attributionNum = numAttributions - 1; attributionNum >= 0; 1568 attributionNum--) { 1569 String attributionTag = op.mAttributions.keyAt(attributionNum); 1570 1571 if (attributionTags.contains(attributionTag)) { 1572 // attribution still exist after upgrade 1573 continue; 1574 } 1575 1576 String newAttributionTag = dstAttributionTags.get(attributionTag); 1577 1578 AttributedOp newAttributedOp = op.getOrCreateAttribution(op, 1579 newAttributionTag); 1580 newAttributedOp.add(op.mAttributions.valueAt(attributionNum)); 1581 op.mAttributions.removeAt(attributionNum); 1582 1583 scheduleFastWriteLocked(); 1584 } 1585 } 1586 } 1587 } 1588 } 1589 }; 1590 systemReady()1591 public void systemReady() { 1592 mConstants.startMonitoring(mContext.getContentResolver()); 1593 mHistoricalRegistry.systemReady(mContext.getContentResolver()); 1594 1595 IntentFilter packageUpdateFilter = new IntentFilter(); 1596 packageUpdateFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); 1597 packageUpdateFilter.addAction(Intent.ACTION_PACKAGE_REPLACED); 1598 packageUpdateFilter.addDataScheme("package"); 1599 1600 mContext.registerReceiverAsUser(mOnPackageUpdatedReceiver, UserHandle.ALL, 1601 packageUpdateFilter, null, null); 1602 1603 synchronized (this) { 1604 for (int uidNum = mUidStates.size() - 1; uidNum >= 0; uidNum--) { 1605 int uid = mUidStates.keyAt(uidNum); 1606 UidState uidState = mUidStates.valueAt(uidNum); 1607 1608 String[] pkgsInUid = getPackagesForUid(uidState.uid); 1609 if (ArrayUtils.isEmpty(pkgsInUid)) { 1610 uidState.clear(); 1611 mUidStates.removeAt(uidNum); 1612 scheduleFastWriteLocked(); 1613 continue; 1614 } 1615 1616 ArrayMap<String, Ops> pkgs = uidState.pkgOps; 1617 if (pkgs == null) { 1618 continue; 1619 } 1620 1621 int numPkgs = pkgs.size(); 1622 for (int pkgNum = 0; pkgNum < numPkgs; pkgNum++) { 1623 String pkg = pkgs.keyAt(pkgNum); 1624 1625 String action; 1626 if (!ArrayUtils.contains(pkgsInUid, pkg)) { 1627 action = Intent.ACTION_PACKAGE_REMOVED; 1628 } else { 1629 action = Intent.ACTION_PACKAGE_REPLACED; 1630 } 1631 1632 SystemServerInitThreadPool.submit( 1633 () -> mOnPackageUpdatedReceiver.onReceive(mContext, new Intent(action) 1634 .setData(Uri.fromParts("package", pkg, null)) 1635 .putExtra(Intent.EXTRA_UID, uid)), 1636 "Update app-ops uidState in case package " + pkg + " changed"); 1637 } 1638 } 1639 } 1640 1641 final IntentFilter packageSuspendFilter = new IntentFilter(); 1642 packageSuspendFilter.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED); 1643 packageSuspendFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED); 1644 mContext.registerReceiverAsUser(new BroadcastReceiver() { 1645 @Override 1646 public void onReceive(Context context, Intent intent) { 1647 final int[] changedUids = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST); 1648 final String[] changedPkgs = intent.getStringArrayExtra( 1649 Intent.EXTRA_CHANGED_PACKAGE_LIST); 1650 for (int code : OPS_RESTRICTED_ON_SUSPEND) { 1651 ArraySet<ModeCallback> callbacks; 1652 synchronized (AppOpsService.this) { 1653 callbacks = mOpModeWatchers.get(code); 1654 if (callbacks == null) { 1655 continue; 1656 } 1657 callbacks = new ArraySet<>(callbacks); 1658 } 1659 for (int i = 0; i < changedUids.length; i++) { 1660 final int changedUid = changedUids[i]; 1661 final String changedPkg = changedPkgs[i]; 1662 // We trust packagemanager to insert matching uid and packageNames in the 1663 // extras 1664 notifyOpChanged(callbacks, code, changedUid, changedPkg); 1665 } 1666 } 1667 } 1668 }, UserHandle.ALL, packageSuspendFilter, null, null); 1669 1670 final IntentFilter packageAddedFilter = new IntentFilter(); 1671 packageAddedFilter.addAction(Intent.ACTION_PACKAGE_ADDED); 1672 packageAddedFilter.addDataScheme("package"); 1673 mContext.registerReceiver(new BroadcastReceiver() { 1674 @Override 1675 public void onReceive(Context context, Intent intent) { 1676 final Uri data = intent.getData(); 1677 1678 final String packageName = data.getSchemeSpecificPart(); 1679 PackageInfo pi = LocalServices.getService( 1680 PackageManagerInternal.class).getPackageInfo(packageName, 1681 PackageManager.GET_PERMISSIONS, Process.myUid(), mContext.getUserId()); 1682 if (isSamplingTarget(pi)) { 1683 synchronized (this) { 1684 mRarelyUsedPackages.add(packageName); 1685 } 1686 } 1687 } 1688 }, packageAddedFilter); 1689 1690 mHandler.postDelayed(new Runnable() { 1691 @Override 1692 public void run() { 1693 List<String> packageNames = getPackageListAndResample(); 1694 initializeRarelyUsedPackagesList(new ArraySet<>(packageNames)); 1695 } 1696 }, RARELY_USED_PACKAGES_INITIALIZATION_DELAY_MILLIS); 1697 1698 PackageManagerInternal packageManagerInternal = LocalServices.getService( 1699 PackageManagerInternal.class); 1700 packageManagerInternal.setExternalSourcesPolicy( 1701 new PackageManagerInternal.ExternalSourcesPolicy() { 1702 @Override 1703 public int getPackageTrustedToInstallApps(String packageName, int uid) { 1704 int appOpMode = checkOperation(AppOpsManager.OP_REQUEST_INSTALL_PACKAGES, 1705 uid, packageName); 1706 switch (appOpMode) { 1707 case AppOpsManager.MODE_ALLOWED: 1708 return PackageManagerInternal.ExternalSourcesPolicy.USER_TRUSTED; 1709 case AppOpsManager.MODE_ERRORED: 1710 return PackageManagerInternal.ExternalSourcesPolicy.USER_BLOCKED; 1711 default: 1712 return PackageManagerInternal.ExternalSourcesPolicy.USER_DEFAULT; 1713 } 1714 } 1715 }); 1716 1717 if (!StorageManager.hasIsolatedStorage()) { 1718 StorageManagerInternal storageManagerInternal = LocalServices.getService( 1719 StorageManagerInternal.class); 1720 storageManagerInternal.addExternalStoragePolicy( 1721 new StorageManagerInternal.ExternalStorageMountPolicy() { 1722 @Override 1723 public int getMountMode(int uid, String packageName) { 1724 if (Process.isIsolated(uid)) { 1725 return Zygote.MOUNT_EXTERNAL_NONE; 1726 } 1727 if (noteOperation(AppOpsManager.OP_READ_EXTERNAL_STORAGE, uid, 1728 packageName, null, true, "External storage policy", true) 1729 != AppOpsManager.MODE_ALLOWED) { 1730 return Zygote.MOUNT_EXTERNAL_NONE; 1731 } 1732 if (noteOperation(AppOpsManager.OP_WRITE_EXTERNAL_STORAGE, uid, 1733 packageName, null, true, "External storage policy", true) 1734 != AppOpsManager.MODE_ALLOWED) { 1735 return Zygote.MOUNT_EXTERNAL_READ; 1736 } 1737 return Zygote.MOUNT_EXTERNAL_WRITE; 1738 } 1739 1740 @Override 1741 public boolean hasExternalStorage(int uid, String packageName) { 1742 final int mountMode = getMountMode(uid, packageName); 1743 return mountMode == Zygote.MOUNT_EXTERNAL_READ 1744 || mountMode == Zygote.MOUNT_EXTERNAL_WRITE; 1745 } 1746 }); 1747 } 1748 mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class); 1749 } 1750 packageRemoved(int uid, String packageName)1751 public void packageRemoved(int uid, String packageName) { 1752 synchronized (this) { 1753 UidState uidState = mUidStates.get(uid); 1754 if (uidState == null) { 1755 return; 1756 } 1757 1758 Ops ops = null; 1759 1760 // Remove any package state if such. 1761 if (uidState.pkgOps != null) { 1762 ops = uidState.pkgOps.remove(packageName); 1763 } 1764 1765 // If we just nuked the last package state check if the UID is valid. 1766 if (ops != null && uidState.pkgOps.isEmpty() 1767 && getPackagesForUid(uid).length <= 0) { 1768 mUidStates.remove(uid); 1769 } 1770 1771 if (ops != null) { 1772 scheduleFastWriteLocked(); 1773 1774 final int numOps = ops.size(); 1775 for (int opNum = 0; opNum < numOps; opNum++) { 1776 final Op op = ops.valueAt(opNum); 1777 1778 final int numAttributions = op.mAttributions.size(); 1779 for (int attributionNum = 0; attributionNum < numAttributions; 1780 attributionNum++) { 1781 AttributedOp attributedOp = op.mAttributions.valueAt(attributionNum); 1782 1783 while (attributedOp.mInProgressEvents != null) { 1784 attributedOp.finished(attributedOp.mInProgressEvents.keyAt(0)); 1785 } 1786 } 1787 } 1788 } 1789 1790 mHistoricalRegistry.clearHistory(uid, packageName); 1791 } 1792 } 1793 uidRemoved(int uid)1794 public void uidRemoved(int uid) { 1795 synchronized (this) { 1796 if (mUidStates.indexOfKey(uid) >= 0) { 1797 mUidStates.remove(uid); 1798 scheduleFastWriteLocked(); 1799 } 1800 } 1801 } 1802 1803 /** 1804 * Update the pending state for the uid 1805 * 1806 * @param currentTime The current elapsed real time 1807 * @param uid The uid that has a pending state 1808 */ updatePendingState(long currentTime, int uid)1809 private void updatePendingState(long currentTime, int uid) { 1810 synchronized (this) { 1811 mLastRealtime = max(currentTime, mLastRealtime); 1812 updatePendingStateIfNeededLocked(mUidStates.get(uid)); 1813 } 1814 } 1815 updateUidProcState(int uid, int procState, @ActivityManager.ProcessCapability int capability)1816 public void updateUidProcState(int uid, int procState, 1817 @ActivityManager.ProcessCapability int capability) { 1818 synchronized (this) { 1819 final UidState uidState = getUidStateLocked(uid, true); 1820 final int newState = PROCESS_STATE_TO_UID_STATE[procState]; 1821 if (uidState != null && (uidState.pendingState != newState 1822 || uidState.pendingCapability != capability)) { 1823 final int oldPendingState = uidState.pendingState; 1824 uidState.pendingState = newState; 1825 uidState.pendingCapability = capability; 1826 if (newState < uidState.state 1827 || (newState <= UID_STATE_MAX_LAST_NON_RESTRICTED 1828 && uidState.state > UID_STATE_MAX_LAST_NON_RESTRICTED)) { 1829 // We are moving to a more important state, or the new state may be in the 1830 // foreground and the old state is in the background, then always do it 1831 // immediately. 1832 commitUidPendingStateLocked(uidState); 1833 } else if (newState == uidState.state && capability != uidState.capability) { 1834 // No change on process state, but process capability has changed. 1835 commitUidPendingStateLocked(uidState); 1836 } else if (uidState.pendingStateCommitTime == 0) { 1837 // We are moving to a less important state for the first time, 1838 // delay the application for a bit. 1839 final long settleTime; 1840 if (uidState.state <= UID_STATE_TOP) { 1841 settleTime = mConstants.TOP_STATE_SETTLE_TIME; 1842 } else if (uidState.state <= UID_STATE_FOREGROUND_SERVICE) { 1843 settleTime = mConstants.FG_SERVICE_STATE_SETTLE_TIME; 1844 } else { 1845 settleTime = mConstants.BG_STATE_SETTLE_TIME; 1846 } 1847 final long commitTime = SystemClock.elapsedRealtime() + settleTime; 1848 uidState.pendingStateCommitTime = commitTime; 1849 1850 mHandler.sendMessageDelayed( 1851 PooledLambda.obtainMessage(AppOpsService::updatePendingState, this, 1852 commitTime + 1, uid), settleTime + 1); 1853 } 1854 1855 if (uidState.pkgOps != null) { 1856 int numPkgs = uidState.pkgOps.size(); 1857 for (int pkgNum = 0; pkgNum < numPkgs; pkgNum++) { 1858 Ops ops = uidState.pkgOps.valueAt(pkgNum); 1859 1860 int numOps = ops.size(); 1861 for (int opNum = 0; opNum < numOps; opNum++) { 1862 Op op = ops.valueAt(opNum); 1863 1864 int numAttributions = op.mAttributions.size(); 1865 for (int attributionNum = 0; attributionNum < numAttributions; 1866 attributionNum++) { 1867 AttributedOp attributedOp = op.mAttributions.valueAt( 1868 attributionNum); 1869 1870 attributedOp.onUidStateChanged(newState); 1871 } 1872 } 1873 } 1874 } 1875 } 1876 } 1877 } 1878 shutdown()1879 public void shutdown() { 1880 Slog.w(TAG, "Writing app ops before shutdown..."); 1881 boolean doWrite = false; 1882 synchronized (this) { 1883 if (mWriteScheduled) { 1884 mWriteScheduled = false; 1885 doWrite = true; 1886 } 1887 } 1888 if (doWrite) { 1889 writeState(); 1890 } 1891 if (AppOpsManager.NOTE_OP_COLLECTION_ENABLED && mWriteNoteOpsScheduled) { 1892 writeNoteOps(); 1893 } 1894 1895 mHistoricalRegistry.shutdown(); 1896 } 1897 collectOps(Ops pkgOps, int[] ops)1898 private ArrayList<AppOpsManager.OpEntry> collectOps(Ops pkgOps, int[] ops) { 1899 ArrayList<AppOpsManager.OpEntry> resOps = null; 1900 final long elapsedNow = SystemClock.elapsedRealtime(); 1901 if (ops == null) { 1902 resOps = new ArrayList<>(); 1903 for (int j=0; j<pkgOps.size(); j++) { 1904 Op curOp = pkgOps.valueAt(j); 1905 resOps.add(getOpEntryForResult(curOp, elapsedNow)); 1906 } 1907 } else { 1908 for (int j=0; j<ops.length; j++) { 1909 Op curOp = pkgOps.get(ops[j]); 1910 if (curOp != null) { 1911 if (resOps == null) { 1912 resOps = new ArrayList<>(); 1913 } 1914 resOps.add(getOpEntryForResult(curOp, elapsedNow)); 1915 } 1916 } 1917 } 1918 return resOps; 1919 } 1920 1921 @Nullable collectUidOps(@onNull UidState uidState, @Nullable int[] ops)1922 private ArrayList<AppOpsManager.OpEntry> collectUidOps(@NonNull UidState uidState, 1923 @Nullable int[] ops) { 1924 if (uidState.opModes == null) { 1925 return null; 1926 } 1927 1928 int opModeCount = uidState.opModes.size(); 1929 if (opModeCount == 0) { 1930 return null; 1931 } 1932 ArrayList<AppOpsManager.OpEntry> resOps = null; 1933 if (ops == null) { 1934 resOps = new ArrayList<>(); 1935 for (int i = 0; i < opModeCount; i++) { 1936 int code = uidState.opModes.keyAt(i); 1937 resOps.add(new OpEntry(code, uidState.opModes.get(code), Collections.emptyMap())); 1938 } 1939 } else { 1940 for (int j=0; j<ops.length; j++) { 1941 int code = ops[j]; 1942 if (uidState.opModes.indexOfKey(code) >= 0) { 1943 if (resOps == null) { 1944 resOps = new ArrayList<>(); 1945 } 1946 resOps.add(new OpEntry(code, uidState.opModes.get(code), 1947 Collections.emptyMap())); 1948 } 1949 } 1950 } 1951 return resOps; 1952 } 1953 getOpEntryForResult(@onNull Op op, long elapsedNow)1954 private static @NonNull OpEntry getOpEntryForResult(@NonNull Op op, long elapsedNow) { 1955 return op.createEntryLocked(); 1956 } 1957 1958 @Override getPackagesForOps(int[] ops)1959 public List<AppOpsManager.PackageOps> getPackagesForOps(int[] ops) { 1960 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS, 1961 Binder.getCallingPid(), Binder.getCallingUid(), null); 1962 ArrayList<AppOpsManager.PackageOps> res = null; 1963 synchronized (this) { 1964 final int uidStateCount = mUidStates.size(); 1965 for (int i = 0; i < uidStateCount; i++) { 1966 UidState uidState = mUidStates.valueAt(i); 1967 if (uidState.pkgOps == null || uidState.pkgOps.isEmpty()) { 1968 continue; 1969 } 1970 ArrayMap<String, Ops> packages = uidState.pkgOps; 1971 final int packageCount = packages.size(); 1972 for (int j = 0; j < packageCount; j++) { 1973 Ops pkgOps = packages.valueAt(j); 1974 ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops); 1975 if (resOps != null) { 1976 if (res == null) { 1977 res = new ArrayList<AppOpsManager.PackageOps>(); 1978 } 1979 AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps( 1980 pkgOps.packageName, pkgOps.uidState.uid, resOps); 1981 res.add(resPackage); 1982 } 1983 } 1984 } 1985 } 1986 return res; 1987 } 1988 1989 @Override getOpsForPackage(int uid, String packageName, int[] ops)1990 public List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName, 1991 int[] ops) { 1992 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS, 1993 Binder.getCallingPid(), Binder.getCallingUid(), null); 1994 String resolvedPackageName = resolvePackageName(uid, packageName); 1995 if (resolvedPackageName == null) { 1996 return Collections.emptyList(); 1997 } 1998 synchronized (this) { 1999 Ops pkgOps = getOpsLocked(uid, resolvedPackageName, null, null, false /* edit */); 2000 if (pkgOps == null) { 2001 return null; 2002 } 2003 ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops); 2004 if (resOps == null) { 2005 return null; 2006 } 2007 ArrayList<AppOpsManager.PackageOps> res = new ArrayList<AppOpsManager.PackageOps>(); 2008 AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps( 2009 pkgOps.packageName, pkgOps.uidState.uid, resOps); 2010 res.add(resPackage); 2011 return res; 2012 } 2013 } 2014 2015 /** 2016 * Verify that historical appop request arguments are valid. 2017 */ ensureHistoricalOpRequestIsValid(int uid, String packageName, String attributionTag, List<String> opNames, int filter, long beginTimeMillis, long endTimeMillis, int flags)2018 private void ensureHistoricalOpRequestIsValid(int uid, String packageName, 2019 String attributionTag, List<String> opNames, int filter, long beginTimeMillis, 2020 long endTimeMillis, int flags) { 2021 if ((filter & FILTER_BY_UID) != 0) { 2022 Preconditions.checkArgument(uid != Process.INVALID_UID); 2023 } else { 2024 Preconditions.checkArgument(uid == Process.INVALID_UID); 2025 } 2026 2027 if ((filter & FILTER_BY_PACKAGE_NAME) != 0) { 2028 Objects.requireNonNull(packageName); 2029 } else { 2030 Preconditions.checkArgument(packageName == null); 2031 } 2032 2033 if ((filter & FILTER_BY_ATTRIBUTION_TAG) == 0) { 2034 Preconditions.checkArgument(attributionTag == null); 2035 } 2036 2037 if ((filter & FILTER_BY_OP_NAMES) != 0) { 2038 Objects.requireNonNull(opNames); 2039 } else { 2040 Preconditions.checkArgument(opNames == null); 2041 } 2042 2043 Preconditions.checkFlagsArgument(filter, 2044 FILTER_BY_UID | FILTER_BY_PACKAGE_NAME | FILTER_BY_ATTRIBUTION_TAG 2045 | FILTER_BY_OP_NAMES); 2046 Preconditions.checkArgumentNonnegative(beginTimeMillis); 2047 Preconditions.checkArgument(endTimeMillis > beginTimeMillis); 2048 Preconditions.checkFlagsArgument(flags, OP_FLAGS_ALL); 2049 } 2050 2051 @Override getHistoricalOps(int uid, String packageName, String attributionTag, List<String> opNames, int filter, long beginTimeMillis, long endTimeMillis, int flags, RemoteCallback callback)2052 public void getHistoricalOps(int uid, String packageName, String attributionTag, 2053 List<String> opNames, int filter, long beginTimeMillis, long endTimeMillis, 2054 int flags, RemoteCallback callback) { 2055 ensureHistoricalOpRequestIsValid(uid, packageName, attributionTag, opNames, filter, 2056 beginTimeMillis, endTimeMillis, flags); 2057 Objects.requireNonNull(callback, "callback cannot be null"); 2058 2059 ActivityManagerInternal ami = LocalServices.getService(ActivityManagerInternal.class); 2060 boolean isCallerInstrumented = ami.isUidCurrentlyInstrumented(Binder.getCallingUid()); 2061 boolean isCallerSystem = Binder.getCallingPid() == Process.myPid(); 2062 2063 if (!isCallerSystem && !isCallerInstrumented) { 2064 mHandler.post(() -> callback.sendResult(new Bundle())); 2065 return; 2066 } 2067 2068 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS, 2069 Binder.getCallingPid(), Binder.getCallingUid(), "getHistoricalOps"); 2070 2071 final String[] opNamesArray = (opNames != null) 2072 ? opNames.toArray(new String[opNames.size()]) : null; 2073 2074 // Must not hold the appops lock 2075 mHandler.post(PooledLambda.obtainRunnable(HistoricalRegistry::getHistoricalOps, 2076 mHistoricalRegistry, uid, packageName, attributionTag, opNamesArray, filter, 2077 beginTimeMillis, endTimeMillis, flags, callback).recycleOnUse()); 2078 } 2079 2080 @Override getHistoricalOpsFromDiskRaw(int uid, String packageName, String attributionTag, List<String> opNames, int filter, long beginTimeMillis, long endTimeMillis, int flags, RemoteCallback callback)2081 public void getHistoricalOpsFromDiskRaw(int uid, String packageName, String attributionTag, 2082 List<String> opNames, int filter, long beginTimeMillis, long endTimeMillis, 2083 int flags, RemoteCallback callback) { 2084 ensureHistoricalOpRequestIsValid(uid, packageName, attributionTag, opNames, filter, 2085 beginTimeMillis, endTimeMillis, flags); 2086 Objects.requireNonNull(callback, "callback cannot be null"); 2087 2088 mContext.enforcePermission(Manifest.permission.MANAGE_APPOPS, 2089 Binder.getCallingPid(), Binder.getCallingUid(), "getHistoricalOps"); 2090 2091 final String[] opNamesArray = (opNames != null) 2092 ? opNames.toArray(new String[opNames.size()]) : null; 2093 2094 // Must not hold the appops lock 2095 mHandler.post(PooledLambda.obtainRunnable(HistoricalRegistry::getHistoricalOpsFromDiskRaw, 2096 mHistoricalRegistry, uid, packageName, attributionTag, opNamesArray, 2097 filter, beginTimeMillis, endTimeMillis, flags, callback).recycleOnUse()); 2098 } 2099 2100 @Override reloadNonHistoricalState()2101 public void reloadNonHistoricalState() { 2102 mContext.enforcePermission(Manifest.permission.MANAGE_APPOPS, 2103 Binder.getCallingPid(), Binder.getCallingUid(), "reloadNonHistoricalState"); 2104 writeState(); 2105 readState(); 2106 } 2107 2108 @Override getUidOps(int uid, int[] ops)2109 public List<AppOpsManager.PackageOps> getUidOps(int uid, int[] ops) { 2110 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS, 2111 Binder.getCallingPid(), Binder.getCallingUid(), null); 2112 synchronized (this) { 2113 UidState uidState = getUidStateLocked(uid, false); 2114 if (uidState == null) { 2115 return null; 2116 } 2117 ArrayList<AppOpsManager.OpEntry> resOps = collectUidOps(uidState, ops); 2118 if (resOps == null) { 2119 return null; 2120 } 2121 ArrayList<AppOpsManager.PackageOps> res = new ArrayList<AppOpsManager.PackageOps>(); 2122 AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps( 2123 null, uidState.uid, resOps); 2124 res.add(resPackage); 2125 return res; 2126 } 2127 } 2128 pruneOpLocked(Op op, int uid, String packageName)2129 private void pruneOpLocked(Op op, int uid, String packageName) { 2130 op.removeAttributionsWithNoTime(); 2131 2132 if (op.mAttributions.isEmpty()) { 2133 Ops ops = getOpsLocked(uid, packageName, null, null, false /* edit */); 2134 if (ops != null) { 2135 ops.remove(op.op); 2136 if (ops.size() <= 0) { 2137 UidState uidState = ops.uidState; 2138 ArrayMap<String, Ops> pkgOps = uidState.pkgOps; 2139 if (pkgOps != null) { 2140 pkgOps.remove(ops.packageName); 2141 if (pkgOps.isEmpty()) { 2142 uidState.pkgOps = null; 2143 } 2144 if (uidState.isDefault()) { 2145 mUidStates.remove(uid); 2146 } 2147 } 2148 } 2149 } 2150 } 2151 } 2152 enforceManageAppOpsModes(int callingPid, int callingUid, int targetUid)2153 private void enforceManageAppOpsModes(int callingPid, int callingUid, int targetUid) { 2154 if (callingPid == Process.myPid()) { 2155 return; 2156 } 2157 final int callingUser = UserHandle.getUserId(callingUid); 2158 synchronized (this) { 2159 if (mProfileOwners != null && mProfileOwners.get(callingUser, -1) == callingUid) { 2160 if (targetUid >= 0 && callingUser == UserHandle.getUserId(targetUid)) { 2161 // Profile owners are allowed to change modes but only for apps 2162 // within their user. 2163 return; 2164 } 2165 } 2166 } 2167 mContext.enforcePermission(android.Manifest.permission.MANAGE_APP_OPS_MODES, 2168 Binder.getCallingPid(), Binder.getCallingUid(), null); 2169 } 2170 2171 @Override setUidMode(int code, int uid, int mode)2172 public void setUidMode(int code, int uid, int mode) { 2173 setUidMode(code, uid, mode, null); 2174 } 2175 setUidMode(int code, int uid, int mode, @Nullable IAppOpsCallback permissionPolicyCallback)2176 private void setUidMode(int code, int uid, int mode, 2177 @Nullable IAppOpsCallback permissionPolicyCallback) { 2178 if (DEBUG) { 2179 Slog.i(TAG, "uid " + uid + " OP_" + opToName(code) + " := " + modeToName(mode) 2180 + " by uid " + Binder.getCallingUid()); 2181 } 2182 2183 enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid); 2184 verifyIncomingOp(code); 2185 code = AppOpsManager.opToSwitch(code); 2186 2187 if (permissionPolicyCallback == null) { 2188 updatePermissionRevokedCompat(uid, code, mode); 2189 } 2190 2191 synchronized (this) { 2192 final int defaultMode = AppOpsManager.opToDefaultMode(code); 2193 2194 UidState uidState = getUidStateLocked(uid, false); 2195 if (uidState == null) { 2196 if (mode == defaultMode) { 2197 return; 2198 } 2199 uidState = new UidState(uid); 2200 uidState.opModes = new SparseIntArray(); 2201 uidState.opModes.put(code, mode); 2202 mUidStates.put(uid, uidState); 2203 scheduleWriteLocked(); 2204 } else if (uidState.opModes == null) { 2205 if (mode != defaultMode) { 2206 uidState.opModes = new SparseIntArray(); 2207 uidState.opModes.put(code, mode); 2208 scheduleWriteLocked(); 2209 } 2210 } else { 2211 if (uidState.opModes.indexOfKey(code) >= 0 && uidState.opModes.get(code) == mode) { 2212 return; 2213 } 2214 if (mode == defaultMode) { 2215 uidState.opModes.delete(code); 2216 if (uidState.opModes.size() <= 0) { 2217 uidState.opModes = null; 2218 } 2219 } else { 2220 uidState.opModes.put(code, mode); 2221 } 2222 scheduleWriteLocked(); 2223 } 2224 uidState.evalForegroundOps(mOpModeWatchers); 2225 } 2226 2227 notifyOpChangedForAllPkgsInUid(code, uid, false, permissionPolicyCallback); 2228 notifyOpChangedSync(code, uid, null, mode); 2229 } 2230 2231 /** 2232 * Notify that an op changed for all packages in an uid. 2233 * 2234 * @param code The op that changed 2235 * @param uid The uid the op was changed for 2236 * @param onlyForeground Only notify watchers that watch for foreground changes 2237 */ notifyOpChangedForAllPkgsInUid(int code, int uid, boolean onlyForeground, @Nullable IAppOpsCallback callbackToIgnore)2238 private void notifyOpChangedForAllPkgsInUid(int code, int uid, boolean onlyForeground, 2239 @Nullable IAppOpsCallback callbackToIgnore) { 2240 String[] uidPackageNames = getPackagesForUid(uid); 2241 ArrayMap<ModeCallback, ArraySet<String>> callbackSpecs = null; 2242 2243 synchronized (this) { 2244 ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code); 2245 if (callbacks != null) { 2246 final int callbackCount = callbacks.size(); 2247 for (int i = 0; i < callbackCount; i++) { 2248 ModeCallback callback = callbacks.valueAt(i); 2249 if (onlyForeground && (callback.mFlags & WATCH_FOREGROUND_CHANGES) == 0) { 2250 continue; 2251 } 2252 2253 ArraySet<String> changedPackages = new ArraySet<>(); 2254 Collections.addAll(changedPackages, uidPackageNames); 2255 if (callbackSpecs == null) { 2256 callbackSpecs = new ArrayMap<>(); 2257 } 2258 callbackSpecs.put(callback, changedPackages); 2259 } 2260 } 2261 2262 for (String uidPackageName : uidPackageNames) { 2263 callbacks = mPackageModeWatchers.get(uidPackageName); 2264 if (callbacks != null) { 2265 if (callbackSpecs == null) { 2266 callbackSpecs = new ArrayMap<>(); 2267 } 2268 final int callbackCount = callbacks.size(); 2269 for (int i = 0; i < callbackCount; i++) { 2270 ModeCallback callback = callbacks.valueAt(i); 2271 if (onlyForeground && (callback.mFlags & WATCH_FOREGROUND_CHANGES) == 0) { 2272 continue; 2273 } 2274 2275 ArraySet<String> changedPackages = callbackSpecs.get(callback); 2276 if (changedPackages == null) { 2277 changedPackages = new ArraySet<>(); 2278 callbackSpecs.put(callback, changedPackages); 2279 } 2280 changedPackages.add(uidPackageName); 2281 } 2282 } 2283 } 2284 2285 if (callbackSpecs != null && callbackToIgnore != null) { 2286 callbackSpecs.remove(mModeWatchers.get(callbackToIgnore.asBinder())); 2287 } 2288 } 2289 2290 if (callbackSpecs == null) { 2291 return; 2292 } 2293 2294 for (int i = 0; i < callbackSpecs.size(); i++) { 2295 final ModeCallback callback = callbackSpecs.keyAt(i); 2296 final ArraySet<String> reportedPackageNames = callbackSpecs.valueAt(i); 2297 if (reportedPackageNames == null) { 2298 mHandler.sendMessage(PooledLambda.obtainMessage( 2299 AppOpsService::notifyOpChanged, 2300 this, callback, code, uid, (String) null)); 2301 2302 } else { 2303 final int reportedPackageCount = reportedPackageNames.size(); 2304 for (int j = 0; j < reportedPackageCount; j++) { 2305 final String reportedPackageName = reportedPackageNames.valueAt(j); 2306 mHandler.sendMessage(PooledLambda.obtainMessage( 2307 AppOpsService::notifyOpChanged, 2308 this, callback, code, uid, reportedPackageName)); 2309 } 2310 } 2311 } 2312 } 2313 updatePermissionRevokedCompat(int uid, int switchCode, int mode)2314 private void updatePermissionRevokedCompat(int uid, int switchCode, int mode) { 2315 PackageManager packageManager = mContext.getPackageManager(); 2316 if (packageManager == null) { 2317 // This can only happen during early boot. At this time the permission state and appop 2318 // state are in sync 2319 return; 2320 } 2321 2322 String[] packageNames = packageManager.getPackagesForUid(uid); 2323 if (ArrayUtils.isEmpty(packageNames)) { 2324 return; 2325 } 2326 String packageName = packageNames[0]; 2327 2328 int[] ops = mSwitchedOps.get(switchCode); 2329 for (int code : ops) { 2330 String permissionName = AppOpsManager.opToPermission(code); 2331 if (permissionName == null) { 2332 continue; 2333 } 2334 2335 if (packageManager.checkPermission(permissionName, packageName) 2336 != PackageManager.PERMISSION_GRANTED) { 2337 continue; 2338 } 2339 2340 PermissionInfo permissionInfo; 2341 try { 2342 permissionInfo = packageManager.getPermissionInfo(permissionName, 0); 2343 } catch (PackageManager.NameNotFoundException e) { 2344 e.printStackTrace(); 2345 continue; 2346 } 2347 2348 if (!permissionInfo.isRuntime()) { 2349 continue; 2350 } 2351 2352 PackageManagerInternal packageManagerInternal = LocalServices.getService( 2353 PackageManagerInternal.class); 2354 boolean supportsRuntimePermissions = packageManagerInternal.getUidTargetSdkVersion(uid) 2355 >= Build.VERSION_CODES.M; 2356 2357 UserHandle user = UserHandle.getUserHandleForUid(uid); 2358 boolean isRevokedCompat; 2359 if (permissionInfo.backgroundPermission != null) { 2360 if (packageManager.checkPermission(permissionInfo.backgroundPermission, packageName) 2361 == PackageManager.PERMISSION_GRANTED) { 2362 boolean isBackgroundRevokedCompat = mode != AppOpsManager.MODE_ALLOWED; 2363 2364 if (isBackgroundRevokedCompat && supportsRuntimePermissions) { 2365 Slog.w(TAG, "setUidMode() called with a mode inconsistent with runtime" 2366 + " permission state, this is discouraged and you should revoke the" 2367 + " runtime permission instead: uid=" + uid + ", switchCode=" 2368 + switchCode + ", mode=" + mode + ", permission=" 2369 + permissionInfo.backgroundPermission); 2370 } 2371 2372 long identity = Binder.clearCallingIdentity(); 2373 try { 2374 packageManager.updatePermissionFlags(permissionInfo.backgroundPermission, 2375 packageName, PackageManager.FLAG_PERMISSION_REVOKED_COMPAT, 2376 isBackgroundRevokedCompat 2377 ? PackageManager.FLAG_PERMISSION_REVOKED_COMPAT : 0, user); 2378 } finally { 2379 Binder.restoreCallingIdentity(identity); 2380 } 2381 } 2382 2383 isRevokedCompat = mode != AppOpsManager.MODE_ALLOWED 2384 && mode != AppOpsManager.MODE_FOREGROUND; 2385 } else { 2386 isRevokedCompat = mode != AppOpsManager.MODE_ALLOWED; 2387 } 2388 2389 if (isRevokedCompat && supportsRuntimePermissions) { 2390 Slog.w(TAG, "setUidMode() called with a mode inconsistent with runtime" 2391 + " permission state, this is discouraged and you should revoke the" 2392 + " runtime permission instead: uid=" + uid + ", switchCode=" 2393 + switchCode + ", mode=" + mode + ", permission=" + permissionName); 2394 } 2395 2396 long identity = Binder.clearCallingIdentity(); 2397 try { 2398 packageManager.updatePermissionFlags(permissionName, packageName, 2399 PackageManager.FLAG_PERMISSION_REVOKED_COMPAT, isRevokedCompat 2400 ? PackageManager.FLAG_PERMISSION_REVOKED_COMPAT : 0, user); 2401 } finally { 2402 Binder.restoreCallingIdentity(identity); 2403 } 2404 } 2405 } 2406 notifyOpChangedSync(int code, int uid, @NonNull String packageName, int mode)2407 private void notifyOpChangedSync(int code, int uid, @NonNull String packageName, int mode) { 2408 final StorageManagerInternal storageManagerInternal = 2409 LocalServices.getService(StorageManagerInternal.class); 2410 if (storageManagerInternal != null) { 2411 storageManagerInternal.onAppOpsChanged(code, uid, packageName, mode); 2412 } 2413 } 2414 2415 /** 2416 * Sets the mode for a certain op and uid. 2417 * 2418 * @param code The op code to set 2419 * @param uid The UID for which to set 2420 * @param packageName The package for which to set 2421 * @param mode The new mode to set 2422 */ 2423 @Override setMode(int code, int uid, @NonNull String packageName, int mode)2424 public void setMode(int code, int uid, @NonNull String packageName, int mode) { 2425 setMode(code, uid, packageName, mode, null); 2426 } 2427 setMode(int code, int uid, @NonNull String packageName, int mode, @Nullable IAppOpsCallback permissionPolicyCallback)2428 private void setMode(int code, int uid, @NonNull String packageName, int mode, 2429 @Nullable IAppOpsCallback permissionPolicyCallback) { 2430 enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid); 2431 verifyIncomingOp(code); 2432 ArraySet<ModeCallback> repCbs = null; 2433 code = AppOpsManager.opToSwitch(code); 2434 2435 RestrictionBypass bypass; 2436 try { 2437 bypass = verifyAndGetBypass(uid, packageName, null); 2438 } catch (SecurityException e) { 2439 Slog.e(TAG, "Cannot setMode", e); 2440 return; 2441 } 2442 2443 synchronized (this) { 2444 UidState uidState = getUidStateLocked(uid, false); 2445 Op op = getOpLocked(code, uid, packageName, null, bypass, true); 2446 if (op != null) { 2447 if (op.mode != mode) { 2448 op.mode = mode; 2449 if (uidState != null) { 2450 uidState.evalForegroundOps(mOpModeWatchers); 2451 } 2452 ArraySet<ModeCallback> cbs = mOpModeWatchers.get(code); 2453 if (cbs != null) { 2454 if (repCbs == null) { 2455 repCbs = new ArraySet<>(); 2456 } 2457 repCbs.addAll(cbs); 2458 } 2459 cbs = mPackageModeWatchers.get(packageName); 2460 if (cbs != null) { 2461 if (repCbs == null) { 2462 repCbs = new ArraySet<>(); 2463 } 2464 repCbs.addAll(cbs); 2465 } 2466 if (repCbs != null && permissionPolicyCallback != null) { 2467 repCbs.remove(mModeWatchers.get(permissionPolicyCallback.asBinder())); 2468 } 2469 if (mode == AppOpsManager.opToDefaultMode(op.op)) { 2470 // If going into the default mode, prune this op 2471 // if there is nothing else interesting in it. 2472 pruneOpLocked(op, uid, packageName); 2473 } 2474 scheduleFastWriteLocked(); 2475 } 2476 } 2477 } 2478 if (repCbs != null) { 2479 mHandler.sendMessage(PooledLambda.obtainMessage( 2480 AppOpsService::notifyOpChanged, 2481 this, repCbs, code, uid, packageName)); 2482 } 2483 2484 notifyOpChangedSync(code, uid, packageName, mode); 2485 } 2486 notifyOpChanged(ArraySet<ModeCallback> callbacks, int code, int uid, String packageName)2487 private void notifyOpChanged(ArraySet<ModeCallback> callbacks, int code, 2488 int uid, String packageName) { 2489 for (int i = 0; i < callbacks.size(); i++) { 2490 final ModeCallback callback = callbacks.valueAt(i); 2491 notifyOpChanged(callback, code, uid, packageName); 2492 } 2493 } 2494 notifyOpChanged(ModeCallback callback, int code, int uid, String packageName)2495 private void notifyOpChanged(ModeCallback callback, int code, 2496 int uid, String packageName) { 2497 if (uid != UID_ANY && callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) { 2498 return; 2499 } 2500 2501 // See CALL_BACK_ON_CHANGED_LISTENER_WITH_SWITCHED_OP_CHANGE 2502 int[] switchedCodes; 2503 if (callback.mWatchedOpCode == ALL_OPS) { 2504 switchedCodes = mSwitchedOps.get(code); 2505 } else if (callback.mWatchedOpCode == OP_NONE) { 2506 switchedCodes = new int[]{code}; 2507 } else { 2508 switchedCodes = new int[]{callback.mWatchedOpCode}; 2509 } 2510 2511 for (int switchedCode : switchedCodes) { 2512 // There are features watching for mode changes such as window manager 2513 // and location manager which are in our process. The callbacks in these 2514 // features may require permissions our remote caller does not have. 2515 final long identity = Binder.clearCallingIdentity(); 2516 try { 2517 callback.mCallback.opChanged(switchedCode, uid, packageName); 2518 } catch (RemoteException e) { 2519 /* ignore */ 2520 } finally { 2521 Binder.restoreCallingIdentity(identity); 2522 } 2523 } 2524 } 2525 addChange(ArrayList<ChangeRec> reports, int op, int uid, String packageName)2526 private static ArrayList<ChangeRec> addChange(ArrayList<ChangeRec> reports, 2527 int op, int uid, String packageName) { 2528 boolean duplicate = false; 2529 if (reports == null) { 2530 reports = new ArrayList<>(); 2531 } else { 2532 final int reportCount = reports.size(); 2533 for (int j = 0; j < reportCount; j++) { 2534 ChangeRec report = reports.get(j); 2535 if (report.op == op && report.pkg.equals(packageName)) { 2536 duplicate = true; 2537 break; 2538 } 2539 } 2540 } 2541 if (!duplicate) { 2542 reports.add(new ChangeRec(op, uid, packageName)); 2543 } 2544 2545 return reports; 2546 } 2547 addCallbacks( HashMap<ModeCallback, ArrayList<ChangeRec>> callbacks, int op, int uid, String packageName, ArraySet<ModeCallback> cbs)2548 private static HashMap<ModeCallback, ArrayList<ChangeRec>> addCallbacks( 2549 HashMap<ModeCallback, ArrayList<ChangeRec>> callbacks, 2550 int op, int uid, String packageName, ArraySet<ModeCallback> cbs) { 2551 if (cbs == null) { 2552 return callbacks; 2553 } 2554 if (callbacks == null) { 2555 callbacks = new HashMap<>(); 2556 } 2557 final int N = cbs.size(); 2558 for (int i=0; i<N; i++) { 2559 ModeCallback cb = cbs.valueAt(i); 2560 ArrayList<ChangeRec> reports = callbacks.get(cb); 2561 ArrayList<ChangeRec> changed = addChange(reports, op, uid, packageName); 2562 if (changed != reports) { 2563 callbacks.put(cb, changed); 2564 } 2565 } 2566 return callbacks; 2567 } 2568 2569 static final class ChangeRec { 2570 final int op; 2571 final int uid; 2572 final String pkg; 2573 ChangeRec(int _op, int _uid, String _pkg)2574 ChangeRec(int _op, int _uid, String _pkg) { 2575 op = _op; 2576 uid = _uid; 2577 pkg = _pkg; 2578 } 2579 } 2580 2581 @Override resetAllModes(int reqUserId, String reqPackageName)2582 public void resetAllModes(int reqUserId, String reqPackageName) { 2583 final int callingPid = Binder.getCallingPid(); 2584 final int callingUid = Binder.getCallingUid(); 2585 reqUserId = ActivityManager.handleIncomingUser(callingPid, callingUid, reqUserId, 2586 true, true, "resetAllModes", null); 2587 2588 int reqUid = -1; 2589 if (reqPackageName != null) { 2590 try { 2591 reqUid = AppGlobals.getPackageManager().getPackageUid( 2592 reqPackageName, PackageManager.MATCH_UNINSTALLED_PACKAGES, reqUserId); 2593 } catch (RemoteException e) { 2594 /* ignore - local call */ 2595 } 2596 } 2597 2598 enforceManageAppOpsModes(callingPid, callingUid, reqUid); 2599 2600 HashMap<ModeCallback, ArrayList<ChangeRec>> callbacks = null; 2601 ArrayList<ChangeRec> allChanges = new ArrayList<>(); 2602 synchronized (this) { 2603 boolean changed = false; 2604 for (int i = mUidStates.size() - 1; i >= 0; i--) { 2605 UidState uidState = mUidStates.valueAt(i); 2606 2607 SparseIntArray opModes = uidState.opModes; 2608 if (opModes != null && (uidState.uid == reqUid || reqUid == -1)) { 2609 final int uidOpCount = opModes.size(); 2610 for (int j = uidOpCount - 1; j >= 0; j--) { 2611 final int code = opModes.keyAt(j); 2612 if (AppOpsManager.opAllowsReset(code)) { 2613 opModes.removeAt(j); 2614 if (opModes.size() <= 0) { 2615 uidState.opModes = null; 2616 } 2617 for (String packageName : getPackagesForUid(uidState.uid)) { 2618 callbacks = addCallbacks(callbacks, code, uidState.uid, packageName, 2619 mOpModeWatchers.get(code)); 2620 callbacks = addCallbacks(callbacks, code, uidState.uid, packageName, 2621 mPackageModeWatchers.get(packageName)); 2622 2623 allChanges = addChange(allChanges, code, uidState.uid, 2624 packageName); 2625 } 2626 } 2627 } 2628 } 2629 2630 if (uidState.pkgOps == null) { 2631 continue; 2632 } 2633 2634 if (reqUserId != UserHandle.USER_ALL 2635 && reqUserId != UserHandle.getUserId(uidState.uid)) { 2636 // Skip any ops for a different user 2637 continue; 2638 } 2639 2640 Map<String, Ops> packages = uidState.pkgOps; 2641 Iterator<Map.Entry<String, Ops>> it = packages.entrySet().iterator(); 2642 boolean uidChanged = false; 2643 while (it.hasNext()) { 2644 Map.Entry<String, Ops> ent = it.next(); 2645 String packageName = ent.getKey(); 2646 if (reqPackageName != null && !reqPackageName.equals(packageName)) { 2647 // Skip any ops for a different package 2648 continue; 2649 } 2650 Ops pkgOps = ent.getValue(); 2651 for (int j=pkgOps.size()-1; j>=0; j--) { 2652 Op curOp = pkgOps.valueAt(j); 2653 if (AppOpsManager.opAllowsReset(curOp.op) 2654 && curOp.mode != AppOpsManager.opToDefaultMode(curOp.op)) { 2655 curOp.mode = AppOpsManager.opToDefaultMode(curOp.op); 2656 changed = true; 2657 uidChanged = true; 2658 final int uid = curOp.uidState.uid; 2659 callbacks = addCallbacks(callbacks, curOp.op, uid, packageName, 2660 mOpModeWatchers.get(curOp.op)); 2661 callbacks = addCallbacks(callbacks, curOp.op, uid, packageName, 2662 mPackageModeWatchers.get(packageName)); 2663 2664 allChanges = addChange(allChanges, curOp.op, uid, packageName); 2665 curOp.removeAttributionsWithNoTime(); 2666 if (curOp.mAttributions.isEmpty()) { 2667 pkgOps.removeAt(j); 2668 } 2669 } 2670 } 2671 if (pkgOps.size() == 0) { 2672 it.remove(); 2673 } 2674 } 2675 if (uidState.isDefault()) { 2676 mUidStates.remove(uidState.uid); 2677 } 2678 if (uidChanged) { 2679 uidState.evalForegroundOps(mOpModeWatchers); 2680 } 2681 } 2682 2683 if (changed) { 2684 scheduleFastWriteLocked(); 2685 } 2686 } 2687 if (callbacks != null) { 2688 for (Map.Entry<ModeCallback, ArrayList<ChangeRec>> ent : callbacks.entrySet()) { 2689 ModeCallback cb = ent.getKey(); 2690 ArrayList<ChangeRec> reports = ent.getValue(); 2691 for (int i=0; i<reports.size(); i++) { 2692 ChangeRec rep = reports.get(i); 2693 mHandler.sendMessage(PooledLambda.obtainMessage( 2694 AppOpsService::notifyOpChanged, 2695 this, cb, rep.op, rep.uid, rep.pkg)); 2696 } 2697 } 2698 } 2699 2700 if (allChanges != null) { 2701 int numChanges = allChanges.size(); 2702 for (int i = 0; i < numChanges; i++) { 2703 ChangeRec change = allChanges.get(i); 2704 notifyOpChangedSync(change.op, change.uid, change.pkg, 2705 AppOpsManager.opToDefaultMode(change.op)); 2706 } 2707 } 2708 } 2709 evalAllForegroundOpsLocked()2710 private void evalAllForegroundOpsLocked() { 2711 for (int uidi = mUidStates.size() - 1; uidi >= 0; uidi--) { 2712 final UidState uidState = mUidStates.valueAt(uidi); 2713 if (uidState.foregroundOps != null) { 2714 uidState.evalForegroundOps(mOpModeWatchers); 2715 } 2716 } 2717 } 2718 2719 @Override startWatchingMode(int op, String packageName, IAppOpsCallback callback)2720 public void startWatchingMode(int op, String packageName, IAppOpsCallback callback) { 2721 startWatchingModeWithFlags(op, packageName, 0, callback); 2722 } 2723 2724 @Override startWatchingModeWithFlags(int op, String packageName, int flags, IAppOpsCallback callback)2725 public void startWatchingModeWithFlags(int op, String packageName, int flags, 2726 IAppOpsCallback callback) { 2727 int watchedUid = -1; 2728 final int callingUid = Binder.getCallingUid(); 2729 final int callingPid = Binder.getCallingPid(); 2730 // TODO: should have a privileged permission to protect this. 2731 // Also, if the caller has requested WATCH_FOREGROUND_CHANGES, should we require 2732 // the USAGE_STATS permission since this can provide information about when an 2733 // app is in the foreground? 2734 Preconditions.checkArgumentInRange(op, AppOpsManager.OP_NONE, 2735 AppOpsManager._NUM_OP - 1, "Invalid op code: " + op); 2736 if (callback == null) { 2737 return; 2738 } 2739 synchronized (this) { 2740 int switchOp = (op != AppOpsManager.OP_NONE) ? AppOpsManager.opToSwitch(op) : op; 2741 2742 int notifiedOps; 2743 if ((flags & CALL_BACK_ON_SWITCHED_OP) == 0) { 2744 if (op == OP_NONE) { 2745 notifiedOps = ALL_OPS; 2746 } else { 2747 notifiedOps = op; 2748 } 2749 } else { 2750 notifiedOps = switchOp; 2751 } 2752 2753 ModeCallback cb = mModeWatchers.get(callback.asBinder()); 2754 if (cb == null) { 2755 cb = new ModeCallback(callback, watchedUid, flags, notifiedOps, callingUid, 2756 callingPid); 2757 mModeWatchers.put(callback.asBinder(), cb); 2758 } 2759 if (switchOp != AppOpsManager.OP_NONE) { 2760 ArraySet<ModeCallback> cbs = mOpModeWatchers.get(switchOp); 2761 if (cbs == null) { 2762 cbs = new ArraySet<>(); 2763 mOpModeWatchers.put(switchOp, cbs); 2764 } 2765 cbs.add(cb); 2766 } 2767 if (packageName != null) { 2768 ArraySet<ModeCallback> cbs = mPackageModeWatchers.get(packageName); 2769 if (cbs == null) { 2770 cbs = new ArraySet<>(); 2771 mPackageModeWatchers.put(packageName, cbs); 2772 } 2773 cbs.add(cb); 2774 } 2775 evalAllForegroundOpsLocked(); 2776 } 2777 } 2778 2779 @Override stopWatchingMode(IAppOpsCallback callback)2780 public void stopWatchingMode(IAppOpsCallback callback) { 2781 if (callback == null) { 2782 return; 2783 } 2784 synchronized (this) { 2785 ModeCallback cb = mModeWatchers.remove(callback.asBinder()); 2786 if (cb != null) { 2787 cb.unlinkToDeath(); 2788 for (int i=mOpModeWatchers.size()-1; i>=0; i--) { 2789 ArraySet<ModeCallback> cbs = mOpModeWatchers.valueAt(i); 2790 cbs.remove(cb); 2791 if (cbs.size() <= 0) { 2792 mOpModeWatchers.removeAt(i); 2793 } 2794 } 2795 for (int i=mPackageModeWatchers.size()-1; i>=0; i--) { 2796 ArraySet<ModeCallback> cbs = mPackageModeWatchers.valueAt(i); 2797 cbs.remove(cb); 2798 if (cbs.size() <= 0) { 2799 mPackageModeWatchers.removeAt(i); 2800 } 2801 } 2802 } 2803 evalAllForegroundOpsLocked(); 2804 } 2805 } 2806 getAppOpsServiceDelegate()2807 public CheckOpsDelegate getAppOpsServiceDelegate() { 2808 synchronized (this) { 2809 return mCheckOpsDelegate; 2810 } 2811 } 2812 setAppOpsServiceDelegate(CheckOpsDelegate delegate)2813 public void setAppOpsServiceDelegate(CheckOpsDelegate delegate) { 2814 synchronized (this) { 2815 mCheckOpsDelegate = delegate; 2816 } 2817 } 2818 2819 @Override checkOperationRaw(int code, int uid, String packageName)2820 public int checkOperationRaw(int code, int uid, String packageName) { 2821 return checkOperationInternal(code, uid, packageName, true /*raw*/); 2822 } 2823 2824 @Override checkOperation(int code, int uid, String packageName)2825 public int checkOperation(int code, int uid, String packageName) { 2826 return checkOperationInternal(code, uid, packageName, false /*raw*/); 2827 } 2828 checkOperationInternal(int code, int uid, String packageName, boolean raw)2829 private int checkOperationInternal(int code, int uid, String packageName, boolean raw) { 2830 final CheckOpsDelegate delegate; 2831 synchronized (this) { 2832 delegate = mCheckOpsDelegate; 2833 } 2834 if (delegate == null) { 2835 return checkOperationImpl(code, uid, packageName, raw); 2836 } 2837 return delegate.checkOperation(code, uid, packageName, raw, 2838 AppOpsService.this::checkOperationImpl); 2839 } 2840 checkOperationImpl(int code, int uid, String packageName, boolean raw)2841 private int checkOperationImpl(int code, int uid, String packageName, 2842 boolean raw) { 2843 verifyIncomingOp(code); 2844 String resolvedPackageName = resolvePackageName(uid, packageName); 2845 if (resolvedPackageName == null) { 2846 return AppOpsManager.MODE_IGNORED; 2847 } 2848 return checkOperationUnchecked(code, uid, resolvedPackageName, raw); 2849 } 2850 2851 /** 2852 * Get the mode of an app-op. 2853 * 2854 * @param code The code of the op 2855 * @param uid The uid of the package the op belongs to 2856 * @param packageName The package the op belongs to 2857 * @param raw If the raw state of eval-ed state should be checked. 2858 * 2859 * @return The mode of the op 2860 */ checkOperationUnchecked(int code, int uid, @NonNull String packageName, boolean raw)2861 private @Mode int checkOperationUnchecked(int code, int uid, @NonNull String packageName, 2862 boolean raw) { 2863 RestrictionBypass bypass; 2864 try { 2865 bypass = verifyAndGetBypass(uid, packageName, null); 2866 } catch (SecurityException e) { 2867 Slog.e(TAG, "checkOperation", e); 2868 return AppOpsManager.opToDefaultMode(code); 2869 } 2870 2871 if (isOpRestrictedDueToSuspend(code, packageName, uid)) { 2872 return AppOpsManager.MODE_IGNORED; 2873 } 2874 synchronized (this) { 2875 if (isOpRestrictedLocked(uid, code, packageName, bypass)) { 2876 return AppOpsManager.MODE_IGNORED; 2877 } 2878 code = AppOpsManager.opToSwitch(code); 2879 UidState uidState = getUidStateLocked(uid, false); 2880 if (uidState != null && uidState.opModes != null 2881 && uidState.opModes.indexOfKey(code) >= 0) { 2882 final int rawMode = uidState.opModes.get(code); 2883 return raw ? rawMode : uidState.evalMode(code, rawMode); 2884 } 2885 Op op = getOpLocked(code, uid, packageName, null, bypass, false); 2886 if (op == null) { 2887 return AppOpsManager.opToDefaultMode(code); 2888 } 2889 return raw ? op.mode : op.evalMode(); 2890 } 2891 } 2892 2893 @Override checkAudioOperation(int code, int usage, int uid, String packageName)2894 public int checkAudioOperation(int code, int usage, int uid, String packageName) { 2895 final CheckOpsDelegate delegate; 2896 synchronized (this) { 2897 delegate = mCheckOpsDelegate; 2898 } 2899 if (delegate == null) { 2900 return checkAudioOperationImpl(code, usage, uid, packageName); 2901 } 2902 return delegate.checkAudioOperation(code, usage, uid, packageName, 2903 AppOpsService.this::checkAudioOperationImpl); 2904 } 2905 checkAudioOperationImpl(int code, int usage, int uid, String packageName)2906 private int checkAudioOperationImpl(int code, int usage, int uid, String packageName) { 2907 final int mode = mAudioRestrictionManager.checkAudioOperation( 2908 code, usage, uid, packageName); 2909 if (mode != AppOpsManager.MODE_ALLOWED) { 2910 return mode; 2911 } 2912 return checkOperation(code, uid, packageName); 2913 } 2914 2915 @Override setAudioRestriction(int code, int usage, int uid, int mode, String[] exceptionPackages)2916 public void setAudioRestriction(int code, int usage, int uid, int mode, 2917 String[] exceptionPackages) { 2918 enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid); 2919 verifyIncomingUid(uid); 2920 verifyIncomingOp(code); 2921 2922 mAudioRestrictionManager.setZenModeAudioRestriction( 2923 code, usage, uid, mode, exceptionPackages); 2924 2925 mHandler.sendMessage(PooledLambda.obtainMessage( 2926 AppOpsService::notifyWatchersOfChange, this, code, UID_ANY)); 2927 } 2928 2929 2930 @Override setCameraAudioRestriction(@AMERA_AUDIO_RESTRICTION int mode)2931 public void setCameraAudioRestriction(@CAMERA_AUDIO_RESTRICTION int mode) { 2932 enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), -1); 2933 2934 mAudioRestrictionManager.setCameraAudioRestriction(mode); 2935 2936 mHandler.sendMessage(PooledLambda.obtainMessage( 2937 AppOpsService::notifyWatchersOfChange, this, 2938 AppOpsManager.OP_PLAY_AUDIO, UID_ANY)); 2939 mHandler.sendMessage(PooledLambda.obtainMessage( 2940 AppOpsService::notifyWatchersOfChange, this, 2941 AppOpsManager.OP_VIBRATE, UID_ANY)); 2942 } 2943 2944 @Override checkPackage(int uid, String packageName)2945 public int checkPackage(int uid, String packageName) { 2946 Objects.requireNonNull(packageName); 2947 try { 2948 verifyAndGetBypass(uid, packageName, null); 2949 2950 return AppOpsManager.MODE_ALLOWED; 2951 } catch (SecurityException ignored) { 2952 return AppOpsManager.MODE_ERRORED; 2953 } 2954 } 2955 2956 @Override noteProxyOperation(int code, int proxiedUid, String proxiedPackageName, String proxiedAttributionTag, int proxyUid, String proxyPackageName, String proxyAttributionTag, boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage)2957 public int noteProxyOperation(int code, int proxiedUid, String proxiedPackageName, 2958 String proxiedAttributionTag, int proxyUid, String proxyPackageName, 2959 String proxyAttributionTag, boolean shouldCollectAsyncNotedOp, String message, 2960 boolean shouldCollectMessage) { 2961 verifyIncomingUid(proxyUid); 2962 verifyIncomingOp(code); 2963 2964 String resolveProxyPackageName = resolvePackageName(proxyUid, proxyPackageName); 2965 if (resolveProxyPackageName == null) { 2966 return AppOpsManager.MODE_IGNORED; 2967 } 2968 2969 final boolean isProxyTrusted = mContext.checkPermission( 2970 Manifest.permission.UPDATE_APP_OPS_STATS, -1, proxyUid) 2971 == PackageManager.PERMISSION_GRANTED; 2972 2973 final int proxyFlags = isProxyTrusted ? AppOpsManager.OP_FLAG_TRUSTED_PROXY 2974 : AppOpsManager.OP_FLAG_UNTRUSTED_PROXY; 2975 final int proxyMode = noteOperationUnchecked(code, proxyUid, resolveProxyPackageName, 2976 proxyAttributionTag, Process.INVALID_UID, null, null, proxyFlags, 2977 !isProxyTrusted, "proxy " + message, shouldCollectMessage); 2978 if (proxyMode != AppOpsManager.MODE_ALLOWED || Binder.getCallingUid() == proxiedUid) { 2979 return proxyMode; 2980 } 2981 2982 String resolveProxiedPackageName = resolvePackageName(proxiedUid, proxiedPackageName); 2983 if (resolveProxiedPackageName == null) { 2984 return AppOpsManager.MODE_IGNORED; 2985 } 2986 final int proxiedFlags = isProxyTrusted ? AppOpsManager.OP_FLAG_TRUSTED_PROXIED 2987 : AppOpsManager.OP_FLAG_UNTRUSTED_PROXIED; 2988 return noteOperationUnchecked(code, proxiedUid, resolveProxiedPackageName, 2989 proxiedAttributionTag, proxyUid, resolveProxyPackageName, proxyAttributionTag, 2990 proxiedFlags, shouldCollectAsyncNotedOp, message, shouldCollectMessage); 2991 } 2992 2993 @Override noteOperation(int code, int uid, String packageName, String attributionTag, boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage)2994 public int noteOperation(int code, int uid, String packageName, String attributionTag, 2995 boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage) { 2996 final CheckOpsDelegate delegate; 2997 synchronized (this) { 2998 delegate = mCheckOpsDelegate; 2999 } 3000 if (delegate == null) { 3001 return noteOperationImpl(code, uid, packageName, attributionTag, 3002 shouldCollectAsyncNotedOp, message, shouldCollectMessage); 3003 } 3004 return delegate.noteOperation(code, uid, packageName, attributionTag, 3005 shouldCollectAsyncNotedOp, message, shouldCollectMessage, 3006 AppOpsService.this::noteOperationImpl); 3007 } 3008 noteOperationImpl(int code, int uid, @Nullable String packageName, @Nullable String attributionTag, boolean shouldCollectAsyncNotedOp, @Nullable String message, boolean shouldCollectMessage)3009 private int noteOperationImpl(int code, int uid, @Nullable String packageName, 3010 @Nullable String attributionTag, boolean shouldCollectAsyncNotedOp, 3011 @Nullable String message, boolean shouldCollectMessage) { 3012 verifyIncomingUid(uid); 3013 verifyIncomingOp(code); 3014 String resolvedPackageName = resolvePackageName(uid, packageName); 3015 if (resolvedPackageName == null) { 3016 return AppOpsManager.MODE_IGNORED; 3017 } 3018 return noteOperationUnchecked(code, uid, resolvedPackageName, attributionTag, 3019 Process.INVALID_UID, null, null, AppOpsManager.OP_FLAG_SELF, 3020 shouldCollectAsyncNotedOp, message, shouldCollectMessage); 3021 } 3022 noteOperationUnchecked(int code, int uid, @NonNull String packageName, @Nullable String attributionTag, int proxyUid, String proxyPackageName, @Nullable String proxyAttributionTag, @OpFlags int flags, boolean shouldCollectAsyncNotedOp, @Nullable String message, boolean shouldCollectMessage)3023 private int noteOperationUnchecked(int code, int uid, @NonNull String packageName, 3024 @Nullable String attributionTag, int proxyUid, String proxyPackageName, 3025 @Nullable String proxyAttributionTag, @OpFlags int flags, 3026 boolean shouldCollectAsyncNotedOp, @Nullable String message, 3027 boolean shouldCollectMessage) { 3028 RestrictionBypass bypass; 3029 try { 3030 bypass = verifyAndGetBypass(uid, packageName, attributionTag); 3031 } catch (SecurityException e) { 3032 Slog.e(TAG, "noteOperation", e); 3033 return AppOpsManager.MODE_ERRORED; 3034 } 3035 3036 synchronized (this) { 3037 final Ops ops = getOpsLocked(uid, packageName, attributionTag, bypass, 3038 true /* edit */); 3039 if (ops == null) { 3040 scheduleOpNotedIfNeededLocked(code, uid, packageName, 3041 AppOpsManager.MODE_IGNORED); 3042 if (DEBUG) Slog.d(TAG, "noteOperation: no op for code " + code + " uid " + uid 3043 + " package " + packageName); 3044 return AppOpsManager.MODE_ERRORED; 3045 } 3046 final Op op = getOpLocked(ops, code, uid, true); 3047 if (isOpRestrictedLocked(uid, code, packageName, bypass)) { 3048 scheduleOpNotedIfNeededLocked(code, uid, packageName, 3049 AppOpsManager.MODE_IGNORED); 3050 return AppOpsManager.MODE_IGNORED; 3051 } 3052 final AttributedOp attributedOp = op.getOrCreateAttribution(op, attributionTag); 3053 if (attributedOp.isRunning()) { 3054 Slog.w(TAG, "Noting op not finished: uid " + uid + " pkg " + packageName + " code " 3055 + code + " startTime of in progress event=" 3056 + attributedOp.mInProgressEvents.valueAt(0).getStartTime()); 3057 } 3058 3059 final int switchCode = AppOpsManager.opToSwitch(code); 3060 final UidState uidState = ops.uidState; 3061 // If there is a non-default per UID policy (we set UID op mode only if 3062 // non-default) it takes over, otherwise use the per package policy. 3063 if (uidState.opModes != null && uidState.opModes.indexOfKey(switchCode) >= 0) { 3064 final int uidMode = uidState.evalMode(code, uidState.opModes.get(switchCode)); 3065 if (uidMode != AppOpsManager.MODE_ALLOWED) { 3066 if (DEBUG) Slog.d(TAG, "noteOperation: uid reject #" + uidMode + " for code " 3067 + switchCode + " (" + code + ") uid " + uid + " package " 3068 + packageName); 3069 attributedOp.rejected(uidState.state, flags); 3070 scheduleOpNotedIfNeededLocked(code, uid, packageName, uidMode); 3071 return uidMode; 3072 } 3073 } else { 3074 final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, uid, true) 3075 : op; 3076 final int mode = switchOp.evalMode(); 3077 if (mode != AppOpsManager.MODE_ALLOWED) { 3078 if (DEBUG) Slog.d(TAG, "noteOperation: reject #" + mode + " for code " 3079 + switchCode + " (" + code + ") uid " + uid + " package " 3080 + packageName); 3081 attributedOp.rejected(uidState.state, flags); 3082 scheduleOpNotedIfNeededLocked(code, uid, packageName, mode); 3083 return mode; 3084 } 3085 } 3086 if (DEBUG) { 3087 Slog.d(TAG, 3088 "noteOperation: allowing code " + code + " uid " + uid + " package " 3089 + packageName + (attributionTag == null ? "" 3090 : "." + attributionTag)); 3091 } 3092 scheduleOpNotedIfNeededLocked(code, uid, packageName, AppOpsManager.MODE_ALLOWED); 3093 attributedOp.accessed(proxyUid, proxyPackageName, proxyAttributionTag, uidState.state, 3094 flags); 3095 3096 if (shouldCollectAsyncNotedOp) { 3097 collectAsyncNotedOp(uid, packageName, code, attributionTag, flags, message, 3098 shouldCollectMessage); 3099 } 3100 3101 return AppOpsManager.MODE_ALLOWED; 3102 } 3103 } 3104 3105 // TODO moltmann: Allow watching for attribution ops 3106 @Override startWatchingActive(int[] ops, IAppOpsActiveCallback callback)3107 public void startWatchingActive(int[] ops, IAppOpsActiveCallback callback) { 3108 int watchedUid = Process.INVALID_UID; 3109 final int callingUid = Binder.getCallingUid(); 3110 final int callingPid = Binder.getCallingPid(); 3111 if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS) 3112 != PackageManager.PERMISSION_GRANTED) { 3113 watchedUid = callingUid; 3114 } 3115 if (ops != null) { 3116 Preconditions.checkArrayElementsInRange(ops, 0, 3117 AppOpsManager._NUM_OP - 1, "Invalid op code in: " + Arrays.toString(ops)); 3118 } 3119 if (callback == null) { 3120 return; 3121 } 3122 synchronized (this) { 3123 SparseArray<ActiveCallback> callbacks = mActiveWatchers.get(callback.asBinder()); 3124 if (callbacks == null) { 3125 callbacks = new SparseArray<>(); 3126 mActiveWatchers.put(callback.asBinder(), callbacks); 3127 } 3128 final ActiveCallback activeCallback = new ActiveCallback(callback, watchedUid, 3129 callingUid, callingPid); 3130 for (int op : ops) { 3131 callbacks.put(op, activeCallback); 3132 } 3133 } 3134 } 3135 3136 @Override stopWatchingActive(IAppOpsActiveCallback callback)3137 public void stopWatchingActive(IAppOpsActiveCallback callback) { 3138 if (callback == null) { 3139 return; 3140 } 3141 synchronized (this) { 3142 final SparseArray<ActiveCallback> activeCallbacks = 3143 mActiveWatchers.remove(callback.asBinder()); 3144 if (activeCallbacks == null) { 3145 return; 3146 } 3147 final int callbackCount = activeCallbacks.size(); 3148 for (int i = 0; i < callbackCount; i++) { 3149 activeCallbacks.valueAt(i).destroy(); 3150 } 3151 } 3152 } 3153 3154 @Override startWatchingStarted(int[] ops, @NonNull IAppOpsStartedCallback callback)3155 public void startWatchingStarted(int[] ops, @NonNull IAppOpsStartedCallback callback) { 3156 int watchedUid = Process.INVALID_UID; 3157 final int callingUid = Binder.getCallingUid(); 3158 final int callingPid = Binder.getCallingPid(); 3159 if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS) 3160 != PackageManager.PERMISSION_GRANTED) { 3161 watchedUid = callingUid; 3162 } 3163 3164 Preconditions.checkArgument(!ArrayUtils.isEmpty(ops), "Ops cannot be null or empty"); 3165 Preconditions.checkArrayElementsInRange(ops, 0, AppOpsManager._NUM_OP - 1, 3166 "Invalid op code in: " + Arrays.toString(ops)); 3167 Objects.requireNonNull(callback, "Callback cannot be null"); 3168 3169 synchronized (this) { 3170 SparseArray<StartedCallback> callbacks = mStartedWatchers.get(callback.asBinder()); 3171 if (callbacks == null) { 3172 callbacks = new SparseArray<>(); 3173 mStartedWatchers.put(callback.asBinder(), callbacks); 3174 } 3175 3176 final StartedCallback startedCallback = new StartedCallback(callback, watchedUid, 3177 callingUid, callingPid); 3178 for (int op : ops) { 3179 callbacks.put(op, startedCallback); 3180 } 3181 } 3182 } 3183 3184 @Override stopWatchingStarted(IAppOpsStartedCallback callback)3185 public void stopWatchingStarted(IAppOpsStartedCallback callback) { 3186 Objects.requireNonNull(callback, "Callback cannot be null"); 3187 3188 synchronized (this) { 3189 final SparseArray<StartedCallback> startedCallbacks = 3190 mStartedWatchers.remove(callback.asBinder()); 3191 if (startedCallbacks == null) { 3192 return; 3193 } 3194 3195 final int callbackCount = startedCallbacks.size(); 3196 for (int i = 0; i < callbackCount; i++) { 3197 startedCallbacks.valueAt(i).destroy(); 3198 } 3199 } 3200 } 3201 3202 @Override startWatchingNoted(@onNull int[] ops, @NonNull IAppOpsNotedCallback callback)3203 public void startWatchingNoted(@NonNull int[] ops, @NonNull IAppOpsNotedCallback callback) { 3204 int watchedUid = Process.INVALID_UID; 3205 final int callingUid = Binder.getCallingUid(); 3206 final int callingPid = Binder.getCallingPid(); 3207 if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS) 3208 != PackageManager.PERMISSION_GRANTED) { 3209 watchedUid = callingUid; 3210 } 3211 Preconditions.checkArgument(!ArrayUtils.isEmpty(ops), "Ops cannot be null or empty"); 3212 Preconditions.checkArrayElementsInRange(ops, 0, AppOpsManager._NUM_OP - 1, 3213 "Invalid op code in: " + Arrays.toString(ops)); 3214 Objects.requireNonNull(callback, "Callback cannot be null"); 3215 synchronized (this) { 3216 SparseArray<NotedCallback> callbacks = mNotedWatchers.get(callback.asBinder()); 3217 if (callbacks == null) { 3218 callbacks = new SparseArray<>(); 3219 mNotedWatchers.put(callback.asBinder(), callbacks); 3220 } 3221 final NotedCallback notedCallback = new NotedCallback(callback, watchedUid, 3222 callingUid, callingPid); 3223 for (int op : ops) { 3224 callbacks.put(op, notedCallback); 3225 } 3226 } 3227 } 3228 3229 @Override stopWatchingNoted(IAppOpsNotedCallback callback)3230 public void stopWatchingNoted(IAppOpsNotedCallback callback) { 3231 Objects.requireNonNull(callback, "Callback cannot be null"); 3232 synchronized (this) { 3233 final SparseArray<NotedCallback> notedCallbacks = 3234 mNotedWatchers.remove(callback.asBinder()); 3235 if (notedCallbacks == null) { 3236 return; 3237 } 3238 final int callbackCount = notedCallbacks.size(); 3239 for (int i = 0; i < callbackCount; i++) { 3240 notedCallbacks.valueAt(i).destroy(); 3241 } 3242 } 3243 } 3244 3245 /** 3246 * Collect an {@link AsyncNotedAppOp}. 3247 * 3248 * @param uid The uid the op was noted for 3249 * @param packageName The package the op was noted for 3250 * @param opCode The code of the op noted 3251 * @param attributionTag attribution tag the op was noted for 3252 * @param message The message for the op noting 3253 */ collectAsyncNotedOp(int uid, @NonNull String packageName, int opCode, @Nullable String attributionTag, @OpFlags int flags, @NonNull String message, boolean shouldCollectMessage)3254 private void collectAsyncNotedOp(int uid, @NonNull String packageName, int opCode, 3255 @Nullable String attributionTag, @OpFlags int flags, @NonNull String message, 3256 boolean shouldCollectMessage) { 3257 Objects.requireNonNull(message); 3258 3259 int callingUid = Binder.getCallingUid(); 3260 3261 long token = Binder.clearCallingIdentity(); 3262 try { 3263 synchronized (this) { 3264 Pair<String, Integer> key = getAsyncNotedOpsKey(packageName, uid); 3265 3266 RemoteCallbackList<IAppOpsAsyncNotedCallback> callbacks = mAsyncOpWatchers.get(key); 3267 AsyncNotedAppOp asyncNotedOp = new AsyncNotedAppOp(opCode, callingUid, 3268 attributionTag, message, System.currentTimeMillis()); 3269 final boolean[] wasNoteForwarded = {false}; 3270 3271 if ((flags & (OP_FLAG_SELF | OP_FLAG_TRUSTED_PROXIED)) != 0 3272 && shouldCollectMessage) { 3273 reportRuntimeAppOpAccessMessageAsyncLocked(uid, packageName, opCode, 3274 attributionTag, message); 3275 } 3276 3277 if (callbacks != null) { 3278 callbacks.broadcast((cb) -> { 3279 try { 3280 cb.opNoted(asyncNotedOp); 3281 wasNoteForwarded[0] = true; 3282 } catch (RemoteException e) { 3283 Slog.e(TAG, 3284 "Could not forward noteOp of " + opCode + " to " + packageName 3285 + "/" + uid + "(" + attributionTag + ")", e); 3286 } 3287 }); 3288 } 3289 3290 if (!wasNoteForwarded[0]) { 3291 ArrayList<AsyncNotedAppOp> unforwardedOps = mUnforwardedAsyncNotedOps.get(key); 3292 if (unforwardedOps == null) { 3293 unforwardedOps = new ArrayList<>(1); 3294 mUnforwardedAsyncNotedOps.put(key, unforwardedOps); 3295 } 3296 3297 unforwardedOps.add(asyncNotedOp); 3298 if (unforwardedOps.size() > MAX_UNFORWARDED_OPS) { 3299 unforwardedOps.remove(0); 3300 } 3301 } 3302 } 3303 } finally { 3304 Binder.restoreCallingIdentity(token); 3305 } 3306 } 3307 3308 /** 3309 * Compute a key to be used in {@link #mAsyncOpWatchers} and {@link #mUnforwardedAsyncNotedOps} 3310 * 3311 * @param packageName The package name of the app 3312 * @param uid The uid of the app 3313 * 3314 * @return They key uniquely identifying the app 3315 */ getAsyncNotedOpsKey(@onNull String packageName, int uid)3316 private @NonNull Pair<String, Integer> getAsyncNotedOpsKey(@NonNull String packageName, 3317 int uid) { 3318 return new Pair<>(packageName, uid); 3319 } 3320 3321 @Override startWatchingAsyncNoted(String packageName, IAppOpsAsyncNotedCallback callback)3322 public void startWatchingAsyncNoted(String packageName, IAppOpsAsyncNotedCallback callback) { 3323 Objects.requireNonNull(packageName); 3324 Objects.requireNonNull(callback); 3325 3326 int uid = Binder.getCallingUid(); 3327 Pair<String, Integer> key = getAsyncNotedOpsKey(packageName, uid); 3328 3329 verifyAndGetBypass(uid, packageName, null); 3330 3331 synchronized (this) { 3332 RemoteCallbackList<IAppOpsAsyncNotedCallback> callbacks = mAsyncOpWatchers.get(key); 3333 if (callbacks == null) { 3334 callbacks = new RemoteCallbackList<IAppOpsAsyncNotedCallback>() { 3335 @Override 3336 public void onCallbackDied(IAppOpsAsyncNotedCallback callback) { 3337 synchronized (AppOpsService.this) { 3338 if (getRegisteredCallbackCount() == 0) { 3339 mAsyncOpWatchers.remove(key); 3340 } 3341 } 3342 } 3343 }; 3344 mAsyncOpWatchers.put(key, callbacks); 3345 } 3346 3347 callbacks.register(callback); 3348 } 3349 } 3350 3351 @Override stopWatchingAsyncNoted(String packageName, IAppOpsAsyncNotedCallback callback)3352 public void stopWatchingAsyncNoted(String packageName, IAppOpsAsyncNotedCallback callback) { 3353 Objects.requireNonNull(packageName); 3354 Objects.requireNonNull(callback); 3355 3356 int uid = Binder.getCallingUid(); 3357 Pair<String, Integer> key = getAsyncNotedOpsKey(packageName, uid); 3358 3359 verifyAndGetBypass(uid, packageName, null); 3360 3361 synchronized (this) { 3362 RemoteCallbackList<IAppOpsAsyncNotedCallback> callbacks = mAsyncOpWatchers.get(key); 3363 if (callbacks != null) { 3364 callbacks.unregister(callback); 3365 if (callbacks.getRegisteredCallbackCount() == 0) { 3366 mAsyncOpWatchers.remove(key); 3367 } 3368 } 3369 } 3370 } 3371 3372 @Override extractAsyncOps(String packageName)3373 public List<AsyncNotedAppOp> extractAsyncOps(String packageName) { 3374 Objects.requireNonNull(packageName); 3375 3376 int uid = Binder.getCallingUid(); 3377 3378 verifyAndGetBypass(uid, packageName, null); 3379 3380 synchronized (this) { 3381 return mUnforwardedAsyncNotedOps.remove(getAsyncNotedOpsKey(packageName, uid)); 3382 } 3383 } 3384 3385 @Override startOperation(IBinder clientId, int code, int uid, String packageName, String attributionTag, boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage)3386 public int startOperation(IBinder clientId, int code, int uid, String packageName, 3387 String attributionTag, boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, 3388 String message, boolean shouldCollectMessage) { 3389 verifyIncomingUid(uid); 3390 verifyIncomingOp(code); 3391 String resolvedPackageName = resolvePackageName(uid, packageName); 3392 if (resolvedPackageName == null) { 3393 return AppOpsManager.MODE_IGNORED; 3394 } 3395 3396 RestrictionBypass bypass; 3397 try { 3398 bypass = verifyAndGetBypass(uid, packageName, attributionTag); 3399 } catch (SecurityException e) { 3400 Slog.e(TAG, "startOperation", e); 3401 return AppOpsManager.MODE_ERRORED; 3402 } 3403 3404 synchronized (this) { 3405 final Ops ops = getOpsLocked(uid, resolvedPackageName, attributionTag, bypass, 3406 true /* edit */); 3407 if (ops == null) { 3408 scheduleOpStartedIfNeededLocked(code, uid, packageName, AppOpsManager.MODE_IGNORED); 3409 if (DEBUG) Slog.d(TAG, "startOperation: no op for code " + code + " uid " + uid 3410 + " package " + resolvedPackageName); 3411 return AppOpsManager.MODE_ERRORED; 3412 } 3413 final Op op = getOpLocked(ops, code, uid, true); 3414 if (isOpRestrictedLocked(uid, code, resolvedPackageName, bypass)) { 3415 scheduleOpStartedIfNeededLocked(code, uid, packageName, AppOpsManager.MODE_IGNORED); 3416 return AppOpsManager.MODE_IGNORED; 3417 } 3418 final AttributedOp attributedOp = op.getOrCreateAttribution(op, attributionTag); 3419 final int switchCode = AppOpsManager.opToSwitch(code); 3420 final UidState uidState = ops.uidState; 3421 // If there is a non-default per UID policy (we set UID op mode only if 3422 // non-default) it takes over, otherwise use the per package policy. 3423 if (uidState.opModes != null && uidState.opModes.indexOfKey(switchCode) >= 0) { 3424 final int uidMode = uidState.evalMode(code, uidState.opModes.get(switchCode)); 3425 if (uidMode != AppOpsManager.MODE_ALLOWED 3426 && (!startIfModeDefault || uidMode != AppOpsManager.MODE_DEFAULT)) { 3427 if (DEBUG) Slog.d(TAG, "noteOperation: uid reject #" + uidMode + " for code " 3428 + switchCode + " (" + code + ") uid " + uid + " package " 3429 + resolvedPackageName); 3430 attributedOp.rejected(uidState.state, AppOpsManager.OP_FLAG_SELF); 3431 scheduleOpStartedIfNeededLocked(code, uid, packageName, uidMode); 3432 return uidMode; 3433 } 3434 } else { 3435 final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, uid, true) 3436 : op; 3437 final int mode = switchOp.evalMode(); 3438 if (mode != AppOpsManager.MODE_ALLOWED 3439 && (!startIfModeDefault || mode != AppOpsManager.MODE_DEFAULT)) { 3440 if (DEBUG) Slog.d(TAG, "startOperation: reject #" + mode + " for code " 3441 + switchCode + " (" + code + ") uid " + uid + " package " 3442 + resolvedPackageName); 3443 attributedOp.rejected(uidState.state, AppOpsManager.OP_FLAG_SELF); 3444 scheduleOpStartedIfNeededLocked(code, uid, packageName, mode); 3445 return mode; 3446 } 3447 } 3448 if (DEBUG) Slog.d(TAG, "startOperation: allowing code " + code + " uid " + uid 3449 + " package " + resolvedPackageName); 3450 scheduleOpStartedIfNeededLocked(code, uid, packageName, AppOpsManager.MODE_ALLOWED); 3451 try { 3452 attributedOp.started(clientId, uidState.state); 3453 } catch (RemoteException e) { 3454 throw new RuntimeException(e); 3455 } 3456 } 3457 3458 if (shouldCollectAsyncNotedOp) { 3459 collectAsyncNotedOp(uid, packageName, code, attributionTag, AppOpsManager.OP_FLAG_SELF, 3460 message, shouldCollectMessage); 3461 } 3462 3463 return AppOpsManager.MODE_ALLOWED; 3464 } 3465 3466 @Override finishOperation(IBinder clientId, int code, int uid, String packageName, String attributionTag)3467 public void finishOperation(IBinder clientId, int code, int uid, String packageName, 3468 String attributionTag) { 3469 verifyIncomingUid(uid); 3470 verifyIncomingOp(code); 3471 String resolvedPackageName = resolvePackageName(uid, packageName); 3472 if (resolvedPackageName == null) { 3473 return; 3474 } 3475 3476 RestrictionBypass bypass; 3477 try { 3478 bypass = verifyAndGetBypass(uid, packageName, attributionTag); 3479 } catch (SecurityException e) { 3480 Slog.e(TAG, "Cannot finishOperation", e); 3481 return; 3482 } 3483 3484 synchronized (this) { 3485 Op op = getOpLocked(code, uid, resolvedPackageName, attributionTag, bypass, true); 3486 if (op == null) { 3487 Slog.e(TAG, "Operation not found: uid=" + uid + " pkg=" + packageName + "(" 3488 + attributionTag + ") op=" + AppOpsManager.opToName(code)); 3489 return; 3490 } 3491 final AttributedOp attributedOp = op.mAttributions.get(attributionTag); 3492 if (attributedOp == null) { 3493 Slog.e(TAG, "Attribution not found: uid=" + uid + " pkg=" + packageName + "(" 3494 + attributionTag + ") op=" + AppOpsManager.opToName(code)); 3495 return; 3496 } 3497 3498 if (attributedOp.isRunning()) { 3499 attributedOp.finished(clientId); 3500 } else { 3501 Slog.e(TAG, "Operation not started: uid=" + uid + " pkg=" + packageName + "(" 3502 + attributionTag + ") op=" + AppOpsManager.opToName(code)); 3503 } 3504 } 3505 } 3506 scheduleOpActiveChangedIfNeededLocked(int code, int uid, String packageName, boolean active)3507 private void scheduleOpActiveChangedIfNeededLocked(int code, int uid, String packageName, 3508 boolean active) { 3509 ArraySet<ActiveCallback> dispatchedCallbacks = null; 3510 final int callbackListCount = mActiveWatchers.size(); 3511 for (int i = 0; i < callbackListCount; i++) { 3512 final SparseArray<ActiveCallback> callbacks = mActiveWatchers.valueAt(i); 3513 ActiveCallback callback = callbacks.get(code); 3514 if (callback != null) { 3515 if (callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) { 3516 continue; 3517 } 3518 if (dispatchedCallbacks == null) { 3519 dispatchedCallbacks = new ArraySet<>(); 3520 } 3521 dispatchedCallbacks.add(callback); 3522 } 3523 } 3524 if (dispatchedCallbacks == null) { 3525 return; 3526 } 3527 mHandler.sendMessage(PooledLambda.obtainMessage( 3528 AppOpsService::notifyOpActiveChanged, 3529 this, dispatchedCallbacks, code, uid, packageName, active)); 3530 } 3531 notifyOpActiveChanged(ArraySet<ActiveCallback> callbacks, int code, int uid, String packageName, boolean active)3532 private void notifyOpActiveChanged(ArraySet<ActiveCallback> callbacks, 3533 int code, int uid, String packageName, boolean active) { 3534 // There are features watching for mode changes such as window manager 3535 // and location manager which are in our process. The callbacks in these 3536 // features may require permissions our remote caller does not have. 3537 final long identity = Binder.clearCallingIdentity(); 3538 try { 3539 final int callbackCount = callbacks.size(); 3540 for (int i = 0; i < callbackCount; i++) { 3541 final ActiveCallback callback = callbacks.valueAt(i); 3542 try { 3543 callback.mCallback.opActiveChanged(code, uid, packageName, active); 3544 } catch (RemoteException e) { 3545 /* do nothing */ 3546 } 3547 } 3548 } finally { 3549 Binder.restoreCallingIdentity(identity); 3550 } 3551 } 3552 scheduleOpStartedIfNeededLocked(int code, int uid, String pkgName, int result)3553 private void scheduleOpStartedIfNeededLocked(int code, int uid, String pkgName, int result) { 3554 ArraySet<StartedCallback> dispatchedCallbacks = null; 3555 final int callbackListCount = mStartedWatchers.size(); 3556 for (int i = 0; i < callbackListCount; i++) { 3557 final SparseArray<StartedCallback> callbacks = mStartedWatchers.valueAt(i); 3558 3559 StartedCallback callback = callbacks.get(code); 3560 if (callback != null) { 3561 if (callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) { 3562 continue; 3563 } 3564 3565 if (dispatchedCallbacks == null) { 3566 dispatchedCallbacks = new ArraySet<>(); 3567 } 3568 dispatchedCallbacks.add(callback); 3569 } 3570 } 3571 3572 if (dispatchedCallbacks == null) { 3573 return; 3574 } 3575 3576 mHandler.sendMessage(PooledLambda.obtainMessage( 3577 AppOpsService::notifyOpStarted, 3578 this, dispatchedCallbacks, code, uid, pkgName, result)); 3579 } 3580 notifyOpStarted(ArraySet<StartedCallback> callbacks, int code, int uid, String packageName, int result)3581 private void notifyOpStarted(ArraySet<StartedCallback> callbacks, 3582 int code, int uid, String packageName, int result) { 3583 final long identity = Binder.clearCallingIdentity(); 3584 try { 3585 final int callbackCount = callbacks.size(); 3586 for (int i = 0; i < callbackCount; i++) { 3587 final StartedCallback callback = callbacks.valueAt(i); 3588 try { 3589 callback.mCallback.opStarted(code, uid, packageName, result); 3590 } catch (RemoteException e) { 3591 /* do nothing */ 3592 } 3593 } 3594 } finally { 3595 Binder.restoreCallingIdentity(identity); 3596 } 3597 } 3598 scheduleOpNotedIfNeededLocked(int code, int uid, String packageName, int result)3599 private void scheduleOpNotedIfNeededLocked(int code, int uid, String packageName, 3600 int result) { 3601 ArraySet<NotedCallback> dispatchedCallbacks = null; 3602 final int callbackListCount = mNotedWatchers.size(); 3603 for (int i = 0; i < callbackListCount; i++) { 3604 final SparseArray<NotedCallback> callbacks = mNotedWatchers.valueAt(i); 3605 final NotedCallback callback = callbacks.get(code); 3606 if (callback != null) { 3607 if (callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) { 3608 continue; 3609 } 3610 if (dispatchedCallbacks == null) { 3611 dispatchedCallbacks = new ArraySet<>(); 3612 } 3613 dispatchedCallbacks.add(callback); 3614 } 3615 } 3616 if (dispatchedCallbacks == null) { 3617 return; 3618 } 3619 mHandler.sendMessage(PooledLambda.obtainMessage( 3620 AppOpsService::notifyOpChecked, 3621 this, dispatchedCallbacks, code, uid, packageName, result)); 3622 } 3623 notifyOpChecked(ArraySet<NotedCallback> callbacks, int code, int uid, String packageName, int result)3624 private void notifyOpChecked(ArraySet<NotedCallback> callbacks, 3625 int code, int uid, String packageName, int result) { 3626 // There are features watching for checks in our process. The callbacks in 3627 // these features may require permissions our remote caller does not have. 3628 final long identity = Binder.clearCallingIdentity(); 3629 try { 3630 final int callbackCount = callbacks.size(); 3631 for (int i = 0; i < callbackCount; i++) { 3632 final NotedCallback callback = callbacks.valueAt(i); 3633 try { 3634 callback.mCallback.opNoted(code, uid, packageName, result); 3635 } catch (RemoteException e) { 3636 /* do nothing */ 3637 } 3638 } 3639 } finally { 3640 Binder.restoreCallingIdentity(identity); 3641 } 3642 } 3643 3644 @Override permissionToOpCode(String permission)3645 public int permissionToOpCode(String permission) { 3646 if (permission == null) { 3647 return AppOpsManager.OP_NONE; 3648 } 3649 return AppOpsManager.permissionToOpCode(permission); 3650 } 3651 3652 @Override shouldCollectNotes(int opCode)3653 public boolean shouldCollectNotes(int opCode) { 3654 Preconditions.checkArgumentInRange(opCode, 0, _NUM_OP - 1, "opCode"); 3655 3656 String perm = AppOpsManager.opToPermission(opCode); 3657 if (perm == null) { 3658 return false; 3659 } 3660 3661 PermissionInfo permInfo; 3662 try { 3663 permInfo = mContext.getPackageManager().getPermissionInfo(perm, 0); 3664 } catch (PackageManager.NameNotFoundException e) { 3665 return false; 3666 } 3667 3668 return permInfo.getProtection() == PROTECTION_DANGEROUS 3669 || (permInfo.getProtectionFlags() & PROTECTION_FLAG_APPOP) != 0; 3670 } 3671 verifyIncomingUid(int uid)3672 private void verifyIncomingUid(int uid) { 3673 if (uid == Binder.getCallingUid()) { 3674 return; 3675 } 3676 if (Binder.getCallingPid() == Process.myPid()) { 3677 return; 3678 } 3679 mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS, 3680 Binder.getCallingPid(), Binder.getCallingUid(), null); 3681 } 3682 verifyIncomingOp(int op)3683 private void verifyIncomingOp(int op) { 3684 if (op >= 0 && op < AppOpsManager._NUM_OP) { 3685 return; 3686 } 3687 throw new IllegalArgumentException("Bad operation #" + op); 3688 } 3689 getUidStateLocked(int uid, boolean edit)3690 private @Nullable UidState getUidStateLocked(int uid, boolean edit) { 3691 UidState uidState = mUidStates.get(uid); 3692 if (uidState == null) { 3693 if (!edit) { 3694 return null; 3695 } 3696 uidState = new UidState(uid); 3697 mUidStates.put(uid, uidState); 3698 } else { 3699 updatePendingStateIfNeededLocked(uidState); 3700 } 3701 return uidState; 3702 } 3703 3704 /** 3705 * Check if the pending state should be updated and do so if needed 3706 * 3707 * @param uidState The uidState that might have a pending state 3708 */ updatePendingStateIfNeededLocked(@onNull UidState uidState)3709 private void updatePendingStateIfNeededLocked(@NonNull UidState uidState) { 3710 if (uidState != null) { 3711 if (uidState.pendingStateCommitTime != 0) { 3712 if (uidState.pendingStateCommitTime < mLastRealtime) { 3713 commitUidPendingStateLocked(uidState); 3714 } else { 3715 mLastRealtime = SystemClock.elapsedRealtime(); 3716 if (uidState.pendingStateCommitTime < mLastRealtime) { 3717 commitUidPendingStateLocked(uidState); 3718 } 3719 } 3720 } 3721 } 3722 } 3723 commitUidPendingStateLocked(UidState uidState)3724 private void commitUidPendingStateLocked(UidState uidState) { 3725 if (uidState.hasForegroundWatchers) { 3726 for (int fgi = uidState.foregroundOps.size() - 1; fgi >= 0; fgi--) { 3727 if (!uidState.foregroundOps.valueAt(fgi)) { 3728 continue; 3729 } 3730 final int code = uidState.foregroundOps.keyAt(fgi); 3731 // For location ops we consider fg state only if the fg service 3732 // is of location type, for all other ops any fg service will do. 3733 final long firstUnrestrictedUidState = resolveFirstUnrestrictedUidState(code); 3734 final boolean resolvedLastFg = uidState.state <= firstUnrestrictedUidState; 3735 final boolean resolvedNowFg = uidState.pendingState <= firstUnrestrictedUidState; 3736 if (resolvedLastFg == resolvedNowFg 3737 && uidState.capability == uidState.pendingCapability 3738 && uidState.appWidgetVisible == uidState.pendingAppWidgetVisible) { 3739 continue; 3740 } 3741 3742 if (uidState.opModes != null 3743 && uidState.opModes.indexOfKey(code) >= 0 3744 && uidState.opModes.get(code) == AppOpsManager.MODE_FOREGROUND) { 3745 mHandler.sendMessage(PooledLambda.obtainMessage( 3746 AppOpsService::notifyOpChangedForAllPkgsInUid, 3747 this, code, uidState.uid, true, null)); 3748 } else if (uidState.pkgOps != null) { 3749 final ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code); 3750 if (callbacks != null) { 3751 for (int cbi = callbacks.size() - 1; cbi >= 0; cbi--) { 3752 final ModeCallback callback = callbacks.valueAt(cbi); 3753 if ((callback.mFlags & AppOpsManager.WATCH_FOREGROUND_CHANGES) == 0 3754 || !callback.isWatchingUid(uidState.uid)) { 3755 continue; 3756 } 3757 for (int pkgi = uidState.pkgOps.size() - 1; pkgi >= 0; pkgi--) { 3758 final Op op = uidState.pkgOps.valueAt(pkgi).get(code); 3759 if (op == null) { 3760 continue; 3761 } 3762 if (op.mode == AppOpsManager.MODE_FOREGROUND) { 3763 mHandler.sendMessage(PooledLambda.obtainMessage( 3764 AppOpsService::notifyOpChanged, 3765 this, callback, code, uidState.uid, 3766 uidState.pkgOps.keyAt(pkgi))); 3767 } 3768 } 3769 } 3770 } 3771 } 3772 } 3773 } 3774 uidState.state = uidState.pendingState; 3775 uidState.capability = uidState.pendingCapability; 3776 uidState.appWidgetVisible = uidState.pendingAppWidgetVisible; 3777 uidState.pendingStateCommitTime = 0; 3778 } 3779 updateAppWidgetVisibility(SparseArray<String> uidPackageNames, boolean visible)3780 private void updateAppWidgetVisibility(SparseArray<String> uidPackageNames, boolean visible) { 3781 synchronized (this) { 3782 for (int i = uidPackageNames.size() - 1; i >= 0; i--) { 3783 final int uid = uidPackageNames.keyAt(i); 3784 final UidState uidState = getUidStateLocked(uid, true); 3785 if (uidState != null && (uidState.pendingAppWidgetVisible != visible)) { 3786 uidState.pendingAppWidgetVisible = visible; 3787 if (uidState.pendingAppWidgetVisible != uidState.appWidgetVisible) { 3788 commitUidPendingStateLocked(uidState); 3789 } 3790 } 3791 } 3792 } 3793 } 3794 3795 /** 3796 * Create a restriction description matching the properties of the package. 3797 * 3798 * @param context A context to use 3799 * @param pkg The package to create the restriction description for 3800 * 3801 * @return The restriction matching the package 3802 */ getBypassforPackage(@onNull AndroidPackage pkg)3803 private RestrictionBypass getBypassforPackage(@NonNull AndroidPackage pkg) { 3804 return new RestrictionBypass(pkg.isPrivileged(), mContext.checkPermission( 3805 android.Manifest.permission.EXEMPT_FROM_AUDIO_RECORD_RESTRICTIONS, -1, pkg.getUid()) 3806 == PackageManager.PERMISSION_GRANTED); 3807 } 3808 3809 /** 3810 * Verify that package belongs to uid and return the {@link RestrictionBypass bypass 3811 * description} for the package. 3812 * 3813 * @param uid The uid the package belongs to 3814 * @param packageName The package the might belong to the uid 3815 * @param attributionTag attribution tag or {@code null} if no need to verify 3816 * 3817 * @return {@code true} iff the package is privileged 3818 */ verifyAndGetBypass(int uid, String packageName, @Nullable String attributionTag)3819 private @Nullable RestrictionBypass verifyAndGetBypass(int uid, String packageName, 3820 @Nullable String attributionTag) { 3821 if (uid == Process.ROOT_UID) { 3822 // For backwards compatibility, don't check package name for root UID. 3823 return null; 3824 } 3825 3826 // Do not check if uid/packageName/attributionTag is already known 3827 synchronized (this) { 3828 UidState uidState = mUidStates.get(uid); 3829 if (uidState != null && uidState.pkgOps != null) { 3830 Ops ops = uidState.pkgOps.get(packageName); 3831 3832 if (ops != null && (attributionTag == null || ops.knownAttributionTags.contains( 3833 attributionTag)) && ops.bypass != null) { 3834 return ops.bypass; 3835 } 3836 } 3837 } 3838 3839 RestrictionBypass bypass = null; 3840 final long ident = Binder.clearCallingIdentity(); 3841 try { 3842 int pkgUid; 3843 AndroidPackage pkg = LocalServices.getService(PackageManagerInternal.class).getPackage( 3844 packageName); 3845 boolean isAttributionTagValid = false; 3846 3847 if (pkg != null) { 3848 if (attributionTag == null) { 3849 isAttributionTagValid = true; 3850 } else { 3851 if (pkg.getAttributions() != null) { 3852 int numAttributions = pkg.getAttributions().size(); 3853 for (int i = 0; i < numAttributions; i++) { 3854 if (pkg.getAttributions().get(i).tag.equals(attributionTag)) { 3855 isAttributionTagValid = true; 3856 } 3857 } 3858 } 3859 } 3860 3861 pkgUid = UserHandle.getUid( 3862 UserHandle.getUserId(uid), UserHandle.getAppId(pkg.getUid())); 3863 bypass = getBypassforPackage(pkg); 3864 } else { 3865 // Allow any attribution tag for resolvable uids 3866 isAttributionTagValid = true; 3867 3868 pkgUid = resolveUid(packageName); 3869 if (pkgUid >= 0) { 3870 bypass = RestrictionBypass.UNRESTRICTED; 3871 } 3872 } 3873 if (pkgUid != uid) { 3874 throw new SecurityException("Specified package " + packageName + " under uid " + uid 3875 + " but it is really " + pkgUid); 3876 } 3877 3878 if (!isAttributionTagValid) { 3879 // TODO moltmann: Switch from logging to enforcement 3880 Slog.e(TAG, "attributionTag " + attributionTag + " not declared in manifest of " 3881 + packageName); 3882 } 3883 } finally { 3884 Binder.restoreCallingIdentity(ident); 3885 } 3886 3887 return bypass; 3888 } 3889 3890 /** 3891 * Get (and potentially create) ops. 3892 * 3893 * @param uid The uid the package belongs to 3894 * @param packageName The name of the package 3895 * @param attributionTag attribution tag 3896 * @param bypass When to bypass certain op restrictions (can be null if edit == false) 3897 * @param edit If an ops does not exist, create the ops? 3898 3899 * @return The ops 3900 */ getOpsLocked(int uid, String packageName, @Nullable String attributionTag, @Nullable RestrictionBypass bypass, boolean edit)3901 private Ops getOpsLocked(int uid, String packageName, @Nullable String attributionTag, 3902 @Nullable RestrictionBypass bypass, boolean edit) { 3903 UidState uidState = getUidStateLocked(uid, edit); 3904 if (uidState == null) { 3905 return null; 3906 } 3907 3908 if (uidState.pkgOps == null) { 3909 if (!edit) { 3910 return null; 3911 } 3912 uidState.pkgOps = new ArrayMap<>(); 3913 } 3914 3915 Ops ops = uidState.pkgOps.get(packageName); 3916 if (ops == null) { 3917 if (!edit) { 3918 return null; 3919 } 3920 ops = new Ops(packageName, uidState); 3921 uidState.pkgOps.put(packageName, ops); 3922 } 3923 3924 if (edit) { 3925 if (bypass != null) { 3926 ops.bypass = bypass; 3927 } 3928 3929 if (attributionTag != null) { 3930 ops.knownAttributionTags.add(attributionTag); 3931 } 3932 } 3933 3934 return ops; 3935 } 3936 scheduleWriteLocked()3937 private void scheduleWriteLocked() { 3938 if (!mWriteScheduled) { 3939 mWriteScheduled = true; 3940 mHandler.postDelayed(mWriteRunner, WRITE_DELAY); 3941 } 3942 } 3943 scheduleFastWriteLocked()3944 private void scheduleFastWriteLocked() { 3945 if (!mFastWriteScheduled) { 3946 mWriteScheduled = true; 3947 mFastWriteScheduled = true; 3948 mHandler.removeCallbacks(mWriteRunner); 3949 mHandler.postDelayed(mWriteRunner, 10*1000); 3950 } 3951 } 3952 3953 /** 3954 * Get the state of an op for a uid. 3955 * 3956 * @param code The code of the op 3957 * @param uid The uid the of the package 3958 * @param packageName The package name for which to get the state for 3959 * @param attributionTag The attribution tag 3960 * @param bypass When to bypass certain op restrictions (can be null if edit == false) 3961 * @param edit Iff {@code true} create the {@link Op} object if not yet created 3962 * 3963 * @return The {@link Op state} of the op 3964 */ getOpLocked(int code, int uid, @NonNull String packageName, @Nullable String attributionTag, @Nullable RestrictionBypass bypass, boolean edit)3965 private @Nullable Op getOpLocked(int code, int uid, @NonNull String packageName, 3966 @Nullable String attributionTag, @Nullable RestrictionBypass bypass, boolean edit) { 3967 Ops ops = getOpsLocked(uid, packageName, attributionTag, bypass, edit); 3968 if (ops == null) { 3969 return null; 3970 } 3971 return getOpLocked(ops, code, uid, edit); 3972 } 3973 getOpLocked(Ops ops, int code, int uid, boolean edit)3974 private Op getOpLocked(Ops ops, int code, int uid, boolean edit) { 3975 Op op = ops.get(code); 3976 if (op == null) { 3977 if (!edit) { 3978 return null; 3979 } 3980 op = new Op(ops.uidState, ops.packageName, code, uid); 3981 ops.put(code, op); 3982 } 3983 if (edit) { 3984 scheduleWriteLocked(); 3985 } 3986 return op; 3987 } 3988 isOpRestrictedDueToSuspend(int code, String packageName, int uid)3989 private boolean isOpRestrictedDueToSuspend(int code, String packageName, int uid) { 3990 if (!ArrayUtils.contains(OPS_RESTRICTED_ON_SUSPEND, code)) { 3991 return false; 3992 } 3993 final PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class); 3994 return pmi.isPackageSuspended(packageName, UserHandle.getUserId(uid)); 3995 } 3996 isOpRestrictedLocked(int uid, int code, String packageName, @Nullable RestrictionBypass appBypass)3997 private boolean isOpRestrictedLocked(int uid, int code, String packageName, 3998 @Nullable RestrictionBypass appBypass) { 3999 int userHandle = UserHandle.getUserId(uid); 4000 final int restrictionSetCount = mOpUserRestrictions.size(); 4001 4002 for (int i = 0; i < restrictionSetCount; i++) { 4003 // For each client, check that the given op is not restricted, or that the given 4004 // package is exempt from the restriction. 4005 ClientRestrictionState restrictionState = mOpUserRestrictions.valueAt(i); 4006 if (restrictionState.hasRestriction(code, packageName, userHandle)) { 4007 RestrictionBypass opBypass = opAllowSystemBypassRestriction(code); 4008 if (opBypass != null) { 4009 // If we are the system, bypass user restrictions for certain codes 4010 synchronized (this) { 4011 if (opBypass.isPrivileged && appBypass != null && appBypass.isPrivileged) { 4012 return false; 4013 } 4014 if (opBypass.isRecordAudioRestrictionExcept && appBypass != null 4015 && appBypass.isRecordAudioRestrictionExcept) { 4016 return false; 4017 } 4018 } 4019 } 4020 return true; 4021 } 4022 } 4023 return false; 4024 } 4025 readState()4026 void readState() { 4027 int oldVersion = NO_VERSION; 4028 synchronized (mFile) { 4029 synchronized (this) { 4030 FileInputStream stream; 4031 try { 4032 stream = mFile.openRead(); 4033 } catch (FileNotFoundException e) { 4034 Slog.i(TAG, "No existing app ops " + mFile.getBaseFile() + "; starting empty"); 4035 return; 4036 } 4037 boolean success = false; 4038 mUidStates.clear(); 4039 try { 4040 XmlPullParser parser = Xml.newPullParser(); 4041 parser.setInput(stream, StandardCharsets.UTF_8.name()); 4042 int type; 4043 while ((type = parser.next()) != XmlPullParser.START_TAG 4044 && type != XmlPullParser.END_DOCUMENT) { 4045 ; 4046 } 4047 4048 if (type != XmlPullParser.START_TAG) { 4049 throw new IllegalStateException("no start tag found"); 4050 } 4051 4052 final String versionString = parser.getAttributeValue(null, "v"); 4053 if (versionString != null) { 4054 oldVersion = Integer.parseInt(versionString); 4055 } 4056 4057 int outerDepth = parser.getDepth(); 4058 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 4059 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 4060 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 4061 continue; 4062 } 4063 4064 String tagName = parser.getName(); 4065 if (tagName.equals("pkg")) { 4066 readPackage(parser); 4067 } else if (tagName.equals("uid")) { 4068 readUidOps(parser); 4069 } else { 4070 Slog.w(TAG, "Unknown element under <app-ops>: " 4071 + parser.getName()); 4072 XmlUtils.skipCurrentTag(parser); 4073 } 4074 } 4075 success = true; 4076 } catch (IllegalStateException e) { 4077 Slog.w(TAG, "Failed parsing " + e); 4078 } catch (NullPointerException e) { 4079 Slog.w(TAG, "Failed parsing " + e); 4080 } catch (NumberFormatException e) { 4081 Slog.w(TAG, "Failed parsing " + e); 4082 } catch (XmlPullParserException e) { 4083 Slog.w(TAG, "Failed parsing " + e); 4084 } catch (IOException e) { 4085 Slog.w(TAG, "Failed parsing " + e); 4086 } catch (IndexOutOfBoundsException e) { 4087 Slog.w(TAG, "Failed parsing " + e); 4088 } finally { 4089 if (!success) { 4090 mUidStates.clear(); 4091 } 4092 try { 4093 stream.close(); 4094 } catch (IOException e) { 4095 } 4096 } 4097 } 4098 } 4099 synchronized (this) { 4100 upgradeLocked(oldVersion); 4101 } 4102 } 4103 upgradeRunAnyInBackgroundLocked()4104 private void upgradeRunAnyInBackgroundLocked() { 4105 for (int i = 0; i < mUidStates.size(); i++) { 4106 final UidState uidState = mUidStates.valueAt(i); 4107 if (uidState == null) { 4108 continue; 4109 } 4110 if (uidState.opModes != null) { 4111 final int idx = uidState.opModes.indexOfKey(AppOpsManager.OP_RUN_IN_BACKGROUND); 4112 if (idx >= 0) { 4113 uidState.opModes.put(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, 4114 uidState.opModes.valueAt(idx)); 4115 } 4116 } 4117 if (uidState.pkgOps == null) { 4118 continue; 4119 } 4120 boolean changed = false; 4121 for (int j = 0; j < uidState.pkgOps.size(); j++) { 4122 Ops ops = uidState.pkgOps.valueAt(j); 4123 if (ops != null) { 4124 final Op op = ops.get(AppOpsManager.OP_RUN_IN_BACKGROUND); 4125 if (op != null && op.mode != AppOpsManager.opToDefaultMode(op.op)) { 4126 final Op copy = new Op(op.uidState, op.packageName, 4127 AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, uidState.uid); 4128 copy.mode = op.mode; 4129 ops.put(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, copy); 4130 changed = true; 4131 } 4132 } 4133 } 4134 if (changed) { 4135 uidState.evalForegroundOps(mOpModeWatchers); 4136 } 4137 } 4138 } 4139 upgradeLocked(int oldVersion)4140 private void upgradeLocked(int oldVersion) { 4141 if (oldVersion >= CURRENT_VERSION) { 4142 return; 4143 } 4144 Slog.d(TAG, "Upgrading app-ops xml from version " + oldVersion + " to " + CURRENT_VERSION); 4145 switch (oldVersion) { 4146 case NO_VERSION: 4147 upgradeRunAnyInBackgroundLocked(); 4148 // fall through 4149 case 1: 4150 // for future upgrades 4151 } 4152 scheduleFastWriteLocked(); 4153 } 4154 readUidOps(XmlPullParser parser)4155 private void readUidOps(XmlPullParser parser) throws NumberFormatException, 4156 XmlPullParserException, IOException { 4157 final int uid = Integer.parseInt(parser.getAttributeValue(null, "n")); 4158 int outerDepth = parser.getDepth(); 4159 int type; 4160 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 4161 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 4162 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 4163 continue; 4164 } 4165 4166 String tagName = parser.getName(); 4167 if (tagName.equals("op")) { 4168 final int code = Integer.parseInt(parser.getAttributeValue(null, "n")); 4169 final int mode = Integer.parseInt(parser.getAttributeValue(null, "m")); 4170 setUidMode(code, uid, mode); 4171 } else { 4172 Slog.w(TAG, "Unknown element under <uid-ops>: " 4173 + parser.getName()); 4174 XmlUtils.skipCurrentTag(parser); 4175 } 4176 } 4177 } 4178 readPackage(XmlPullParser parser)4179 private void readPackage(XmlPullParser parser) 4180 throws NumberFormatException, XmlPullParserException, IOException { 4181 String pkgName = parser.getAttributeValue(null, "n"); 4182 int outerDepth = parser.getDepth(); 4183 int type; 4184 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 4185 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 4186 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 4187 continue; 4188 } 4189 4190 String tagName = parser.getName(); 4191 if (tagName.equals("uid")) { 4192 readUid(parser, pkgName); 4193 } else { 4194 Slog.w(TAG, "Unknown element under <pkg>: " 4195 + parser.getName()); 4196 XmlUtils.skipCurrentTag(parser); 4197 } 4198 } 4199 } 4200 readUid(XmlPullParser parser, String pkgName)4201 private void readUid(XmlPullParser parser, String pkgName) 4202 throws NumberFormatException, XmlPullParserException, IOException { 4203 int uid = Integer.parseInt(parser.getAttributeValue(null, "n")); 4204 final UidState uidState = getUidStateLocked(uid, true); 4205 int outerDepth = parser.getDepth(); 4206 int type; 4207 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 4208 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 4209 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 4210 continue; 4211 } 4212 String tagName = parser.getName(); 4213 if (tagName.equals("op")) { 4214 readOp(parser, uidState, pkgName); 4215 } else { 4216 Slog.w(TAG, "Unknown element under <pkg>: " 4217 + parser.getName()); 4218 XmlUtils.skipCurrentTag(parser); 4219 } 4220 } 4221 uidState.evalForegroundOps(mOpModeWatchers); 4222 } 4223 readAttributionOp(XmlPullParser parser, @NonNull Op parent, @Nullable String attribution)4224 private void readAttributionOp(XmlPullParser parser, @NonNull Op parent, 4225 @Nullable String attribution) throws NumberFormatException, IOException { 4226 final AttributedOp attributedOp = parent.getOrCreateAttribution(parent, attribution); 4227 4228 final long key = XmlUtils.readLongAttribute(parser, "n"); 4229 final int uidState = extractUidStateFromKey(key); 4230 final int opFlags = extractFlagsFromKey(key); 4231 4232 final long accessTime = XmlUtils.readLongAttribute(parser, "t", 0); 4233 final long rejectTime = XmlUtils.readLongAttribute(parser, "r", 0); 4234 final long accessDuration = XmlUtils.readLongAttribute(parser, "d", -1); 4235 final String proxyPkg = XmlUtils.readStringAttribute(parser, "pp"); 4236 final int proxyUid = XmlUtils.readIntAttribute(parser, "pu", Process.INVALID_UID); 4237 final String proxyAttributionTag = XmlUtils.readStringAttribute(parser, "pc"); 4238 4239 if (accessTime > 0) { 4240 attributedOp.accessed(accessTime, accessDuration, proxyUid, proxyPkg, 4241 proxyAttributionTag, uidState, opFlags); 4242 } 4243 if (rejectTime > 0) { 4244 attributedOp.rejected(rejectTime, uidState, opFlags); 4245 } 4246 } 4247 readOp(XmlPullParser parser, @NonNull UidState uidState, @NonNull String pkgName)4248 private void readOp(XmlPullParser parser, @NonNull UidState uidState, @NonNull String pkgName) 4249 throws NumberFormatException, 4250 XmlPullParserException, IOException { 4251 int opCode = Integer.parseInt(parser.getAttributeValue(null, "n")); 4252 Op op = new Op(uidState, pkgName, opCode, uidState.uid); 4253 4254 final int mode = XmlUtils.readIntAttribute(parser, "m", 4255 AppOpsManager.opToDefaultMode(op.op)); 4256 op.mode = mode; 4257 4258 int outerDepth = parser.getDepth(); 4259 int type; 4260 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 4261 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 4262 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 4263 continue; 4264 } 4265 String tagName = parser.getName(); 4266 if (tagName.equals("st")) { 4267 readAttributionOp(parser, op, XmlUtils.readStringAttribute(parser, "id")); 4268 } else { 4269 Slog.w(TAG, "Unknown element under <op>: " 4270 + parser.getName()); 4271 XmlUtils.skipCurrentTag(parser); 4272 } 4273 } 4274 4275 if (uidState.pkgOps == null) { 4276 uidState.pkgOps = new ArrayMap<>(); 4277 } 4278 Ops ops = uidState.pkgOps.get(pkgName); 4279 if (ops == null) { 4280 ops = new Ops(pkgName, uidState); 4281 uidState.pkgOps.put(pkgName, ops); 4282 } 4283 ops.put(op.op, op); 4284 } 4285 writeState()4286 void writeState() { 4287 synchronized (mFile) { 4288 FileOutputStream stream; 4289 try { 4290 stream = mFile.startWrite(); 4291 } catch (IOException e) { 4292 Slog.w(TAG, "Failed to write state: " + e); 4293 return; 4294 } 4295 4296 List<AppOpsManager.PackageOps> allOps = getPackagesForOps(null); 4297 4298 try { 4299 XmlSerializer out = new FastXmlSerializer(); 4300 out.setOutput(stream, StandardCharsets.UTF_8.name()); 4301 out.startDocument(null, true); 4302 out.startTag(null, "app-ops"); 4303 out.attribute(null, "v", String.valueOf(CURRENT_VERSION)); 4304 4305 SparseArray<SparseIntArray> uidStatesClone; 4306 synchronized (this) { 4307 uidStatesClone = new SparseArray<>(mUidStates.size()); 4308 4309 final int uidStateCount = mUidStates.size(); 4310 for (int uidStateNum = 0; uidStateNum < uidStateCount; uidStateNum++) { 4311 UidState uidState = mUidStates.valueAt(uidStateNum); 4312 int uid = mUidStates.keyAt(uidStateNum); 4313 4314 SparseIntArray opModes = uidState.opModes; 4315 if (opModes != null && opModes.size() > 0) { 4316 uidStatesClone.put(uid, new SparseIntArray(opModes.size())); 4317 4318 final int opCount = opModes.size(); 4319 for (int opCountNum = 0; opCountNum < opCount; opCountNum++) { 4320 uidStatesClone.get(uid).put( 4321 opModes.keyAt(opCountNum), 4322 opModes.valueAt(opCountNum)); 4323 } 4324 } 4325 } 4326 } 4327 4328 final int uidStateCount = uidStatesClone.size(); 4329 for (int uidStateNum = 0; uidStateNum < uidStateCount; uidStateNum++) { 4330 SparseIntArray opModes = uidStatesClone.valueAt(uidStateNum); 4331 if (opModes != null && opModes.size() > 0) { 4332 out.startTag(null, "uid"); 4333 out.attribute(null, "n", 4334 Integer.toString(uidStatesClone.keyAt(uidStateNum))); 4335 final int opCount = opModes.size(); 4336 for (int opCountNum = 0; opCountNum < opCount; opCountNum++) { 4337 final int op = opModes.keyAt(opCountNum); 4338 final int mode = opModes.valueAt(opCountNum); 4339 out.startTag(null, "op"); 4340 out.attribute(null, "n", Integer.toString(op)); 4341 out.attribute(null, "m", Integer.toString(mode)); 4342 out.endTag(null, "op"); 4343 } 4344 out.endTag(null, "uid"); 4345 } 4346 } 4347 4348 if (allOps != null) { 4349 String lastPkg = null; 4350 for (int i=0; i<allOps.size(); i++) { 4351 AppOpsManager.PackageOps pkg = allOps.get(i); 4352 if (!pkg.getPackageName().equals(lastPkg)) { 4353 if (lastPkg != null) { 4354 out.endTag(null, "pkg"); 4355 } 4356 lastPkg = pkg.getPackageName(); 4357 out.startTag(null, "pkg"); 4358 out.attribute(null, "n", lastPkg); 4359 } 4360 out.startTag(null, "uid"); 4361 out.attribute(null, "n", Integer.toString(pkg.getUid())); 4362 List<AppOpsManager.OpEntry> ops = pkg.getOps(); 4363 for (int j=0; j<ops.size(); j++) { 4364 AppOpsManager.OpEntry op = ops.get(j); 4365 out.startTag(null, "op"); 4366 out.attribute(null, "n", Integer.toString(op.getOp())); 4367 if (op.getMode() != AppOpsManager.opToDefaultMode(op.getOp())) { 4368 out.attribute(null, "m", Integer.toString(op.getMode())); 4369 } 4370 4371 for (String attributionTag : op.getAttributedOpEntries().keySet()) { 4372 final AttributedOpEntry attribution = 4373 op.getAttributedOpEntries().get(attributionTag); 4374 4375 final ArraySet<Long> keys = attribution.collectKeys(); 4376 4377 final int keyCount = keys.size(); 4378 for (int k = 0; k < keyCount; k++) { 4379 final long key = keys.valueAt(k); 4380 4381 final int uidState = AppOpsManager.extractUidStateFromKey(key); 4382 final int flags = AppOpsManager.extractFlagsFromKey(key); 4383 4384 final long accessTime = attribution.getLastAccessTime(uidState, 4385 uidState, flags); 4386 final long rejectTime = attribution.getLastRejectTime(uidState, 4387 uidState, flags); 4388 final long accessDuration = attribution.getLastDuration( 4389 uidState, uidState, flags); 4390 // Proxy information for rejections is not backed up 4391 final OpEventProxyInfo proxy = attribution.getLastProxyInfo( 4392 uidState, uidState, flags); 4393 4394 if (accessTime <= 0 && rejectTime <= 0 && accessDuration <= 0 4395 && proxy == null) { 4396 continue; 4397 } 4398 4399 String proxyPkg = null; 4400 String proxyAttributionTag = null; 4401 int proxyUid = Process.INVALID_UID; 4402 if (proxy != null) { 4403 proxyPkg = proxy.getPackageName(); 4404 proxyAttributionTag = proxy.getAttributionTag(); 4405 proxyUid = proxy.getUid(); 4406 } 4407 4408 out.startTag(null, "st"); 4409 if (attributionTag != null) { 4410 out.attribute(null, "id", attributionTag); 4411 } 4412 out.attribute(null, "n", Long.toString(key)); 4413 if (accessTime > 0) { 4414 out.attribute(null, "t", Long.toString(accessTime)); 4415 } 4416 if (rejectTime > 0) { 4417 out.attribute(null, "r", Long.toString(rejectTime)); 4418 } 4419 if (accessDuration > 0) { 4420 out.attribute(null, "d", Long.toString(accessDuration)); 4421 } 4422 if (proxyPkg != null) { 4423 out.attribute(null, "pp", proxyPkg); 4424 } 4425 if (proxyAttributionTag != null) { 4426 out.attribute(null, "pc", proxyAttributionTag); 4427 } 4428 if (proxyUid >= 0) { 4429 out.attribute(null, "pu", Integer.toString(proxyUid)); 4430 } 4431 out.endTag(null, "st"); 4432 } 4433 } 4434 4435 out.endTag(null, "op"); 4436 } 4437 out.endTag(null, "uid"); 4438 } 4439 if (lastPkg != null) { 4440 out.endTag(null, "pkg"); 4441 } 4442 } 4443 4444 out.endTag(null, "app-ops"); 4445 out.endDocument(); 4446 mFile.finishWrite(stream); 4447 } catch (IOException e) { 4448 Slog.w(TAG, "Failed to write state, restoring backup.", e); 4449 mFile.failWrite(stream); 4450 } 4451 } 4452 } 4453 4454 static class Shell extends ShellCommand { 4455 final IAppOpsService mInterface; 4456 final AppOpsService mInternal; 4457 4458 int userId = UserHandle.USER_SYSTEM; 4459 String packageName; 4460 String attributionTag; 4461 String opStr; 4462 String modeStr; 4463 int op; 4464 int mode; 4465 int packageUid; 4466 int nonpackageUid; 4467 final static Binder sBinder = new Binder(); 4468 IBinder mToken; 4469 boolean targetsUid; 4470 Shell(IAppOpsService iface, AppOpsService internal)4471 Shell(IAppOpsService iface, AppOpsService internal) { 4472 mInterface = iface; 4473 mInternal = internal; 4474 mToken = AppOpsManager.getClientId(); 4475 } 4476 4477 @Override onCommand(String cmd)4478 public int onCommand(String cmd) { 4479 return onShellCommand(this, cmd); 4480 } 4481 4482 @Override onHelp()4483 public void onHelp() { 4484 PrintWriter pw = getOutPrintWriter(); 4485 dumpCommandHelp(pw); 4486 } 4487 strOpToOp(String op, PrintWriter err)4488 static private int strOpToOp(String op, PrintWriter err) { 4489 try { 4490 return AppOpsManager.strOpToOp(op); 4491 } catch (IllegalArgumentException e) { 4492 } 4493 try { 4494 return Integer.parseInt(op); 4495 } catch (NumberFormatException e) { 4496 } 4497 try { 4498 return AppOpsManager.strDebugOpToOp(op); 4499 } catch (IllegalArgumentException e) { 4500 err.println("Error: " + e.getMessage()); 4501 return -1; 4502 } 4503 } 4504 strModeToMode(String modeStr, PrintWriter err)4505 static int strModeToMode(String modeStr, PrintWriter err) { 4506 for (int i = AppOpsManager.MODE_NAMES.length - 1; i >= 0; i--) { 4507 if (AppOpsManager.MODE_NAMES[i].equals(modeStr)) { 4508 return i; 4509 } 4510 } 4511 try { 4512 return Integer.parseInt(modeStr); 4513 } catch (NumberFormatException e) { 4514 } 4515 err.println("Error: Mode " + modeStr + " is not valid"); 4516 return -1; 4517 } 4518 parseUserOpMode(int defMode, PrintWriter err)4519 int parseUserOpMode(int defMode, PrintWriter err) throws RemoteException { 4520 userId = UserHandle.USER_CURRENT; 4521 opStr = null; 4522 modeStr = null; 4523 for (String argument; (argument = getNextArg()) != null;) { 4524 if ("--user".equals(argument)) { 4525 userId = UserHandle.parseUserArg(getNextArgRequired()); 4526 } else { 4527 if (opStr == null) { 4528 opStr = argument; 4529 } else if (modeStr == null) { 4530 modeStr = argument; 4531 break; 4532 } 4533 } 4534 } 4535 if (opStr == null) { 4536 err.println("Error: Operation not specified."); 4537 return -1; 4538 } 4539 op = strOpToOp(opStr, err); 4540 if (op < 0) { 4541 return -1; 4542 } 4543 if (modeStr != null) { 4544 if ((mode=strModeToMode(modeStr, err)) < 0) { 4545 return -1; 4546 } 4547 } else { 4548 mode = defMode; 4549 } 4550 return 0; 4551 } 4552 parseUserPackageOp(boolean reqOp, PrintWriter err)4553 int parseUserPackageOp(boolean reqOp, PrintWriter err) throws RemoteException { 4554 userId = UserHandle.USER_CURRENT; 4555 packageName = null; 4556 opStr = null; 4557 for (String argument; (argument = getNextArg()) != null;) { 4558 if ("--user".equals(argument)) { 4559 userId = UserHandle.parseUserArg(getNextArgRequired()); 4560 } else if ("--uid".equals(argument)) { 4561 targetsUid = true; 4562 } else if ("--attribution".equals(argument)) { 4563 attributionTag = getNextArgRequired(); 4564 } else { 4565 if (packageName == null) { 4566 packageName = argument; 4567 } else if (opStr == null) { 4568 opStr = argument; 4569 break; 4570 } 4571 } 4572 } 4573 if (packageName == null) { 4574 err.println("Error: Package name not specified."); 4575 return -1; 4576 } else if (opStr == null && reqOp) { 4577 err.println("Error: Operation not specified."); 4578 return -1; 4579 } 4580 if (opStr != null) { 4581 op = strOpToOp(opStr, err); 4582 if (op < 0) { 4583 return -1; 4584 } 4585 } else { 4586 op = AppOpsManager.OP_NONE; 4587 } 4588 if (userId == UserHandle.USER_CURRENT) { 4589 userId = ActivityManager.getCurrentUser(); 4590 } 4591 nonpackageUid = -1; 4592 try { 4593 nonpackageUid = Integer.parseInt(packageName); 4594 } catch (NumberFormatException e) { 4595 } 4596 if (nonpackageUid == -1 && packageName.length() > 1 && packageName.charAt(0) == 'u' 4597 && packageName.indexOf('.') < 0) { 4598 int i = 1; 4599 while (i < packageName.length() && packageName.charAt(i) >= '0' 4600 && packageName.charAt(i) <= '9') { 4601 i++; 4602 } 4603 if (i > 1 && i < packageName.length()) { 4604 String userStr = packageName.substring(1, i); 4605 try { 4606 int user = Integer.parseInt(userStr); 4607 char type = packageName.charAt(i); 4608 i++; 4609 int startTypeVal = i; 4610 while (i < packageName.length() && packageName.charAt(i) >= '0' 4611 && packageName.charAt(i) <= '9') { 4612 i++; 4613 } 4614 if (i > startTypeVal) { 4615 String typeValStr = packageName.substring(startTypeVal, i); 4616 try { 4617 int typeVal = Integer.parseInt(typeValStr); 4618 if (type == 'a') { 4619 nonpackageUid = UserHandle.getUid(user, 4620 typeVal + Process.FIRST_APPLICATION_UID); 4621 } else if (type == 's') { 4622 nonpackageUid = UserHandle.getUid(user, typeVal); 4623 } 4624 } catch (NumberFormatException e) { 4625 } 4626 } 4627 } catch (NumberFormatException e) { 4628 } 4629 } 4630 } 4631 if (nonpackageUid != -1) { 4632 packageName = null; 4633 } else { 4634 packageUid = resolveUid(packageName); 4635 if (packageUid < 0) { 4636 packageUid = AppGlobals.getPackageManager().getPackageUid(packageName, 4637 PackageManager.MATCH_UNINSTALLED_PACKAGES, userId); 4638 } 4639 if (packageUid < 0) { 4640 err.println("Error: No UID for " + packageName + " in user " + userId); 4641 return -1; 4642 } 4643 } 4644 return 0; 4645 } 4646 } 4647 onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ShellCallback callback, ResultReceiver resultReceiver)4648 @Override public void onShellCommand(FileDescriptor in, FileDescriptor out, 4649 FileDescriptor err, String[] args, ShellCallback callback, 4650 ResultReceiver resultReceiver) { 4651 (new Shell(this, this)).exec(this, in, out, err, args, callback, resultReceiver); 4652 } 4653 dumpCommandHelp(PrintWriter pw)4654 static void dumpCommandHelp(PrintWriter pw) { 4655 pw.println("AppOps service (appops) commands:"); 4656 pw.println(" help"); 4657 pw.println(" Print this help text."); 4658 pw.println(" start [--user <USER_ID>] [--attribution <ATTRIBUTION_TAG>] <PACKAGE | UID> " 4659 + "<OP> "); 4660 pw.println(" Starts a given operation for a particular application."); 4661 pw.println(" stop [--user <USER_ID>] [--attribution <ATTRIBUTION_TAG>] <PACKAGE | UID> " 4662 + "<OP> "); 4663 pw.println(" Stops a given operation for a particular application."); 4664 pw.println(" set [--user <USER_ID>] <[--uid] PACKAGE | UID> <OP> <MODE>"); 4665 pw.println(" Set the mode for a particular application and operation."); 4666 pw.println(" get [--user <USER_ID>] [--attribution <ATTRIBUTION_TAG>] <PACKAGE | UID> " 4667 + "[<OP>]"); 4668 pw.println(" Return the mode for a particular application and optional operation."); 4669 pw.println(" query-op [--user <USER_ID>] <OP> [<MODE>]"); 4670 pw.println(" Print all packages that currently have the given op in the given mode."); 4671 pw.println(" reset [--user <USER_ID>] [<PACKAGE>]"); 4672 pw.println(" Reset the given application or all applications to default modes."); 4673 pw.println(" write-settings"); 4674 pw.println(" Immediately write pending changes to storage."); 4675 pw.println(" read-settings"); 4676 pw.println(" Read the last written settings, replacing current state in RAM."); 4677 pw.println(" options:"); 4678 pw.println(" <PACKAGE> an Android package name or its UID if prefixed by --uid"); 4679 pw.println(" <OP> an AppOps operation."); 4680 pw.println(" <MODE> one of allow, ignore, deny, or default"); 4681 pw.println(" <USER_ID> the user id under which the package is installed. If --user is"); 4682 pw.println(" not specified, the current user is assumed."); 4683 } 4684 onShellCommand(Shell shell, String cmd)4685 static int onShellCommand(Shell shell, String cmd) { 4686 if (cmd == null) { 4687 return shell.handleDefaultCommands(cmd); 4688 } 4689 PrintWriter pw = shell.getOutPrintWriter(); 4690 PrintWriter err = shell.getErrPrintWriter(); 4691 try { 4692 switch (cmd) { 4693 case "set": { 4694 int res = shell.parseUserPackageOp(true, err); 4695 if (res < 0) { 4696 return res; 4697 } 4698 String modeStr = shell.getNextArg(); 4699 if (modeStr == null) { 4700 err.println("Error: Mode not specified."); 4701 return -1; 4702 } 4703 4704 final int mode = shell.strModeToMode(modeStr, err); 4705 if (mode < 0) { 4706 return -1; 4707 } 4708 4709 if (!shell.targetsUid && shell.packageName != null) { 4710 shell.mInterface.setMode(shell.op, shell.packageUid, shell.packageName, 4711 mode); 4712 } else if (shell.targetsUid && shell.packageName != null) { 4713 try { 4714 final int uid = shell.mInternal.mContext.getPackageManager() 4715 .getPackageUidAsUser(shell.packageName, shell.userId); 4716 shell.mInterface.setUidMode(shell.op, uid, mode); 4717 } catch (PackageManager.NameNotFoundException e) { 4718 return -1; 4719 } 4720 } else { 4721 shell.mInterface.setUidMode(shell.op, shell.nonpackageUid, mode); 4722 } 4723 return 0; 4724 } 4725 case "get": { 4726 int res = shell.parseUserPackageOp(false, err); 4727 if (res < 0) { 4728 return res; 4729 } 4730 4731 List<AppOpsManager.PackageOps> ops = new ArrayList<>(); 4732 if (shell.packageName != null) { 4733 // Uid mode overrides package mode, so make sure it's also reported 4734 List<AppOpsManager.PackageOps> r = shell.mInterface.getUidOps( 4735 shell.packageUid, 4736 shell.op != AppOpsManager.OP_NONE ? new int[]{shell.op} : null); 4737 if (r != null) { 4738 ops.addAll(r); 4739 } 4740 r = shell.mInterface.getOpsForPackage( 4741 shell.packageUid, shell.packageName, 4742 shell.op != AppOpsManager.OP_NONE ? new int[]{shell.op} : null); 4743 if (r != null) { 4744 ops.addAll(r); 4745 } 4746 } else { 4747 ops = shell.mInterface.getUidOps( 4748 shell.nonpackageUid, 4749 shell.op != AppOpsManager.OP_NONE ? new int[]{shell.op} : null); 4750 } 4751 if (ops == null || ops.size() <= 0) { 4752 pw.println("No operations."); 4753 if (shell.op > AppOpsManager.OP_NONE && shell.op < AppOpsManager._NUM_OP) { 4754 pw.println("Default mode: " + AppOpsManager.modeToName( 4755 AppOpsManager.opToDefaultMode(shell.op))); 4756 } 4757 return 0; 4758 } 4759 final long now = System.currentTimeMillis(); 4760 for (int i=0; i<ops.size(); i++) { 4761 AppOpsManager.PackageOps packageOps = ops.get(i); 4762 if (packageOps.getPackageName() == null) { 4763 pw.print("Uid mode: "); 4764 } 4765 List<AppOpsManager.OpEntry> entries = packageOps.getOps(); 4766 for (int j=0; j<entries.size(); j++) { 4767 AppOpsManager.OpEntry ent = entries.get(j); 4768 pw.print(AppOpsManager.opToName(ent.getOp())); 4769 pw.print(": "); 4770 pw.print(AppOpsManager.modeToName(ent.getMode())); 4771 if (shell.attributionTag == null) { 4772 if (ent.getLastAccessTime(OP_FLAGS_ALL) != -1) { 4773 pw.print("; time="); 4774 TimeUtils.formatDuration( 4775 now - ent.getLastAccessTime(OP_FLAGS_ALL), pw); 4776 pw.print(" ago"); 4777 } 4778 if (ent.getLastRejectTime(OP_FLAGS_ALL) != -1) { 4779 pw.print("; rejectTime="); 4780 TimeUtils.formatDuration( 4781 now - ent.getLastRejectTime(OP_FLAGS_ALL), pw); 4782 pw.print(" ago"); 4783 } 4784 if (ent.isRunning()) { 4785 pw.print(" (running)"); 4786 } else if (ent.getLastDuration(OP_FLAGS_ALL) != -1) { 4787 pw.print("; duration="); 4788 TimeUtils.formatDuration(ent.getLastDuration(OP_FLAGS_ALL), pw); 4789 } 4790 } else { 4791 final AppOpsManager.AttributedOpEntry attributionEnt = 4792 ent.getAttributedOpEntries().get(shell.attributionTag); 4793 if (attributionEnt != null) { 4794 if (attributionEnt.getLastAccessTime(OP_FLAGS_ALL) != -1) { 4795 pw.print("; time="); 4796 TimeUtils.formatDuration( 4797 now - attributionEnt.getLastAccessTime( 4798 OP_FLAGS_ALL), pw); 4799 pw.print(" ago"); 4800 } 4801 if (attributionEnt.getLastRejectTime(OP_FLAGS_ALL) != -1) { 4802 pw.print("; rejectTime="); 4803 TimeUtils.formatDuration( 4804 now - attributionEnt.getLastRejectTime( 4805 OP_FLAGS_ALL), pw); 4806 pw.print(" ago"); 4807 } 4808 if (attributionEnt.isRunning()) { 4809 pw.print(" (running)"); 4810 } else if (attributionEnt.getLastDuration(OP_FLAGS_ALL) 4811 != -1) { 4812 pw.print("; duration="); 4813 TimeUtils.formatDuration( 4814 attributionEnt.getLastDuration(OP_FLAGS_ALL), pw); 4815 } 4816 } 4817 } 4818 pw.println(); 4819 } 4820 } 4821 return 0; 4822 } 4823 case "query-op": { 4824 int res = shell.parseUserOpMode(AppOpsManager.MODE_IGNORED, err); 4825 if (res < 0) { 4826 return res; 4827 } 4828 List<AppOpsManager.PackageOps> ops = shell.mInterface.getPackagesForOps( 4829 new int[] {shell.op}); 4830 if (ops == null || ops.size() <= 0) { 4831 pw.println("No operations."); 4832 return 0; 4833 } 4834 for (int i=0; i<ops.size(); i++) { 4835 final AppOpsManager.PackageOps pkg = ops.get(i); 4836 boolean hasMatch = false; 4837 final List<AppOpsManager.OpEntry> entries = ops.get(i).getOps(); 4838 for (int j=0; j<entries.size(); j++) { 4839 AppOpsManager.OpEntry ent = entries.get(j); 4840 if (ent.getOp() == shell.op && ent.getMode() == shell.mode) { 4841 hasMatch = true; 4842 break; 4843 } 4844 } 4845 if (hasMatch) { 4846 pw.println(pkg.getPackageName()); 4847 } 4848 } 4849 return 0; 4850 } 4851 case "reset": { 4852 String packageName = null; 4853 int userId = UserHandle.USER_CURRENT; 4854 for (String argument; (argument = shell.getNextArg()) != null;) { 4855 if ("--user".equals(argument)) { 4856 String userStr = shell.getNextArgRequired(); 4857 userId = UserHandle.parseUserArg(userStr); 4858 } else { 4859 if (packageName == null) { 4860 packageName = argument; 4861 } else { 4862 err.println("Error: Unsupported argument: " + argument); 4863 return -1; 4864 } 4865 } 4866 } 4867 4868 if (userId == UserHandle.USER_CURRENT) { 4869 userId = ActivityManager.getCurrentUser(); 4870 } 4871 4872 shell.mInterface.resetAllModes(userId, packageName); 4873 pw.print("Reset all modes for: "); 4874 if (userId == UserHandle.USER_ALL) { 4875 pw.print("all users"); 4876 } else { 4877 pw.print("user "); pw.print(userId); 4878 } 4879 pw.print(", "); 4880 if (packageName == null) { 4881 pw.println("all packages"); 4882 } else { 4883 pw.print("package "); pw.println(packageName); 4884 } 4885 return 0; 4886 } 4887 case "write-settings": { 4888 shell.mInternal.enforceManageAppOpsModes(Binder.getCallingPid(), 4889 Binder.getCallingUid(), -1); 4890 long token = Binder.clearCallingIdentity(); 4891 try { 4892 synchronized (shell.mInternal) { 4893 shell.mInternal.mHandler.removeCallbacks(shell.mInternal.mWriteRunner); 4894 } 4895 shell.mInternal.writeState(); 4896 pw.println("Current settings written."); 4897 } finally { 4898 Binder.restoreCallingIdentity(token); 4899 } 4900 return 0; 4901 } 4902 case "read-settings": { 4903 shell.mInternal.enforceManageAppOpsModes(Binder.getCallingPid(), 4904 Binder.getCallingUid(), -1); 4905 long token = Binder.clearCallingIdentity(); 4906 try { 4907 shell.mInternal.readState(); 4908 pw.println("Last settings read."); 4909 } finally { 4910 Binder.restoreCallingIdentity(token); 4911 } 4912 return 0; 4913 } 4914 case "start": { 4915 int res = shell.parseUserPackageOp(true, err); 4916 if (res < 0) { 4917 return res; 4918 } 4919 4920 if (shell.packageName != null) { 4921 shell.mInterface.startOperation(shell.mToken, shell.op, shell.packageUid, 4922 shell.packageName, shell.attributionTag, true, true, 4923 "appops start shell command", true); 4924 } else { 4925 return -1; 4926 } 4927 return 0; 4928 } 4929 case "stop": { 4930 int res = shell.parseUserPackageOp(true, err); 4931 if (res < 0) { 4932 return res; 4933 } 4934 4935 if (shell.packageName != null) { 4936 shell.mInterface.finishOperation(shell.mToken, shell.op, shell.packageUid, 4937 shell.packageName, shell.attributionTag); 4938 } else { 4939 return -1; 4940 } 4941 return 0; 4942 } 4943 default: 4944 return shell.handleDefaultCommands(cmd); 4945 } 4946 } catch (RemoteException e) { 4947 pw.println("Remote exception: " + e); 4948 } 4949 return -1; 4950 } 4951 dumpHelp(PrintWriter pw)4952 private void dumpHelp(PrintWriter pw) { 4953 pw.println("AppOps service (appops) dump options:"); 4954 pw.println(" -h"); 4955 pw.println(" Print this help text."); 4956 pw.println(" --op [OP]"); 4957 pw.println(" Limit output to data associated with the given app op code."); 4958 pw.println(" --mode [MODE]"); 4959 pw.println(" Limit output to data associated with the given app op mode."); 4960 pw.println(" --package [PACKAGE]"); 4961 pw.println(" Limit output to data associated with the given package name."); 4962 pw.println(" --attributionTag [attributionTag]"); 4963 pw.println(" Limit output to data associated with the given attribution tag."); 4964 pw.println(" --watchers"); 4965 pw.println(" Only output the watcher sections."); 4966 } 4967 dumpStatesLocked(@onNull PrintWriter pw, @Nullable String filterAttributionTag, @HistoricalOpsRequestFilter int filter, long nowElapsed, @NonNull Op op, long now, @NonNull SimpleDateFormat sdf, @NonNull Date date, @NonNull String prefix)4968 private void dumpStatesLocked(@NonNull PrintWriter pw, @Nullable String filterAttributionTag, 4969 @HistoricalOpsRequestFilter int filter, long nowElapsed, @NonNull Op op, long now, 4970 @NonNull SimpleDateFormat sdf, @NonNull Date date, @NonNull String prefix) { 4971 final int numAttributions = op.mAttributions.size(); 4972 for (int i = 0; i < numAttributions; i++) { 4973 if ((filter & FILTER_BY_ATTRIBUTION_TAG) != 0 && !Objects.equals( 4974 op.mAttributions.keyAt(i), filterAttributionTag)) { 4975 continue; 4976 } 4977 4978 pw.print(prefix + op.mAttributions.keyAt(i) + "=[\n"); 4979 dumpStatesLocked(pw, nowElapsed, op, op.mAttributions.keyAt(i), now, sdf, date, 4980 prefix + " "); 4981 pw.print(prefix + "]\n"); 4982 } 4983 } 4984 dumpStatesLocked(@onNull PrintWriter pw, long nowElapsed, @NonNull Op op, @Nullable String attributionTag, long now, @NonNull SimpleDateFormat sdf, @NonNull Date date, @NonNull String prefix)4985 private void dumpStatesLocked(@NonNull PrintWriter pw, long nowElapsed, @NonNull Op op, 4986 @Nullable String attributionTag, long now, @NonNull SimpleDateFormat sdf, 4987 @NonNull Date date, @NonNull String prefix) { 4988 4989 final AttributedOpEntry entry = op.createSingleAttributionEntryLocked( 4990 attributionTag).getAttributedOpEntries().get(attributionTag); 4991 4992 final ArraySet<Long> keys = entry.collectKeys(); 4993 4994 final int keyCount = keys.size(); 4995 for (int k = 0; k < keyCount; k++) { 4996 final long key = keys.valueAt(k); 4997 4998 final int uidState = AppOpsManager.extractUidStateFromKey(key); 4999 final int flags = AppOpsManager.extractFlagsFromKey(key); 5000 5001 final long accessTime = entry.getLastAccessTime(uidState, uidState, flags); 5002 final long rejectTime = entry.getLastRejectTime(uidState, uidState, flags); 5003 final long accessDuration = entry.getLastDuration(uidState, uidState, flags); 5004 final OpEventProxyInfo proxy = entry.getLastProxyInfo(uidState, uidState, flags); 5005 5006 String proxyPkg = null; 5007 String proxyAttributionTag = null; 5008 int proxyUid = Process.INVALID_UID; 5009 if (proxy != null) { 5010 proxyPkg = proxy.getPackageName(); 5011 proxyAttributionTag = proxy.getAttributionTag(); 5012 proxyUid = proxy.getUid(); 5013 } 5014 5015 if (accessTime > 0) { 5016 pw.print(prefix); 5017 pw.print("Access: "); 5018 pw.print(AppOpsManager.keyToString(key)); 5019 pw.print(" "); 5020 date.setTime(accessTime); 5021 pw.print(sdf.format(date)); 5022 pw.print(" ("); 5023 TimeUtils.formatDuration(accessTime - now, pw); 5024 pw.print(")"); 5025 if (accessDuration > 0) { 5026 pw.print(" duration="); 5027 TimeUtils.formatDuration(accessDuration, pw); 5028 } 5029 if (proxyUid >= 0) { 5030 pw.print(" proxy["); 5031 pw.print("uid="); 5032 pw.print(proxyUid); 5033 pw.print(", pkg="); 5034 pw.print(proxyPkg); 5035 pw.print(", attributionTag="); 5036 pw.print(proxyAttributionTag); 5037 pw.print("]"); 5038 } 5039 pw.println(); 5040 } 5041 5042 if (rejectTime > 0) { 5043 pw.print(prefix); 5044 pw.print("Reject: "); 5045 pw.print(AppOpsManager.keyToString(key)); 5046 date.setTime(rejectTime); 5047 pw.print(sdf.format(date)); 5048 pw.print(" ("); 5049 TimeUtils.formatDuration(rejectTime - now, pw); 5050 pw.print(")"); 5051 if (proxyUid >= 0) { 5052 pw.print(" proxy["); 5053 pw.print("uid="); 5054 pw.print(proxyUid); 5055 pw.print(", pkg="); 5056 pw.print(proxyPkg); 5057 pw.print(", attributionTag="); 5058 pw.print(proxyAttributionTag); 5059 pw.print("]"); 5060 } 5061 pw.println(); 5062 } 5063 } 5064 5065 final AttributedOp attributedOp = op.mAttributions.get(attributionTag); 5066 if (attributedOp.isRunning()) { 5067 long earliestElapsedTime = Long.MAX_VALUE; 5068 long maxNumStarts = 0; 5069 int numInProgressEvents = attributedOp.mInProgressEvents.size(); 5070 for (int i = 0; i < numInProgressEvents; i++) { 5071 InProgressStartOpEvent event = attributedOp.mInProgressEvents.valueAt(i); 5072 5073 earliestElapsedTime = Math.min(earliestElapsedTime, event.getStartElapsedTime()); 5074 maxNumStarts = Math.max(maxNumStarts, event.numUnfinishedStarts); 5075 } 5076 5077 pw.print(prefix + "Running start at: "); 5078 TimeUtils.formatDuration(nowElapsed - earliestElapsedTime, pw); 5079 pw.println(); 5080 5081 if (maxNumStarts > 1) { 5082 pw.print(prefix + "startNesting="); 5083 pw.println(maxNumStarts); 5084 } 5085 } 5086 } 5087 5088 @Override dump(FileDescriptor fd, PrintWriter pw, String[] args)5089 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 5090 if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return; 5091 5092 int dumpOp = OP_NONE; 5093 String dumpPackage = null; 5094 String dumpAttributionTag = null; 5095 int dumpUid = Process.INVALID_UID; 5096 int dumpMode = -1; 5097 boolean dumpWatchers = false; 5098 // TODO ntmyren: Remove the dumpHistory and dumpFilter 5099 boolean dumpHistory = false; 5100 @HistoricalOpsRequestFilter int dumpFilter = 0; 5101 5102 if (args != null) { 5103 for (int i=0; i<args.length; i++) { 5104 String arg = args[i]; 5105 if ("-h".equals(arg)) { 5106 dumpHelp(pw); 5107 return; 5108 } else if ("-a".equals(arg)) { 5109 // dump all data 5110 } else if ("--op".equals(arg)) { 5111 i++; 5112 if (i >= args.length) { 5113 pw.println("No argument for --op option"); 5114 return; 5115 } 5116 dumpOp = Shell.strOpToOp(args[i], pw); 5117 dumpFilter |= FILTER_BY_OP_NAMES; 5118 if (dumpOp < 0) { 5119 return; 5120 } 5121 } else if ("--package".equals(arg)) { 5122 i++; 5123 if (i >= args.length) { 5124 pw.println("No argument for --package option"); 5125 return; 5126 } 5127 dumpPackage = args[i]; 5128 dumpFilter |= FILTER_BY_PACKAGE_NAME; 5129 try { 5130 dumpUid = AppGlobals.getPackageManager().getPackageUid(dumpPackage, 5131 PackageManager.MATCH_KNOWN_PACKAGES | PackageManager.MATCH_INSTANT, 5132 0); 5133 } catch (RemoteException e) { 5134 } 5135 if (dumpUid < 0) { 5136 pw.println("Unknown package: " + dumpPackage); 5137 return; 5138 } 5139 dumpUid = UserHandle.getAppId(dumpUid); 5140 dumpFilter |= FILTER_BY_UID; 5141 } else if ("--attributionTag".equals(arg)) { 5142 i++; 5143 if (i >= args.length) { 5144 pw.println("No argument for --attributionTag option"); 5145 return; 5146 } 5147 dumpAttributionTag = args[i]; 5148 dumpFilter |= FILTER_BY_ATTRIBUTION_TAG; 5149 } else if ("--mode".equals(arg)) { 5150 i++; 5151 if (i >= args.length) { 5152 pw.println("No argument for --mode option"); 5153 return; 5154 } 5155 dumpMode = Shell.strModeToMode(args[i], pw); 5156 if (dumpMode < 0) { 5157 return; 5158 } 5159 } else if ("--watchers".equals(arg)) { 5160 dumpWatchers = true; 5161 } else if (arg.length() > 0 && arg.charAt(0) == '-'){ 5162 pw.println("Unknown option: " + arg); 5163 return; 5164 } else { 5165 pw.println("Unknown command: " + arg); 5166 return; 5167 } 5168 } 5169 } 5170 5171 synchronized (this) { 5172 pw.println("Current AppOps Service state:"); 5173 if (!dumpHistory && !dumpWatchers) { 5174 mConstants.dump(pw); 5175 } 5176 pw.println(); 5177 final long now = System.currentTimeMillis(); 5178 final long nowElapsed = SystemClock.elapsedRealtime(); 5179 final long nowUptime = SystemClock.uptimeMillis(); 5180 final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); 5181 final Date date = new Date(); 5182 boolean needSep = false; 5183 if (dumpFilter == 0 && dumpMode < 0 && mProfileOwners != null && !dumpWatchers 5184 && !dumpHistory) { 5185 pw.println(" Profile owners:"); 5186 for (int poi = 0; poi < mProfileOwners.size(); poi++) { 5187 pw.print(" User #"); 5188 pw.print(mProfileOwners.keyAt(poi)); 5189 pw.print(": "); 5190 UserHandle.formatUid(pw, mProfileOwners.valueAt(poi)); 5191 pw.println(); 5192 } 5193 pw.println(); 5194 } 5195 if (mOpModeWatchers.size() > 0 && !dumpHistory) { 5196 boolean printedHeader = false; 5197 for (int i=0; i<mOpModeWatchers.size(); i++) { 5198 if (dumpOp >= 0 && dumpOp != mOpModeWatchers.keyAt(i)) { 5199 continue; 5200 } 5201 boolean printedOpHeader = false; 5202 ArraySet<ModeCallback> callbacks = mOpModeWatchers.valueAt(i); 5203 for (int j=0; j<callbacks.size(); j++) { 5204 final ModeCallback cb = callbacks.valueAt(j); 5205 if (dumpPackage != null 5206 && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) { 5207 continue; 5208 } 5209 needSep = true; 5210 if (!printedHeader) { 5211 pw.println(" Op mode watchers:"); 5212 printedHeader = true; 5213 } 5214 if (!printedOpHeader) { 5215 pw.print(" Op "); 5216 pw.print(AppOpsManager.opToName(mOpModeWatchers.keyAt(i))); 5217 pw.println(":"); 5218 printedOpHeader = true; 5219 } 5220 pw.print(" #"); pw.print(j); pw.print(": "); 5221 pw.println(cb); 5222 } 5223 } 5224 } 5225 if (mPackageModeWatchers.size() > 0 && dumpOp < 0 && !dumpHistory) { 5226 boolean printedHeader = false; 5227 for (int i=0; i<mPackageModeWatchers.size(); i++) { 5228 if (dumpPackage != null && !dumpPackage.equals(mPackageModeWatchers.keyAt(i))) { 5229 continue; 5230 } 5231 needSep = true; 5232 if (!printedHeader) { 5233 pw.println(" Package mode watchers:"); 5234 printedHeader = true; 5235 } 5236 pw.print(" Pkg "); pw.print(mPackageModeWatchers.keyAt(i)); 5237 pw.println(":"); 5238 ArraySet<ModeCallback> callbacks = mPackageModeWatchers.valueAt(i); 5239 for (int j=0; j<callbacks.size(); j++) { 5240 pw.print(" #"); pw.print(j); pw.print(": "); 5241 pw.println(callbacks.valueAt(j)); 5242 } 5243 } 5244 } 5245 if (mModeWatchers.size() > 0 && dumpOp < 0 && !dumpHistory) { 5246 boolean printedHeader = false; 5247 for (int i=0; i<mModeWatchers.size(); i++) { 5248 final ModeCallback cb = mModeWatchers.valueAt(i); 5249 if (dumpPackage != null 5250 && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) { 5251 continue; 5252 } 5253 needSep = true; 5254 if (!printedHeader) { 5255 pw.println(" All op mode watchers:"); 5256 printedHeader = true; 5257 } 5258 pw.print(" "); 5259 pw.print(Integer.toHexString(System.identityHashCode(mModeWatchers.keyAt(i)))); 5260 pw.print(": "); pw.println(cb); 5261 } 5262 } 5263 if (mActiveWatchers.size() > 0 && dumpMode < 0) { 5264 needSep = true; 5265 boolean printedHeader = false; 5266 for (int watcherNum = 0; watcherNum < mActiveWatchers.size(); watcherNum++) { 5267 final SparseArray<ActiveCallback> activeWatchers = 5268 mActiveWatchers.valueAt(watcherNum); 5269 if (activeWatchers.size() <= 0) { 5270 continue; 5271 } 5272 final ActiveCallback cb = activeWatchers.valueAt(0); 5273 if (dumpOp >= 0 && activeWatchers.indexOfKey(dumpOp) < 0) { 5274 continue; 5275 } 5276 if (dumpPackage != null 5277 && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) { 5278 continue; 5279 } 5280 if (!printedHeader) { 5281 pw.println(" All op active watchers:"); 5282 printedHeader = true; 5283 } 5284 pw.print(" "); 5285 pw.print(Integer.toHexString(System.identityHashCode( 5286 mActiveWatchers.keyAt(watcherNum)))); 5287 pw.println(" ->"); 5288 pw.print(" ["); 5289 final int opCount = activeWatchers.size(); 5290 for (int opNum = 0; opNum < opCount; opNum++) { 5291 if (opNum > 0) { 5292 pw.print(' '); 5293 } 5294 pw.print(AppOpsManager.opToName(activeWatchers.keyAt(opNum))); 5295 if (opNum < opCount - 1) { 5296 pw.print(','); 5297 } 5298 } 5299 pw.println("]"); 5300 pw.print(" "); 5301 pw.println(cb); 5302 } 5303 } 5304 if (mStartedWatchers.size() > 0 && dumpMode < 0) { 5305 needSep = true; 5306 boolean printedHeader = false; 5307 5308 final int watchersSize = mStartedWatchers.size(); 5309 for (int watcherNum = 0; watcherNum < watchersSize; watcherNum++) { 5310 final SparseArray<StartedCallback> startedWatchers = 5311 mStartedWatchers.valueAt(watcherNum); 5312 if (startedWatchers.size() <= 0) { 5313 continue; 5314 } 5315 5316 final StartedCallback cb = startedWatchers.valueAt(0); 5317 if (dumpOp >= 0 && startedWatchers.indexOfKey(dumpOp) < 0) { 5318 continue; 5319 } 5320 5321 if (dumpPackage != null 5322 && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) { 5323 continue; 5324 } 5325 5326 if (!printedHeader) { 5327 pw.println(" All op started watchers:"); 5328 printedHeader = true; 5329 } 5330 5331 pw.print(" "); 5332 pw.print(Integer.toHexString(System.identityHashCode( 5333 mStartedWatchers.keyAt(watcherNum)))); 5334 pw.println(" ->"); 5335 5336 pw.print(" ["); 5337 final int opCount = startedWatchers.size(); 5338 for (int opNum = 0; opNum < opCount; opNum++) { 5339 if (opNum > 0) { 5340 pw.print(' '); 5341 } 5342 5343 pw.print(AppOpsManager.opToName(startedWatchers.keyAt(opNum))); 5344 if (opNum < opCount - 1) { 5345 pw.print(','); 5346 } 5347 } 5348 pw.println("]"); 5349 5350 pw.print(" "); 5351 pw.println(cb); 5352 } 5353 } 5354 if (mNotedWatchers.size() > 0 && dumpMode < 0) { 5355 needSep = true; 5356 boolean printedHeader = false; 5357 for (int watcherNum = 0; watcherNum < mNotedWatchers.size(); watcherNum++) { 5358 final SparseArray<NotedCallback> notedWatchers = 5359 mNotedWatchers.valueAt(watcherNum); 5360 if (notedWatchers.size() <= 0) { 5361 continue; 5362 } 5363 final NotedCallback cb = notedWatchers.valueAt(0); 5364 if (dumpOp >= 0 && notedWatchers.indexOfKey(dumpOp) < 0) { 5365 continue; 5366 } 5367 if (dumpPackage != null 5368 && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) { 5369 continue; 5370 } 5371 if (!printedHeader) { 5372 pw.println(" All op noted watchers:"); 5373 printedHeader = true; 5374 } 5375 pw.print(" "); 5376 pw.print(Integer.toHexString(System.identityHashCode( 5377 mNotedWatchers.keyAt(watcherNum)))); 5378 pw.println(" ->"); 5379 pw.print(" ["); 5380 final int opCount = notedWatchers.size(); 5381 for (int opNum = 0; opNum < opCount; opNum++) { 5382 if (opNum > 0) { 5383 pw.print(' '); 5384 } 5385 pw.print(AppOpsManager.opToName(notedWatchers.keyAt(opNum))); 5386 if (opNum < opCount - 1) { 5387 pw.print(','); 5388 } 5389 } 5390 pw.println("]"); 5391 pw.print(" "); 5392 pw.println(cb); 5393 } 5394 } 5395 if (mAudioRestrictionManager.hasActiveRestrictions() && dumpOp < 0 5396 && dumpPackage != null && dumpMode < 0 && !dumpWatchers && !dumpWatchers) { 5397 needSep = mAudioRestrictionManager.dump(pw) | needSep ; 5398 } 5399 if (needSep) { 5400 pw.println(); 5401 } 5402 for (int i=0; i<mUidStates.size(); i++) { 5403 UidState uidState = mUidStates.valueAt(i); 5404 final SparseIntArray opModes = uidState.opModes; 5405 final ArrayMap<String, Ops> pkgOps = uidState.pkgOps; 5406 5407 if (dumpWatchers || dumpHistory) { 5408 continue; 5409 } 5410 if (dumpOp >= 0 || dumpPackage != null || dumpMode >= 0) { 5411 boolean hasOp = dumpOp < 0 || (uidState.opModes != null 5412 && uidState.opModes.indexOfKey(dumpOp) >= 0); 5413 boolean hasPackage = dumpPackage == null || dumpUid == mUidStates.keyAt(i); 5414 boolean hasMode = dumpMode < 0; 5415 if (!hasMode && opModes != null) { 5416 for (int opi = 0; !hasMode && opi < opModes.size(); opi++) { 5417 if (opModes.valueAt(opi) == dumpMode) { 5418 hasMode = true; 5419 } 5420 } 5421 } 5422 if (pkgOps != null) { 5423 for (int pkgi = 0; 5424 (!hasOp || !hasPackage || !hasMode) && pkgi < pkgOps.size(); 5425 pkgi++) { 5426 Ops ops = pkgOps.valueAt(pkgi); 5427 if (!hasOp && ops != null && ops.indexOfKey(dumpOp) >= 0) { 5428 hasOp = true; 5429 } 5430 if (!hasMode) { 5431 for (int opi = 0; !hasMode && opi < ops.size(); opi++) { 5432 if (ops.valueAt(opi).mode == dumpMode) { 5433 hasMode = true; 5434 } 5435 } 5436 } 5437 if (!hasPackage && dumpPackage.equals(ops.packageName)) { 5438 hasPackage = true; 5439 } 5440 } 5441 } 5442 if (uidState.foregroundOps != null && !hasOp) { 5443 if (uidState.foregroundOps.indexOfKey(dumpOp) > 0) { 5444 hasOp = true; 5445 } 5446 } 5447 if (!hasOp || !hasPackage || !hasMode) { 5448 continue; 5449 } 5450 } 5451 5452 pw.print(" Uid "); UserHandle.formatUid(pw, uidState.uid); pw.println(":"); 5453 pw.print(" state="); 5454 pw.println(AppOpsManager.getUidStateName(uidState.state)); 5455 if (uidState.state != uidState.pendingState) { 5456 pw.print(" pendingState="); 5457 pw.println(AppOpsManager.getUidStateName(uidState.pendingState)); 5458 } 5459 pw.print(" capability="); 5460 ActivityManager.printCapabilitiesFull(pw, uidState.capability); 5461 pw.println(); 5462 if (uidState.capability != uidState.pendingCapability) { 5463 pw.print(" pendingCapability="); 5464 ActivityManager.printCapabilitiesFull(pw, uidState.pendingCapability); 5465 pw.println(); 5466 } 5467 pw.print(" appWidgetVisible="); 5468 pw.println(uidState.appWidgetVisible); 5469 if (uidState.appWidgetVisible != uidState.pendingAppWidgetVisible) { 5470 pw.print(" pendingAppWidgetVisible="); 5471 pw.println(uidState.pendingAppWidgetVisible); 5472 } 5473 if (uidState.pendingStateCommitTime != 0) { 5474 pw.print(" pendingStateCommitTime="); 5475 TimeUtils.formatDuration(uidState.pendingStateCommitTime, nowElapsed, pw); 5476 pw.println(); 5477 } 5478 if (uidState.foregroundOps != null && (dumpMode < 0 5479 || dumpMode == AppOpsManager.MODE_FOREGROUND)) { 5480 pw.println(" foregroundOps:"); 5481 for (int j = 0; j < uidState.foregroundOps.size(); j++) { 5482 if (dumpOp >= 0 && dumpOp != uidState.foregroundOps.keyAt(j)) { 5483 continue; 5484 } 5485 pw.print(" "); 5486 pw.print(AppOpsManager.opToName(uidState.foregroundOps.keyAt(j))); 5487 pw.print(": "); 5488 pw.println(uidState.foregroundOps.valueAt(j) ? "WATCHER" : "SILENT"); 5489 } 5490 pw.print(" hasForegroundWatchers="); 5491 pw.println(uidState.hasForegroundWatchers); 5492 } 5493 needSep = true; 5494 5495 if (opModes != null) { 5496 final int opModeCount = opModes.size(); 5497 for (int j = 0; j < opModeCount; j++) { 5498 final int code = opModes.keyAt(j); 5499 final int mode = opModes.valueAt(j); 5500 if (dumpOp >= 0 && dumpOp != code) { 5501 continue; 5502 } 5503 if (dumpMode >= 0 && dumpMode != mode) { 5504 continue; 5505 } 5506 pw.print(" "); pw.print(AppOpsManager.opToName(code)); 5507 pw.print(": mode="); pw.println(AppOpsManager.modeToName(mode)); 5508 } 5509 } 5510 5511 if (pkgOps == null) { 5512 continue; 5513 } 5514 5515 for (int pkgi = 0; pkgi < pkgOps.size(); pkgi++) { 5516 final Ops ops = pkgOps.valueAt(pkgi); 5517 if (dumpPackage != null && !dumpPackage.equals(ops.packageName)) { 5518 continue; 5519 } 5520 boolean printedPackage = false; 5521 for (int j=0; j<ops.size(); j++) { 5522 final Op op = ops.valueAt(j); 5523 final int opCode = op.op; 5524 if (dumpOp >= 0 && dumpOp != opCode) { 5525 continue; 5526 } 5527 if (dumpMode >= 0 && dumpMode != op.mode) { 5528 continue; 5529 } 5530 if (!printedPackage) { 5531 pw.print(" Package "); pw.print(ops.packageName); pw.println(":"); 5532 printedPackage = true; 5533 } 5534 pw.print(" "); pw.print(AppOpsManager.opToName(opCode)); 5535 pw.print(" ("); pw.print(AppOpsManager.modeToName(op.mode)); 5536 final int switchOp = AppOpsManager.opToSwitch(opCode); 5537 if (switchOp != opCode) { 5538 pw.print(" / switch "); 5539 pw.print(AppOpsManager.opToName(switchOp)); 5540 final Op switchObj = ops.get(switchOp); 5541 int mode = switchObj != null ? switchObj.mode 5542 : AppOpsManager.opToDefaultMode(switchOp); 5543 pw.print("="); pw.print(AppOpsManager.modeToName(mode)); 5544 } 5545 pw.println("): "); 5546 dumpStatesLocked(pw, dumpAttributionTag, dumpFilter, nowElapsed, op, now, 5547 sdf, date, " "); 5548 } 5549 } 5550 } 5551 if (needSep) { 5552 pw.println(); 5553 } 5554 5555 final int userRestrictionCount = mOpUserRestrictions.size(); 5556 for (int i = 0; i < userRestrictionCount; i++) { 5557 IBinder token = mOpUserRestrictions.keyAt(i); 5558 ClientRestrictionState restrictionState = mOpUserRestrictions.valueAt(i); 5559 boolean printedTokenHeader = false; 5560 5561 if (dumpMode >= 0 || dumpWatchers || dumpHistory) { 5562 continue; 5563 } 5564 5565 final int restrictionCount = restrictionState.perUserRestrictions != null 5566 ? restrictionState.perUserRestrictions.size() : 0; 5567 if (restrictionCount > 0 && dumpPackage == null) { 5568 boolean printedOpsHeader = false; 5569 for (int j = 0; j < restrictionCount; j++) { 5570 int userId = restrictionState.perUserRestrictions.keyAt(j); 5571 boolean[] restrictedOps = restrictionState.perUserRestrictions.valueAt(j); 5572 if (restrictedOps == null) { 5573 continue; 5574 } 5575 if (dumpOp >= 0 && (dumpOp >= restrictedOps.length 5576 || !restrictedOps[dumpOp])) { 5577 continue; 5578 } 5579 if (!printedTokenHeader) { 5580 pw.println(" User restrictions for token " + token + ":"); 5581 printedTokenHeader = true; 5582 } 5583 if (!printedOpsHeader) { 5584 pw.println(" Restricted ops:"); 5585 printedOpsHeader = true; 5586 } 5587 StringBuilder restrictedOpsValue = new StringBuilder(); 5588 restrictedOpsValue.append("["); 5589 final int restrictedOpCount = restrictedOps.length; 5590 for (int k = 0; k < restrictedOpCount; k++) { 5591 if (restrictedOps[k]) { 5592 if (restrictedOpsValue.length() > 1) { 5593 restrictedOpsValue.append(", "); 5594 } 5595 restrictedOpsValue.append(AppOpsManager.opToName(k)); 5596 } 5597 } 5598 restrictedOpsValue.append("]"); 5599 pw.print(" "); pw.print("user: "); pw.print(userId); 5600 pw.print(" restricted ops: "); pw.println(restrictedOpsValue); 5601 } 5602 } 5603 5604 final int excludedPackageCount = restrictionState.perUserExcludedPackages != null 5605 ? restrictionState.perUserExcludedPackages.size() : 0; 5606 if (excludedPackageCount > 0 && dumpOp < 0) { 5607 boolean printedPackagesHeader = false; 5608 for (int j = 0; j < excludedPackageCount; j++) { 5609 int userId = restrictionState.perUserExcludedPackages.keyAt(j); 5610 String[] packageNames = restrictionState.perUserExcludedPackages.valueAt(j); 5611 if (packageNames == null) { 5612 continue; 5613 } 5614 boolean hasPackage; 5615 if (dumpPackage != null) { 5616 hasPackage = false; 5617 for (String pkg : packageNames) { 5618 if (dumpPackage.equals(pkg)) { 5619 hasPackage = true; 5620 break; 5621 } 5622 } 5623 } else { 5624 hasPackage = true; 5625 } 5626 if (!hasPackage) { 5627 continue; 5628 } 5629 if (!printedTokenHeader) { 5630 pw.println(" User restrictions for token " + token + ":"); 5631 printedTokenHeader = true; 5632 } 5633 if (!printedPackagesHeader) { 5634 pw.println(" Excluded packages:"); 5635 printedPackagesHeader = true; 5636 } 5637 pw.print(" "); pw.print("user: "); pw.print(userId); 5638 pw.print(" packages: "); pw.println(Arrays.toString(packageNames)); 5639 } 5640 } 5641 } 5642 } 5643 5644 // Must not hold the appops lock 5645 if (dumpHistory && !dumpWatchers) { 5646 mHistoricalRegistry.dump(" ", pw, dumpUid, dumpPackage, dumpAttributionTag, dumpOp, 5647 dumpFilter); 5648 } 5649 } 5650 5651 @Override setUserRestrictions(Bundle restrictions, IBinder token, int userHandle)5652 public void setUserRestrictions(Bundle restrictions, IBinder token, int userHandle) { 5653 checkSystemUid("setUserRestrictions"); 5654 Objects.requireNonNull(restrictions); 5655 Objects.requireNonNull(token); 5656 for (int i = 0; i < AppOpsManager._NUM_OP; i++) { 5657 String restriction = AppOpsManager.opToRestriction(i); 5658 if (restriction != null) { 5659 setUserRestrictionNoCheck(i, restrictions.getBoolean(restriction, false), token, 5660 userHandle, null); 5661 } 5662 } 5663 } 5664 5665 @Override setUserRestriction(int code, boolean restricted, IBinder token, int userHandle, String[] exceptionPackages)5666 public void setUserRestriction(int code, boolean restricted, IBinder token, int userHandle, 5667 String[] exceptionPackages) { 5668 if (Binder.getCallingPid() != Process.myPid()) { 5669 mContext.enforcePermission(Manifest.permission.MANAGE_APP_OPS_RESTRICTIONS, 5670 Binder.getCallingPid(), Binder.getCallingUid(), null); 5671 } 5672 if (userHandle != UserHandle.getCallingUserId()) { 5673 if (mContext.checkCallingOrSelfPermission(Manifest.permission 5674 .INTERACT_ACROSS_USERS_FULL) != PackageManager.PERMISSION_GRANTED 5675 && mContext.checkCallingOrSelfPermission(Manifest.permission 5676 .INTERACT_ACROSS_USERS) != PackageManager.PERMISSION_GRANTED) { 5677 throw new SecurityException("Need INTERACT_ACROSS_USERS_FULL or" 5678 + " INTERACT_ACROSS_USERS to interact cross user "); 5679 } 5680 } 5681 verifyIncomingOp(code); 5682 Objects.requireNonNull(token); 5683 setUserRestrictionNoCheck(code, restricted, token, userHandle, exceptionPackages); 5684 } 5685 setUserRestrictionNoCheck(int code, boolean restricted, IBinder token, int userHandle, String[] exceptionPackages)5686 private void setUserRestrictionNoCheck(int code, boolean restricted, IBinder token, 5687 int userHandle, String[] exceptionPackages) { 5688 synchronized (AppOpsService.this) { 5689 ClientRestrictionState restrictionState = mOpUserRestrictions.get(token); 5690 5691 if (restrictionState == null) { 5692 try { 5693 restrictionState = new ClientRestrictionState(token); 5694 } catch (RemoteException e) { 5695 return; 5696 } 5697 mOpUserRestrictions.put(token, restrictionState); 5698 } 5699 5700 if (restrictionState.setRestriction(code, restricted, exceptionPackages, userHandle)) { 5701 mHandler.sendMessage(PooledLambda.obtainMessage( 5702 AppOpsService::notifyWatchersOfChange, this, code, UID_ANY)); 5703 } 5704 5705 if (restrictionState.isDefault()) { 5706 mOpUserRestrictions.remove(token); 5707 restrictionState.destroy(); 5708 } 5709 } 5710 } 5711 notifyWatchersOfChange(int code, int uid)5712 private void notifyWatchersOfChange(int code, int uid) { 5713 final ArraySet<ModeCallback> clonedCallbacks; 5714 synchronized (this) { 5715 ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code); 5716 if (callbacks == null) { 5717 return; 5718 } 5719 clonedCallbacks = new ArraySet<>(callbacks); 5720 } 5721 5722 notifyOpChanged(clonedCallbacks, code, uid, null); 5723 } 5724 5725 @Override removeUser(int userHandle)5726 public void removeUser(int userHandle) throws RemoteException { 5727 checkSystemUid("removeUser"); 5728 synchronized (AppOpsService.this) { 5729 final int tokenCount = mOpUserRestrictions.size(); 5730 for (int i = tokenCount - 1; i >= 0; i--) { 5731 ClientRestrictionState opRestrictions = mOpUserRestrictions.valueAt(i); 5732 opRestrictions.removeUser(userHandle); 5733 } 5734 removeUidsForUserLocked(userHandle); 5735 } 5736 } 5737 5738 @Override isOperationActive(int code, int uid, String packageName)5739 public boolean isOperationActive(int code, int uid, String packageName) { 5740 if (Binder.getCallingUid() != uid) { 5741 if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS) 5742 != PackageManager.PERMISSION_GRANTED) { 5743 return false; 5744 } 5745 } 5746 verifyIncomingOp(code); 5747 final String resolvedPackageName = resolvePackageName(uid, packageName); 5748 if (resolvedPackageName == null) { 5749 return false; 5750 } 5751 // TODO moltmann: Allow to check for attribution op activeness 5752 synchronized (AppOpsService.this) { 5753 Ops pkgOps = getOpsLocked(uid, resolvedPackageName, null, null, false); 5754 if (pkgOps == null) { 5755 return false; 5756 } 5757 5758 Op op = pkgOps.get(code); 5759 if (op == null) { 5760 return false; 5761 } 5762 5763 return op.isRunning(); 5764 } 5765 } 5766 5767 @Override setHistoryParameters(@ppOpsManager.HistoricalMode int mode, long baseSnapshotInterval, int compressionStep)5768 public void setHistoryParameters(@AppOpsManager.HistoricalMode int mode, 5769 long baseSnapshotInterval, int compressionStep) { 5770 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS, 5771 "setHistoryParameters"); 5772 // Must not hold the appops lock 5773 mHistoricalRegistry.setHistoryParameters(mode, baseSnapshotInterval, compressionStep); 5774 } 5775 5776 @Override offsetHistory(long offsetMillis)5777 public void offsetHistory(long offsetMillis) { 5778 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS, 5779 "offsetHistory"); 5780 // Must not hold the appops lock 5781 mHistoricalRegistry.offsetHistory(offsetMillis); 5782 } 5783 5784 @Override addHistoricalOps(HistoricalOps ops)5785 public void addHistoricalOps(HistoricalOps ops) { 5786 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS, 5787 "addHistoricalOps"); 5788 // Must not hold the appops lock 5789 mHistoricalRegistry.addHistoricalOps(ops); 5790 } 5791 5792 @Override resetHistoryParameters()5793 public void resetHistoryParameters() { 5794 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS, 5795 "resetHistoryParameters"); 5796 // Must not hold the appops lock 5797 mHistoricalRegistry.resetHistoryParameters(); 5798 } 5799 5800 @Override clearHistory()5801 public void clearHistory() { 5802 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS, 5803 "clearHistory"); 5804 // Must not hold the appops lock 5805 mHistoricalRegistry.clearHistory(); 5806 } 5807 5808 @Override rebootHistory(long offlineDurationMillis)5809 public void rebootHistory(long offlineDurationMillis) { 5810 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS, 5811 "rebootHistory"); 5812 5813 Preconditions.checkArgument(offlineDurationMillis >= 0); 5814 5815 // Must not hold the appops lock 5816 mHistoricalRegistry.shutdown(); 5817 5818 if (offlineDurationMillis > 0) { 5819 SystemClock.sleep(offlineDurationMillis); 5820 } 5821 5822 mHistoricalRegistry = new HistoricalRegistry(mHistoricalRegistry); 5823 mHistoricalRegistry.systemReady(mContext.getContentResolver()); 5824 mHistoricalRegistry.persistPendingHistory(); 5825 } 5826 5827 /** 5828 * Report runtime access to AppOp together with message (including stack trace) 5829 * 5830 * @param packageName The package which reported the op 5831 * @param notedAppOp contains code of op and attributionTag provided by developer 5832 * @param message Message describing AppOp access (can be stack trace) 5833 * 5834 * @return Config for future sampling to reduce amount of reporting 5835 */ 5836 @Override reportRuntimeAppOpAccessMessageAndGetConfig( String packageName, SyncNotedAppOp notedAppOp, String message)5837 public MessageSamplingConfig reportRuntimeAppOpAccessMessageAndGetConfig( 5838 String packageName, SyncNotedAppOp notedAppOp, String message) { 5839 int uid = Binder.getCallingUid(); 5840 Objects.requireNonNull(packageName); 5841 synchronized (this) { 5842 switchPackageIfBootTimeOrRarelyUsedLocked(packageName); 5843 if (!packageName.equals(mSampledPackage)) { 5844 return new MessageSamplingConfig(OP_NONE, 0, 5845 Instant.now().plus(1, ChronoUnit.HOURS).toEpochMilli()); 5846 } 5847 5848 Objects.requireNonNull(notedAppOp); 5849 Objects.requireNonNull(message); 5850 5851 reportRuntimeAppOpAccessMessageInternalLocked(uid, packageName, 5852 AppOpsManager.strOpToOp(notedAppOp.getOp()), 5853 notedAppOp.getAttributionTag(), message); 5854 5855 return new MessageSamplingConfig(mSampledAppOpCode, mAcceptableLeftDistance, 5856 Instant.now().plus(1, ChronoUnit.HOURS).toEpochMilli()); 5857 } 5858 } 5859 5860 /** 5861 * Report runtime access to AppOp together with message (entry point for reporting 5862 * asynchronous access) 5863 * @param uid Uid of the package which reported the op 5864 * @param packageName The package which reported the op 5865 * @param opCode Code of AppOp 5866 * @param attributionTag FeautreId of AppOp reported 5867 * @param message Message describing AppOp access (can be stack trace) 5868 */ reportRuntimeAppOpAccessMessageAsyncLocked(int uid, @NonNull String packageName, int opCode, @Nullable String attributionTag, @NonNull String message)5869 private void reportRuntimeAppOpAccessMessageAsyncLocked(int uid, 5870 @NonNull String packageName, int opCode, @Nullable String attributionTag, 5871 @NonNull String message) { 5872 switchPackageIfBootTimeOrRarelyUsedLocked(packageName); 5873 if (!Objects.equals(mSampledPackage, packageName)) { 5874 return; 5875 } 5876 reportRuntimeAppOpAccessMessageInternalLocked(uid, packageName, opCode, attributionTag, 5877 message); 5878 } 5879 5880 /** 5881 * Decides whether reported message is within the range of watched AppOps and picks it for 5882 * reporting uniformly at random across all received messages. 5883 */ reportRuntimeAppOpAccessMessageInternalLocked(int uid, @NonNull String packageName, int opCode, @Nullable String attributionTag, @NonNull String message)5884 private void reportRuntimeAppOpAccessMessageInternalLocked(int uid, 5885 @NonNull String packageName, int opCode, @Nullable String attributionTag, 5886 @NonNull String message) { 5887 int newLeftDistance = AppOpsManager.leftCircularDistance(opCode, 5888 mSampledAppOpCode, _NUM_OP); 5889 5890 if (mAcceptableLeftDistance < newLeftDistance) { 5891 return; 5892 } 5893 5894 if (mAcceptableLeftDistance > newLeftDistance) { 5895 mAcceptableLeftDistance = newLeftDistance; 5896 mMessagesCollectedCount = 0.0f; 5897 } 5898 5899 mMessagesCollectedCount += 1.0f; 5900 if (ThreadLocalRandom.current().nextFloat() <= 1.0f / mMessagesCollectedCount) { 5901 mCollectedRuntimePermissionMessage = new RuntimeAppOpAccessMessage(uid, opCode, 5902 packageName, attributionTag, message, mSamplingStrategy); 5903 } 5904 return; 5905 } 5906 5907 /** Pulls current AppOps access report and resamples package and app op to watch */ 5908 @Override collectRuntimeAppOpAccessMessage()5909 public @Nullable RuntimeAppOpAccessMessage collectRuntimeAppOpAccessMessage() { 5910 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS, 5911 Binder.getCallingPid(), Binder.getCallingUid(), null); 5912 RuntimeAppOpAccessMessage result; 5913 synchronized (this) { 5914 result = mCollectedRuntimePermissionMessage; 5915 mCollectedRuntimePermissionMessage = null; 5916 } 5917 mHandler.sendMessage(PooledLambda.obtainMessage( 5918 AppOpsService::getPackageListAndResample, 5919 this)); 5920 return result; 5921 } 5922 5923 /** 5924 * Checks if package is in the list of rarely used package and starts watching the new package 5925 * to collect incoming message or if collection is happening in first minutes since boot. 5926 * @param packageName 5927 */ switchPackageIfBootTimeOrRarelyUsedLocked(@onNull String packageName)5928 private void switchPackageIfBootTimeOrRarelyUsedLocked(@NonNull String packageName) { 5929 if (mSampledPackage == null) { 5930 if (ThreadLocalRandom.current().nextFloat() < 0.5f) { 5931 mSamplingStrategy = SAMPLING_STRATEGY_BOOT_TIME_SAMPLING; 5932 resampleAppOpForPackageLocked(packageName); 5933 } 5934 } else if (mRarelyUsedPackages.contains(packageName)) { 5935 mRarelyUsedPackages.remove(packageName); 5936 if (ThreadLocalRandom.current().nextFloat() < 0.5f) { 5937 mSamplingStrategy = SAMPLING_STRATEGY_RARELY_USED; 5938 resampleAppOpForPackageLocked(packageName); 5939 } 5940 } 5941 } 5942 5943 /** Obtains package list and resamples package and appop to watch. */ getPackageListAndResample()5944 private List<String> getPackageListAndResample() { 5945 List<String> packageNames = getPackageNamesForSampling(); 5946 synchronized (this) { 5947 resamplePackageAndAppOpLocked(packageNames); 5948 } 5949 return packageNames; 5950 } 5951 5952 /** Resamples package and appop to watch from the list provided. */ resamplePackageAndAppOpLocked(@onNull List<String> packageNames)5953 private void resamplePackageAndAppOpLocked(@NonNull List<String> packageNames) { 5954 if (!packageNames.isEmpty()) { 5955 mSamplingStrategy = SAMPLING_STRATEGY_UNIFORM; 5956 resampleAppOpForPackageLocked(packageNames.get( 5957 ThreadLocalRandom.current().nextInt(packageNames.size()))); 5958 } 5959 } 5960 5961 /** Resamples appop for the chosen package and initializes sampling state */ resampleAppOpForPackageLocked(@onNull String packageName)5962 private void resampleAppOpForPackageLocked(@NonNull String packageName) { 5963 mMessagesCollectedCount = 0.0f; 5964 mSampledAppOpCode = ThreadLocalRandom.current().nextInt(_NUM_OP); 5965 mAcceptableLeftDistance = _NUM_OP; 5966 mSampledPackage = packageName; 5967 } 5968 5969 /** 5970 * Creates list of rarely used packages - packages which were not used over last week or 5971 * which declared but did not use permissions over last week. 5972 * */ initializeRarelyUsedPackagesList(@onNull ArraySet<String> candidates)5973 private void initializeRarelyUsedPackagesList(@NonNull ArraySet<String> candidates) { 5974 AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class); 5975 List<String> runtimeAppOpsList = getRuntimeAppOpsList(); 5976 AppOpsManager.HistoricalOpsRequest histOpsRequest = 5977 new AppOpsManager.HistoricalOpsRequest.Builder( 5978 Math.max(Instant.now().minus(7, ChronoUnit.DAYS).toEpochMilli(), 0), 5979 Long.MAX_VALUE).setOpNames(runtimeAppOpsList).setFlags( 5980 OP_FLAG_SELF | OP_FLAG_TRUSTED_PROXIED).build(); 5981 appOps.getHistoricalOps(histOpsRequest, AsyncTask.THREAD_POOL_EXECUTOR, 5982 new Consumer<HistoricalOps>() { 5983 @Override 5984 public void accept(HistoricalOps histOps) { 5985 int uidCount = histOps.getUidCount(); 5986 for (int uidIdx = 0; uidIdx < uidCount; uidIdx++) { 5987 final AppOpsManager.HistoricalUidOps uidOps = histOps.getUidOpsAt( 5988 uidIdx); 5989 int pkgCount = uidOps.getPackageCount(); 5990 for (int pkgIdx = 0; pkgIdx < pkgCount; pkgIdx++) { 5991 String packageName = uidOps.getPackageOpsAt( 5992 pkgIdx).getPackageName(); 5993 if (!candidates.contains(packageName)) { 5994 continue; 5995 } 5996 AppOpsManager.HistoricalPackageOps packageOps = 5997 uidOps.getPackageOpsAt(pkgIdx); 5998 if (packageOps.getOpCount() != 0) { 5999 candidates.remove(packageName); 6000 } 6001 } 6002 } 6003 synchronized (this) { 6004 int numPkgs = mRarelyUsedPackages.size(); 6005 for (int i = 0; i < numPkgs; i++) { 6006 candidates.add(mRarelyUsedPackages.valueAt(i)); 6007 } 6008 mRarelyUsedPackages = candidates; 6009 } 6010 } 6011 }); 6012 } 6013 6014 /** List of app ops related to runtime permissions */ getRuntimeAppOpsList()6015 private List<String> getRuntimeAppOpsList() { 6016 ArrayList<String> result = new ArrayList(); 6017 for (int i = 0; i < _NUM_OP; i++) { 6018 if (shouldCollectNotes(i)) { 6019 result.add(opToPublicName(i)); 6020 } 6021 } 6022 return result; 6023 } 6024 6025 /** Returns list of packages to be used for package sampling */ getPackageNamesForSampling()6026 private @NonNull List<String> getPackageNamesForSampling() { 6027 List<String> packageNames = new ArrayList<>(); 6028 PackageManagerInternal packageManagerInternal = LocalServices.getService( 6029 PackageManagerInternal.class); 6030 PackageList packages = packageManagerInternal.getPackageList(); 6031 for (String packageName : packages.getPackageNames()) { 6032 PackageInfo pkg = packageManagerInternal.getPackageInfo(packageName, 6033 PackageManager.GET_PERMISSIONS, Process.myUid(), mContext.getUserId()); 6034 if (isSamplingTarget(pkg)) { 6035 packageNames.add(pkg.packageName); 6036 } 6037 } 6038 return packageNames; 6039 } 6040 6041 /** Checks whether package should be included in sampling pool */ isSamplingTarget(@ullable PackageInfo pkg)6042 private boolean isSamplingTarget(@Nullable PackageInfo pkg) { 6043 if (pkg == null) { 6044 return false; 6045 } 6046 String[] requestedPermissions = pkg.requestedPermissions; 6047 if (requestedPermissions == null) { 6048 return false; 6049 } 6050 for (String permission : requestedPermissions) { 6051 PermissionInfo permissionInfo; 6052 try { 6053 permissionInfo = mContext.getPackageManager().getPermissionInfo(permission, 0); 6054 } catch (PackageManager.NameNotFoundException ignored) { 6055 continue; 6056 } 6057 if (permissionInfo.getProtection() == PROTECTION_DANGEROUS) { 6058 return true; 6059 } 6060 } 6061 return false; 6062 } 6063 removeUidsForUserLocked(int userHandle)6064 private void removeUidsForUserLocked(int userHandle) { 6065 for (int i = mUidStates.size() - 1; i >= 0; --i) { 6066 final int uid = mUidStates.keyAt(i); 6067 if (UserHandle.getUserId(uid) == userHandle) { 6068 mUidStates.removeAt(i); 6069 } 6070 } 6071 } 6072 checkSystemUid(String function)6073 private void checkSystemUid(String function) { 6074 int uid = Binder.getCallingUid(); 6075 if (uid != Process.SYSTEM_UID) { 6076 throw new SecurityException(function + " must by called by the system"); 6077 } 6078 } 6079 resolvePackageName(int uid, String packageName)6080 private static String resolvePackageName(int uid, String packageName) { 6081 if (uid == Process.ROOT_UID) { 6082 return "root"; 6083 } else if (uid == Process.SHELL_UID) { 6084 return "com.android.shell"; 6085 } else if (uid == Process.MEDIA_UID) { 6086 return "media"; 6087 } else if (uid == Process.AUDIOSERVER_UID) { 6088 return "audioserver"; 6089 } else if (uid == Process.CAMERASERVER_UID) { 6090 return "cameraserver"; 6091 } else if (uid == Process.SYSTEM_UID && packageName == null) { 6092 return "android"; 6093 } 6094 return packageName; 6095 } 6096 resolveUid(String packageName)6097 private static int resolveUid(String packageName) { 6098 if (packageName == null) { 6099 return -1; 6100 } 6101 switch (packageName) { 6102 case "root": 6103 return Process.ROOT_UID; 6104 case "shell": 6105 return Process.SHELL_UID; 6106 case "media": 6107 return Process.MEDIA_UID; 6108 case "audioserver": 6109 return Process.AUDIOSERVER_UID; 6110 case "cameraserver": 6111 return Process.CAMERASERVER_UID; 6112 } 6113 return -1; 6114 } 6115 getPackagesForUid(int uid)6116 private static String[] getPackagesForUid(int uid) { 6117 String[] packageNames = null; 6118 6119 // Very early during boot the package manager is not yet or not yet fully started. At this 6120 // time there are no packages yet. 6121 if (AppGlobals.getPackageManager() != null) { 6122 try { 6123 packageNames = AppGlobals.getPackageManager().getPackagesForUid(uid); 6124 } catch (RemoteException e) { 6125 /* ignore - local call */ 6126 } 6127 } 6128 if (packageNames == null) { 6129 return EmptyArray.STRING; 6130 } 6131 return packageNames; 6132 } 6133 6134 private final class ClientRestrictionState implements DeathRecipient { 6135 private final IBinder token; 6136 SparseArray<boolean[]> perUserRestrictions; 6137 SparseArray<String[]> perUserExcludedPackages; 6138 ClientRestrictionState(IBinder token)6139 public ClientRestrictionState(IBinder token) 6140 throws RemoteException { 6141 token.linkToDeath(this, 0); 6142 this.token = token; 6143 } 6144 setRestriction(int code, boolean restricted, String[] excludedPackages, int userId)6145 public boolean setRestriction(int code, boolean restricted, 6146 String[] excludedPackages, int userId) { 6147 boolean changed = false; 6148 6149 if (perUserRestrictions == null && restricted) { 6150 perUserRestrictions = new SparseArray<>(); 6151 } 6152 6153 int[] users; 6154 if (userId == UserHandle.USER_ALL) { 6155 List<UserInfo> liveUsers = UserManager.get(mContext).getUsers(false); 6156 6157 users = new int[liveUsers.size()]; 6158 for (int i = 0; i < liveUsers.size(); i++) { 6159 users[i] = liveUsers.get(i).id; 6160 } 6161 } else { 6162 users = new int[]{userId}; 6163 } 6164 6165 if (perUserRestrictions != null) { 6166 int numUsers = users.length; 6167 6168 for (int i = 0; i < numUsers; i++) { 6169 int thisUserId = users[i]; 6170 6171 boolean[] userRestrictions = perUserRestrictions.get(thisUserId); 6172 if (userRestrictions == null && restricted) { 6173 userRestrictions = new boolean[AppOpsManager._NUM_OP]; 6174 perUserRestrictions.put(thisUserId, userRestrictions); 6175 } 6176 if (userRestrictions != null && userRestrictions[code] != restricted) { 6177 userRestrictions[code] = restricted; 6178 if (!restricted && isDefault(userRestrictions)) { 6179 perUserRestrictions.remove(thisUserId); 6180 userRestrictions = null; 6181 } 6182 changed = true; 6183 } 6184 6185 if (userRestrictions != null) { 6186 final boolean noExcludedPackages = ArrayUtils.isEmpty(excludedPackages); 6187 if (perUserExcludedPackages == null && !noExcludedPackages) { 6188 perUserExcludedPackages = new SparseArray<>(); 6189 } 6190 if (perUserExcludedPackages != null && !Arrays.equals(excludedPackages, 6191 perUserExcludedPackages.get(thisUserId))) { 6192 if (noExcludedPackages) { 6193 perUserExcludedPackages.remove(thisUserId); 6194 if (perUserExcludedPackages.size() <= 0) { 6195 perUserExcludedPackages = null; 6196 } 6197 } else { 6198 perUserExcludedPackages.put(thisUserId, excludedPackages); 6199 } 6200 changed = true; 6201 } 6202 } 6203 } 6204 } 6205 6206 return changed; 6207 } 6208 hasRestriction(int restriction, String packageName, int userId)6209 public boolean hasRestriction(int restriction, String packageName, int userId) { 6210 if (perUserRestrictions == null) { 6211 return false; 6212 } 6213 boolean[] restrictions = perUserRestrictions.get(userId); 6214 if (restrictions == null) { 6215 return false; 6216 } 6217 if (!restrictions[restriction]) { 6218 return false; 6219 } 6220 if (perUserExcludedPackages == null) { 6221 return true; 6222 } 6223 String[] perUserExclusions = perUserExcludedPackages.get(userId); 6224 if (perUserExclusions == null) { 6225 return true; 6226 } 6227 return !ArrayUtils.contains(perUserExclusions, packageName); 6228 } 6229 removeUser(int userId)6230 public void removeUser(int userId) { 6231 if (perUserExcludedPackages != null) { 6232 perUserExcludedPackages.remove(userId); 6233 if (perUserExcludedPackages.size() <= 0) { 6234 perUserExcludedPackages = null; 6235 } 6236 } 6237 if (perUserRestrictions != null) { 6238 perUserRestrictions.remove(userId); 6239 if (perUserRestrictions.size() <= 0) { 6240 perUserRestrictions = null; 6241 } 6242 } 6243 } 6244 isDefault()6245 public boolean isDefault() { 6246 return perUserRestrictions == null || perUserRestrictions.size() <= 0; 6247 } 6248 6249 @Override binderDied()6250 public void binderDied() { 6251 synchronized (AppOpsService.this) { 6252 mOpUserRestrictions.remove(token); 6253 if (perUserRestrictions == null) { 6254 return; 6255 } 6256 final int userCount = perUserRestrictions.size(); 6257 for (int i = 0; i < userCount; i++) { 6258 final boolean[] restrictions = perUserRestrictions.valueAt(i); 6259 final int restrictionCount = restrictions.length; 6260 for (int j = 0; j < restrictionCount; j++) { 6261 if (restrictions[j]) { 6262 final int changedCode = j; 6263 mHandler.post(() -> notifyWatchersOfChange(changedCode, UID_ANY)); 6264 } 6265 } 6266 } 6267 destroy(); 6268 } 6269 } 6270 destroy()6271 public void destroy() { 6272 token.unlinkToDeath(this, 0); 6273 } 6274 isDefault(boolean[] array)6275 private boolean isDefault(boolean[] array) { 6276 if (ArrayUtils.isEmpty(array)) { 6277 return true; 6278 } 6279 for (boolean value : array) { 6280 if (value) { 6281 return false; 6282 } 6283 } 6284 return true; 6285 } 6286 } 6287 6288 private final class AppOpsManagerInternalImpl extends AppOpsManagerInternal { setDeviceAndProfileOwners(SparseIntArray owners)6289 @Override public void setDeviceAndProfileOwners(SparseIntArray owners) { 6290 synchronized (AppOpsService.this) { 6291 mProfileOwners = owners; 6292 } 6293 } 6294 6295 @Override updateAppWidgetVisibility(SparseArray<String> uidPackageNames, boolean visible)6296 public void updateAppWidgetVisibility(SparseArray<String> uidPackageNames, 6297 boolean visible) { 6298 AppOpsService.this.updateAppWidgetVisibility(uidPackageNames, visible); 6299 } 6300 6301 @Override setUidModeFromPermissionPolicy(int code, int uid, int mode, @Nullable IAppOpsCallback callback)6302 public void setUidModeFromPermissionPolicy(int code, int uid, int mode, 6303 @Nullable IAppOpsCallback callback) { 6304 setUidMode(code, uid, mode, callback); 6305 } 6306 6307 @Override setModeFromPermissionPolicy(int code, int uid, @NonNull String packageName, int mode, @Nullable IAppOpsCallback callback)6308 public void setModeFromPermissionPolicy(int code, int uid, @NonNull String packageName, 6309 int mode, @Nullable IAppOpsCallback callback) { 6310 setMode(code, uid, packageName, mode, callback); 6311 } 6312 } 6313 6314 6315 /** 6316 * Async task for writing note op stack trace, op code, package name and version to file 6317 * More specifically, writes all the collected ops from {@link #mNoteOpCallerStacktraces} 6318 */ writeNoteOps()6319 private void writeNoteOps() { 6320 synchronized (this) { 6321 mWriteNoteOpsScheduled = false; 6322 } 6323 synchronized (mNoteOpCallerStacktracesFile) { 6324 try (FileWriter writer = new FileWriter(mNoteOpCallerStacktracesFile)) { 6325 int numTraces = mNoteOpCallerStacktraces.size(); 6326 for (int i = 0; i < numTraces; i++) { 6327 // Writing json formatted string into file 6328 writer.write(mNoteOpCallerStacktraces.valueAt(i).asJson()); 6329 // Comma separation, so we can wrap the entire log as a JSON object 6330 // when all results are collected 6331 writer.write(","); 6332 } 6333 } catch (IOException e) { 6334 Slog.w(TAG, "Failed to load opsValidation file for FileWriter", e); 6335 } 6336 } 6337 } 6338 6339 /** 6340 * This class represents a NoteOp Trace object amd contains the necessary fields that will 6341 * be written to file to use for permissions data validation in JSON format 6342 */ 6343 @Immutable 6344 static class NoteOpTrace { 6345 static final String STACKTRACE = "stackTrace"; 6346 static final String OP = "op"; 6347 static final String PACKAGENAME = "packageName"; 6348 static final String VERSION = "version"; 6349 6350 private final @NonNull String mStackTrace; 6351 private final int mOp; 6352 private final @Nullable String mPackageName; 6353 private final long mVersion; 6354 6355 /** 6356 * Initialize a NoteOp object using a JSON object containing the necessary fields 6357 * 6358 * @param jsonTrace JSON object represented as a string 6359 * 6360 * @return NoteOpTrace object initialized with JSON fields 6361 */ fromJson(String jsonTrace)6362 static NoteOpTrace fromJson(String jsonTrace) { 6363 try { 6364 // Re-add closing bracket which acted as a delimiter by the reader 6365 JSONObject obj = new JSONObject(jsonTrace.concat("}")); 6366 return new NoteOpTrace(obj.getString(STACKTRACE), obj.getInt(OP), 6367 obj.getString(PACKAGENAME), obj.getLong(VERSION)); 6368 } catch (JSONException e) { 6369 // Swallow error, only meant for logging ops, should not affect flow of the code 6370 Slog.e(TAG, "Error constructing NoteOpTrace object " 6371 + "JSON trace format incorrect", e); 6372 return null; 6373 } 6374 } 6375 NoteOpTrace(String stackTrace, int op, String packageName, long version)6376 NoteOpTrace(String stackTrace, int op, String packageName, long version) { 6377 mStackTrace = stackTrace; 6378 mOp = op; 6379 mPackageName = packageName; 6380 mVersion = version; 6381 } 6382 6383 @Override equals(Object o)6384 public boolean equals(Object o) { 6385 if (this == o) return true; 6386 if (o == null || getClass() != o.getClass()) return false; 6387 NoteOpTrace that = (NoteOpTrace) o; 6388 return mOp == that.mOp 6389 && mVersion == that.mVersion 6390 && mStackTrace.equals(that.mStackTrace) 6391 && Objects.equals(mPackageName, that.mPackageName); 6392 } 6393 6394 @Override hashCode()6395 public int hashCode() { 6396 return Objects.hash(mStackTrace, mOp, mPackageName, mVersion); 6397 } 6398 6399 /** 6400 * The object is formatted as a JSON object and returned as a String 6401 * 6402 * @return JSON formatted string 6403 */ asJson()6404 public String asJson() { 6405 return "{" 6406 + "\"" + STACKTRACE + "\":\"" + mStackTrace.replace("\n", "\\n") 6407 + '\"' + ",\"" + OP + "\":" + mOp 6408 + ",\"" + PACKAGENAME + "\":\"" + mPackageName + '\"' 6409 + ",\"" + VERSION + "\":" + mVersion 6410 + '}'; 6411 } 6412 } 6413 6414 /** 6415 * Collects noteOps, noteProxyOps and startOps from AppOpsManager and writes it into a file 6416 * which will be used for permissions data validation, the given parameters to this method 6417 * will be logged in json format 6418 * 6419 * @param stackTrace stacktrace from the most recent call in AppOpsManager 6420 * @param op op code 6421 * @param packageName package making call 6422 * @param version android version for this call 6423 */ 6424 @Override collectNoteOpCallsForValidation(String stackTrace, int op, String packageName, long version)6425 public void collectNoteOpCallsForValidation(String stackTrace, int op, String packageName, 6426 long version) { 6427 if (!AppOpsManager.NOTE_OP_COLLECTION_ENABLED) { 6428 return; 6429 } 6430 6431 Objects.requireNonNull(stackTrace); 6432 Preconditions.checkArgument(op >= 0); 6433 Preconditions.checkArgument(op < AppOpsManager._NUM_OP); 6434 Objects.requireNonNull(version); 6435 6436 NoteOpTrace noteOpTrace = new NoteOpTrace(stackTrace, op, packageName, version); 6437 6438 boolean noteOpSetWasChanged; 6439 synchronized (this) { 6440 noteOpSetWasChanged = mNoteOpCallerStacktraces.add(noteOpTrace); 6441 if (noteOpSetWasChanged && !mWriteNoteOpsScheduled) { 6442 mWriteNoteOpsScheduled = true; 6443 mHandler.postDelayed(PooledLambda.obtainRunnable((that) -> { 6444 AsyncTask.execute(() -> { 6445 that.writeNoteOps(); 6446 }); 6447 }, this), 2500); 6448 } 6449 } 6450 } 6451 } 6452