1 /* 2 * Copyright (C) 2010 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 package android.os; 17 18 import android.animation.ValueAnimator; 19 import android.annotation.IntDef; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.annotation.TestApi; 23 import android.app.ActivityManager; 24 import android.app.ActivityThread; 25 import android.app.IActivityManager; 26 import android.compat.annotation.UnsupportedAppUsage; 27 import android.content.BroadcastReceiver; 28 import android.content.Context; 29 import android.content.Intent; 30 import android.content.ServiceConnection; 31 import android.content.pm.ApplicationInfo; 32 import android.content.pm.PackageManager; 33 import android.content.res.Configuration; 34 import android.net.TrafficStats; 35 import android.net.Uri; 36 import android.os.storage.IStorageManager; 37 import android.os.strictmode.CleartextNetworkViolation; 38 import android.os.strictmode.ContentUriWithoutPermissionViolation; 39 import android.os.strictmode.CredentialProtectedWhileLockedViolation; 40 import android.os.strictmode.CustomViolation; 41 import android.os.strictmode.DiskReadViolation; 42 import android.os.strictmode.DiskWriteViolation; 43 import android.os.strictmode.ExplicitGcViolation; 44 import android.os.strictmode.FileUriExposedViolation; 45 import android.os.strictmode.ImplicitDirectBootViolation; 46 import android.os.strictmode.IncorrectContextUseViolation; 47 import android.os.strictmode.InstanceCountViolation; 48 import android.os.strictmode.IntentReceiverLeakedViolation; 49 import android.os.strictmode.LeakedClosableViolation; 50 import android.os.strictmode.NetworkViolation; 51 import android.os.strictmode.NonSdkApiUsedViolation; 52 import android.os.strictmode.ResourceMismatchViolation; 53 import android.os.strictmode.ServiceConnectionLeakedViolation; 54 import android.os.strictmode.SqliteObjectLeakedViolation; 55 import android.os.strictmode.UnbufferedIoViolation; 56 import android.os.strictmode.UnsafeIntentLaunchViolation; 57 import android.os.strictmode.UntaggedSocketViolation; 58 import android.os.strictmode.Violation; 59 import android.os.strictmode.WebViewMethodCalledOnWrongThreadViolation; 60 import android.util.ArrayMap; 61 import android.util.Log; 62 import android.util.Printer; 63 import android.util.Singleton; 64 import android.util.Slog; 65 import android.util.SparseLongArray; 66 import android.view.IWindowManager; 67 68 import com.android.internal.annotations.GuardedBy; 69 import com.android.internal.os.BackgroundThread; 70 import com.android.internal.os.RuntimeInit; 71 import com.android.internal.util.FastPrintWriter; 72 import com.android.internal.util.HexDump; 73 74 import dalvik.system.BlockGuard; 75 import dalvik.system.CloseGuard; 76 import dalvik.system.VMDebug; 77 import dalvik.system.VMRuntime; 78 79 import java.io.PrintWriter; 80 import java.io.StringWriter; 81 import java.lang.annotation.Retention; 82 import java.lang.annotation.RetentionPolicy; 83 import java.net.InetAddress; 84 import java.net.UnknownHostException; 85 import java.util.ArrayDeque; 86 import java.util.ArrayList; 87 import java.util.Arrays; 88 import java.util.Deque; 89 import java.util.HashMap; 90 import java.util.concurrent.Executor; 91 import java.util.concurrent.RejectedExecutionException; 92 import java.util.concurrent.atomic.AtomicInteger; 93 import java.util.function.Consumer; 94 95 /** 96 * StrictMode is a developer tool which detects things you might be doing by accident and brings 97 * them to your attention so you can fix them. 98 * 99 * <p>StrictMode is most commonly used to catch accidental disk or network access on the 100 * application's main thread, where UI operations are received and animations take place. Keeping 101 * disk and network operations off the main thread makes for much smoother, more responsive 102 * applications. By keeping your application's main thread responsive, you also prevent <a 103 * href="{@docRoot}guide/practices/design/responsiveness.html">ANR dialogs</a> from being shown to 104 * users. 105 * 106 * <p class="note">Note that even though an Android device's disk is often on flash memory, many 107 * devices run a filesystem on top of that memory with very limited concurrency. It's often the case 108 * that almost all disk accesses are fast, but may in individual cases be dramatically slower when 109 * certain I/O is happening in the background from other processes. If possible, it's best to assume 110 * that such things are not fast. 111 * 112 * <p>Example code to enable from early in your {@link android.app.Application}, {@link 113 * android.app.Activity}, or other application component's {@link android.app.Application#onCreate} 114 * method: 115 * 116 * <pre> 117 * public void onCreate() { 118 * if (DEVELOPER_MODE) { 119 * StrictMode.setThreadPolicy(new {@link ThreadPolicy.Builder StrictMode.ThreadPolicy.Builder}() 120 * .detectDiskReads() 121 * .detectDiskWrites() 122 * .detectNetwork() // or .detectAll() for all detectable problems 123 * .penaltyLog() 124 * .build()); 125 * StrictMode.setVmPolicy(new {@link VmPolicy.Builder StrictMode.VmPolicy.Builder}() 126 * .detectLeakedSqlLiteObjects() 127 * .detectLeakedClosableObjects() 128 * .penaltyLog() 129 * .penaltyDeath() 130 * .build()); 131 * } 132 * super.onCreate(); 133 * } 134 * </pre> 135 * 136 * <p>You can decide what should happen when a violation is detected. For example, using {@link 137 * ThreadPolicy.Builder#penaltyLog} you can watch the output of <code>adb logcat</code> while you 138 * use your application to see the violations as they happen. 139 * 140 * <p>If you find violations that you feel are problematic, there are a variety of tools to help 141 * solve them: threads, {@link android.os.Handler}, {@link android.os.AsyncTask}, {@link 142 * android.app.IntentService}, etc. But don't feel compelled to fix everything that StrictMode 143 * finds. In particular, many cases of disk access are often necessary during the normal activity 144 * lifecycle. Use StrictMode to find things you did by accident. Network requests on the UI thread 145 * are almost always a problem, though. 146 * 147 * <p class="note">StrictMode is not a security mechanism and is not guaranteed to find all disk or 148 * network accesses. While it does propagate its state across process boundaries when doing {@link 149 * android.os.Binder} calls, it's still ultimately a best effort mechanism. Notably, disk or network 150 * access from JNI calls won't necessarily trigger it. Future versions of Android may catch more (or 151 * fewer) operations, so you should never leave StrictMode enabled in applications distributed on 152 * Google Play. 153 */ 154 public final class StrictMode { 155 private static final String TAG = "StrictMode"; 156 private static final boolean LOG_V = Log.isLoggable(TAG, Log.VERBOSE); 157 158 /** 159 * Boolean system property to disable strict mode checks outright. Set this to 'true' to force 160 * disable; 'false' has no effect on other enable/disable policy. 161 * 162 * @hide 163 */ 164 public static final String DISABLE_PROPERTY = "persist.sys.strictmode.disable"; 165 166 /** 167 * The boolean system property to control screen flashes on violations. 168 * 169 * @hide 170 */ 171 public static final String VISUAL_PROPERTY = "persist.sys.strictmode.visual"; 172 173 /** 174 * Temporary property used to include {@link #DETECT_VM_CLEARTEXT_NETWORK} in {@link 175 * VmPolicy.Builder#detectAll()}. Apps can still always opt-into detection using {@link 176 * VmPolicy.Builder#detectCleartextNetwork()}. 177 */ 178 private static final String CLEARTEXT_PROPERTY = "persist.sys.strictmode.clear"; 179 180 /** 181 * Quick feature-flag that can be used to disable the defaults provided by {@link 182 * #initThreadDefaults(ApplicationInfo)} and {@link #initVmDefaults(ApplicationInfo)}. 183 */ 184 private static final boolean DISABLE = false; 185 186 // Only apply VM penalties for the same violation at this interval. 187 private static final long MIN_VM_INTERVAL_MS = 1000; 188 189 // Only log a duplicate stack trace to the logs every second. 190 private static final long MIN_LOG_INTERVAL_MS = 1000; 191 192 // Only show an annoying dialog at most every 30 seconds 193 private static final long MIN_DIALOG_INTERVAL_MS = 30000; 194 195 // Only log a dropbox entry at most every 30 seconds 196 private static final long MIN_DROPBOX_INTERVAL_MS = 3000; 197 198 // How many Span tags (e.g. animations) to report. 199 private static final int MAX_SPAN_TAGS = 20; 200 201 // How many offending stacks to keep track of (and time) per loop 202 // of the Looper. 203 private static final int MAX_OFFENSES_PER_LOOP = 10; 204 205 /** @hide */ 206 @IntDef(flag = true, prefix = { "DETECT_THREAD_", "PENALTY_" }, value = { 207 DETECT_THREAD_DISK_WRITE, 208 DETECT_THREAD_DISK_READ, 209 DETECT_THREAD_NETWORK, 210 DETECT_THREAD_CUSTOM, 211 DETECT_THREAD_RESOURCE_MISMATCH, 212 DETECT_THREAD_UNBUFFERED_IO, 213 DETECT_THREAD_EXPLICIT_GC, 214 PENALTY_GATHER, 215 PENALTY_LOG, 216 PENALTY_DIALOG, 217 PENALTY_DEATH, 218 PENALTY_FLASH, 219 PENALTY_DROPBOX, 220 PENALTY_DEATH_ON_NETWORK, 221 PENALTY_DEATH_ON_CLEARTEXT_NETWORK, 222 PENALTY_DEATH_ON_FILE_URI_EXPOSURE, 223 }) 224 @Retention(RetentionPolicy.SOURCE) 225 public @interface ThreadPolicyMask {} 226 227 // Thread policy: bits 0-15 228 229 /** @hide */ 230 private static final int DETECT_THREAD_DISK_WRITE = 1 << 0; 231 /** @hide */ 232 private static final int DETECT_THREAD_DISK_READ = 1 << 1; 233 /** @hide */ 234 private static final int DETECT_THREAD_NETWORK = 1 << 2; 235 /** @hide */ 236 private static final int DETECT_THREAD_CUSTOM = 1 << 3; 237 /** @hide */ 238 private static final int DETECT_THREAD_RESOURCE_MISMATCH = 1 << 4; 239 /** @hide */ 240 private static final int DETECT_THREAD_UNBUFFERED_IO = 1 << 5; 241 /** @hide */ 242 private static final int DETECT_THREAD_EXPLICIT_GC = 1 << 6; 243 244 /** @hide */ 245 private static final int DETECT_THREAD_ALL = 0x0000ffff; 246 247 /** @hide */ 248 @IntDef(flag = true, prefix = { "DETECT_THREAD_", "PENALTY_" }, value = { 249 DETECT_VM_CURSOR_LEAKS, 250 DETECT_VM_CLOSABLE_LEAKS, 251 DETECT_VM_ACTIVITY_LEAKS, 252 DETECT_VM_INSTANCE_LEAKS, 253 DETECT_VM_REGISTRATION_LEAKS, 254 DETECT_VM_FILE_URI_EXPOSURE, 255 DETECT_VM_CLEARTEXT_NETWORK, 256 DETECT_VM_CONTENT_URI_WITHOUT_PERMISSION, 257 DETECT_VM_UNTAGGED_SOCKET, 258 DETECT_VM_NON_SDK_API_USAGE, 259 DETECT_VM_IMPLICIT_DIRECT_BOOT, 260 DETECT_VM_INCORRECT_CONTEXT_USE, 261 DETECT_VM_UNSAFE_INTENT_LAUNCH, 262 PENALTY_GATHER, 263 PENALTY_LOG, 264 PENALTY_DIALOG, 265 PENALTY_DEATH, 266 PENALTY_FLASH, 267 PENALTY_DROPBOX, 268 PENALTY_DEATH_ON_NETWORK, 269 PENALTY_DEATH_ON_CLEARTEXT_NETWORK, 270 PENALTY_DEATH_ON_FILE_URI_EXPOSURE, 271 }) 272 @Retention(RetentionPolicy.SOURCE) 273 public @interface VmPolicyMask {} 274 275 // VM policy: bits 0-15 276 277 /** @hide */ 278 private static final int DETECT_VM_CURSOR_LEAKS = 1 << 0; 279 /** @hide */ 280 private static final int DETECT_VM_CLOSABLE_LEAKS = 1 << 1; 281 /** @hide */ 282 private static final int DETECT_VM_ACTIVITY_LEAKS = 1 << 2; 283 /** @hide */ 284 private static final int DETECT_VM_INSTANCE_LEAKS = 1 << 3; 285 /** @hide */ 286 private static final int DETECT_VM_REGISTRATION_LEAKS = 1 << 4; 287 /** @hide */ 288 private static final int DETECT_VM_FILE_URI_EXPOSURE = 1 << 5; 289 /** @hide */ 290 private static final int DETECT_VM_CLEARTEXT_NETWORK = 1 << 6; 291 /** @hide */ 292 private static final int DETECT_VM_CONTENT_URI_WITHOUT_PERMISSION = 1 << 7; 293 /** @hide */ 294 private static final int DETECT_VM_UNTAGGED_SOCKET = 1 << 8; 295 /** @hide */ 296 private static final int DETECT_VM_NON_SDK_API_USAGE = 1 << 9; 297 /** @hide */ 298 private static final int DETECT_VM_IMPLICIT_DIRECT_BOOT = 1 << 10; 299 /** @hide */ 300 private static final int DETECT_VM_CREDENTIAL_PROTECTED_WHILE_LOCKED = 1 << 11; 301 /** @hide */ 302 private static final int DETECT_VM_INCORRECT_CONTEXT_USE = 1 << 12; 303 /** @hide */ 304 private static final int DETECT_VM_UNSAFE_INTENT_LAUNCH = 1 << 13; 305 306 /** @hide */ 307 private static final int DETECT_VM_ALL = 0x0000ffff; 308 309 // Penalty policy: bits 16-31 310 311 /** 312 * Non-public penalty mode which overrides all the other penalty bits and signals that we're in 313 * a Binder call and we should ignore the other penalty bits and instead serialize back all our 314 * offending stack traces to the caller to ultimately handle in the originating process. 315 * 316 * <p>This must be kept in sync with the constant in libs/binder/Parcel.cpp 317 * 318 * @hide 319 */ 320 public static final int PENALTY_GATHER = 1 << 31; 321 322 /** {@hide} */ 323 public static final int PENALTY_LOG = 1 << 30; 324 /** {@hide} */ 325 public static final int PENALTY_DIALOG = 1 << 29; 326 /** {@hide} */ 327 public static final int PENALTY_DEATH = 1 << 28; 328 /** {@hide} */ 329 public static final int PENALTY_FLASH = 1 << 27; 330 /** {@hide} */ 331 public static final int PENALTY_DROPBOX = 1 << 26; 332 /** {@hide} */ 333 public static final int PENALTY_DEATH_ON_NETWORK = 1 << 25; 334 /** {@hide} */ 335 public static final int PENALTY_DEATH_ON_CLEARTEXT_NETWORK = 1 << 24; 336 /** {@hide} */ 337 public static final int PENALTY_DEATH_ON_FILE_URI_EXPOSURE = 1 << 23; 338 339 /** @hide */ 340 public static final int PENALTY_ALL = 0xffff0000; 341 342 /** {@hide} */ 343 public static final int NETWORK_POLICY_ACCEPT = 0; 344 /** {@hide} */ 345 public static final int NETWORK_POLICY_LOG = 1; 346 /** {@hide} */ 347 public static final int NETWORK_POLICY_REJECT = 2; 348 349 // TODO: wrap in some ImmutableHashMap thing. 350 // Note: must be before static initialization of sVmPolicy. 351 private static final HashMap<Class, Integer> EMPTY_CLASS_LIMIT_MAP = 352 new HashMap<Class, Integer>(); 353 354 /** The current VmPolicy in effect. */ 355 private static volatile VmPolicy sVmPolicy = VmPolicy.LAX; 356 357 /** {@hide} */ 358 @TestApi 359 public interface ViolationLogger { 360 361 /** Called when penaltyLog is enabled and a violation needs logging. */ log(ViolationInfo info)362 void log(ViolationInfo info); 363 } 364 365 private static final ViolationLogger LOGCAT_LOGGER = 366 info -> { 367 String msg; 368 if (info.durationMillis != -1) { 369 msg = "StrictMode policy violation; ~duration=" + info.durationMillis + " ms:"; 370 } else { 371 msg = "StrictMode policy violation:"; 372 } 373 Log.d(TAG, msg + " " + info.getStackTrace()); 374 }; 375 376 private static volatile ViolationLogger sLogger = LOGCAT_LOGGER; 377 378 private static final ThreadLocal<OnThreadViolationListener> sThreadViolationListener = 379 new ThreadLocal<>(); 380 private static final ThreadLocal<Executor> sThreadViolationExecutor = new ThreadLocal<>(); 381 382 /** 383 * When #{@link ThreadPolicy.Builder#penaltyListener} is enabled, the listener is called on the 384 * provided executor when a Thread violation occurs. 385 */ 386 public interface OnThreadViolationListener { 387 /** Called on a thread policy violation. */ onThreadViolation(Violation v)388 void onThreadViolation(Violation v); 389 } 390 391 /** 392 * When #{@link VmPolicy.Builder#penaltyListener} is enabled, the listener is called on the 393 * provided executor when a VM violation occurs. 394 */ 395 public interface OnVmViolationListener { 396 /** Called on a VM policy violation. */ onVmViolation(Violation v)397 void onVmViolation(Violation v); 398 } 399 400 /** {@hide} */ 401 @TestApi setViolationLogger(ViolationLogger listener)402 public static void setViolationLogger(ViolationLogger listener) { 403 if (listener == null) { 404 listener = LOGCAT_LOGGER; 405 } 406 sLogger = listener; 407 } 408 409 /** 410 * The number of threads trying to do an async dropbox write. Just to limit ourselves out of 411 * paranoia. 412 */ 413 private static final AtomicInteger sDropboxCallsInFlight = new AtomicInteger(0); 414 415 /** 416 * Callback supplied to dalvik / libcore to get informed of usages of java API that are not 417 * a part of the public SDK. 418 */ 419 private static final Consumer<String> sNonSdkApiUsageConsumer = 420 message -> onVmPolicyViolation(new NonSdkApiUsedViolation(message)); 421 StrictMode()422 private StrictMode() {} 423 424 /** 425 * {@link StrictMode} policy applied to a certain thread. 426 * 427 * <p>The policy is enabled by {@link #setThreadPolicy}. The current policy can be retrieved 428 * with {@link #getThreadPolicy}. 429 * 430 * <p>Note that multiple penalties may be provided and they're run in order from least to most 431 * severe (logging before process death, for example). There's currently no mechanism to choose 432 * different penalties for different detected actions. 433 */ 434 public static final class ThreadPolicy { 435 /** The default, lax policy which doesn't catch anything. */ 436 public static final ThreadPolicy LAX = new ThreadPolicy(0, null, null); 437 438 @UnsupportedAppUsage 439 final @ThreadPolicyMask int mask; 440 final OnThreadViolationListener mListener; 441 final Executor mCallbackExecutor; 442 ThreadPolicy(@hreadPolicyMask int mask, OnThreadViolationListener listener, Executor executor)443 private ThreadPolicy(@ThreadPolicyMask int mask, OnThreadViolationListener listener, 444 Executor executor) { 445 this.mask = mask; 446 mListener = listener; 447 mCallbackExecutor = executor; 448 } 449 450 @Override toString()451 public String toString() { 452 return "[StrictMode.ThreadPolicy; mask=" + mask + "]"; 453 } 454 455 /** 456 * Creates {@link ThreadPolicy} instances. Methods whose names start with {@code detect} 457 * specify what problems we should look for. Methods whose names start with {@code penalty} 458 * specify what we should do when we detect a problem. 459 * 460 * <p>You can call as many {@code detect} and {@code penalty} methods as you like. Currently 461 * order is insignificant: all penalties apply to all detected problems. 462 * 463 * <p>For example, detect everything and log anything that's found: 464 * 465 * <pre> 466 * StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder() 467 * .detectAll() 468 * .penaltyLog() 469 * .build(); 470 * StrictMode.setThreadPolicy(policy); 471 * </pre> 472 */ 473 public static final class Builder { 474 private @ThreadPolicyMask int mMask = 0; 475 private OnThreadViolationListener mListener; 476 private Executor mExecutor; 477 478 /** 479 * Create a Builder that detects nothing and has no violations. (but note that {@link 480 * #build} will default to enabling {@link #penaltyLog} if no other penalties are 481 * specified) 482 */ Builder()483 public Builder() { 484 mMask = 0; 485 } 486 487 /** Initialize a Builder from an existing ThreadPolicy. */ Builder(ThreadPolicy policy)488 public Builder(ThreadPolicy policy) { 489 mMask = policy.mask; 490 mListener = policy.mListener; 491 mExecutor = policy.mCallbackExecutor; 492 } 493 494 /** 495 * Detect everything that's potentially suspect. 496 * 497 * <p>As of the Gingerbread release this includes network and disk operations but will 498 * likely expand in future releases. 499 */ detectAll()500 public @NonNull Builder detectAll() { 501 detectDiskReads(); 502 detectDiskWrites(); 503 detectNetwork(); 504 505 final int targetSdk = VMRuntime.getRuntime().getTargetSdkVersion(); 506 if (targetSdk >= Build.VERSION_CODES.HONEYCOMB) { 507 detectCustomSlowCalls(); 508 } 509 if (targetSdk >= Build.VERSION_CODES.M) { 510 detectResourceMismatches(); 511 } 512 if (targetSdk >= Build.VERSION_CODES.O) { 513 detectUnbufferedIo(); 514 } 515 return this; 516 } 517 518 /** Disable the detection of everything. */ permitAll()519 public @NonNull Builder permitAll() { 520 return disable(DETECT_THREAD_ALL); 521 } 522 523 /** Enable detection of network operations. */ detectNetwork()524 public @NonNull Builder detectNetwork() { 525 return enable(DETECT_THREAD_NETWORK); 526 } 527 528 /** Disable detection of network operations. */ permitNetwork()529 public @NonNull Builder permitNetwork() { 530 return disable(DETECT_THREAD_NETWORK); 531 } 532 533 /** Enable detection of disk reads. */ detectDiskReads()534 public @NonNull Builder detectDiskReads() { 535 return enable(DETECT_THREAD_DISK_READ); 536 } 537 538 /** Disable detection of disk reads. */ permitDiskReads()539 public @NonNull Builder permitDiskReads() { 540 return disable(DETECT_THREAD_DISK_READ); 541 } 542 543 /** Enable detection of slow calls. */ detectCustomSlowCalls()544 public @NonNull Builder detectCustomSlowCalls() { 545 return enable(DETECT_THREAD_CUSTOM); 546 } 547 548 /** Disable detection of slow calls. */ permitCustomSlowCalls()549 public @NonNull Builder permitCustomSlowCalls() { 550 return disable(DETECT_THREAD_CUSTOM); 551 } 552 553 /** Disable detection of mismatches between defined resource types and getter calls. */ permitResourceMismatches()554 public @NonNull Builder permitResourceMismatches() { 555 return disable(DETECT_THREAD_RESOURCE_MISMATCH); 556 } 557 558 /** Detect unbuffered input/output operations. */ detectUnbufferedIo()559 public @NonNull Builder detectUnbufferedIo() { 560 return enable(DETECT_THREAD_UNBUFFERED_IO); 561 } 562 563 /** Disable detection of unbuffered input/output operations. */ permitUnbufferedIo()564 public @NonNull Builder permitUnbufferedIo() { 565 return disable(DETECT_THREAD_UNBUFFERED_IO); 566 } 567 568 /** 569 * Enables detection of mismatches between defined resource types and getter calls. 570 * 571 * <p>This helps detect accidental type mismatches and potentially expensive type 572 * conversions when obtaining typed resources. 573 * 574 * <p>For example, a strict mode violation would be thrown when calling {@link 575 * android.content.res.TypedArray#getInt(int, int)} on an index that contains a 576 * String-type resource. If the string value can be parsed as an integer, this method 577 * call will return a value without crashing; however, the developer should format the 578 * resource as an integer to avoid unnecessary type conversion. 579 */ detectResourceMismatches()580 public @NonNull Builder detectResourceMismatches() { 581 return enable(DETECT_THREAD_RESOURCE_MISMATCH); 582 } 583 584 /** Enable detection of disk writes. */ detectDiskWrites()585 public @NonNull Builder detectDiskWrites() { 586 return enable(DETECT_THREAD_DISK_WRITE); 587 } 588 589 /** Disable detection of disk writes. */ permitDiskWrites()590 public @NonNull Builder permitDiskWrites() { 591 return disable(DETECT_THREAD_DISK_WRITE); 592 } 593 594 /** 595 * Detect explicit GC requests, i.e. calls to Runtime.gc(). 596 * 597 * @hide 598 */ 599 @TestApi detectExplicitGc()600 public @NonNull Builder detectExplicitGc() { 601 // TODO(b/3400644): Un-hide this for next API update 602 // TODO(b/3400644): Un-hide ExplicitGcViolation for next API update 603 // TODO(b/3400644): Make DETECT_EXPLICIT_GC a @TestApi for next API update 604 // TODO(b/3400644): Call this from detectAll in next API update 605 return enable(DETECT_THREAD_EXPLICIT_GC); 606 } 607 608 /** 609 * Disable detection of explicit GC requests, i.e. calls to Runtime.gc(). 610 * 611 * @hide 612 */ permitExplicitGc()613 public @NonNull Builder permitExplicitGc() { 614 // TODO(b/3400644): Un-hide this for next API update 615 return disable(DETECT_THREAD_EXPLICIT_GC); 616 } 617 618 /** 619 * Show an annoying dialog to the developer on detected violations, rate-limited to be 620 * only a little annoying. 621 */ penaltyDialog()622 public @NonNull Builder penaltyDialog() { 623 return enable(PENALTY_DIALOG); 624 } 625 626 /** 627 * Crash the whole process on violation. This penalty runs at the end of all enabled 628 * penalties so you'll still get see logging or other violations before the process 629 * dies. 630 * 631 * <p>Unlike {@link #penaltyDeathOnNetwork}, this applies to disk reads, disk writes, 632 * and network usage if their corresponding detect flags are set. 633 */ penaltyDeath()634 public @NonNull Builder penaltyDeath() { 635 return enable(PENALTY_DEATH); 636 } 637 638 /** 639 * Crash the whole process on any network usage. Unlike {@link #penaltyDeath}, this 640 * penalty runs <em>before</em> anything else. You must still have called {@link 641 * #detectNetwork} to enable this. 642 * 643 * <p>In the Honeycomb or later SDKs, this is on by default. 644 */ penaltyDeathOnNetwork()645 public @NonNull Builder penaltyDeathOnNetwork() { 646 return enable(PENALTY_DEATH_ON_NETWORK); 647 } 648 649 /** Flash the screen during a violation. */ penaltyFlashScreen()650 public @NonNull Builder penaltyFlashScreen() { 651 return enable(PENALTY_FLASH); 652 } 653 654 /** Log detected violations to the system log. */ penaltyLog()655 public @NonNull Builder penaltyLog() { 656 return enable(PENALTY_LOG); 657 } 658 659 /** 660 * Enable detected violations log a stacktrace and timing data to the {@link 661 * android.os.DropBoxManager DropBox} on policy violation. Intended mostly for platform 662 * integrators doing beta user field data collection. 663 */ penaltyDropBox()664 public @NonNull Builder penaltyDropBox() { 665 return enable(PENALTY_DROPBOX); 666 } 667 668 /** 669 * Call #{@link OnThreadViolationListener#onThreadViolation(Violation)} on specified 670 * executor every violation. 671 */ penaltyListener( @onNull Executor executor, @NonNull OnThreadViolationListener listener)672 public @NonNull Builder penaltyListener( 673 @NonNull Executor executor, @NonNull OnThreadViolationListener listener) { 674 if (executor == null) { 675 throw new NullPointerException("executor must not be null"); 676 } 677 mListener = listener; 678 mExecutor = executor; 679 return this; 680 } 681 682 /** @removed */ penaltyListener( @onNull OnThreadViolationListener listener, @NonNull Executor executor)683 public @NonNull Builder penaltyListener( 684 @NonNull OnThreadViolationListener listener, @NonNull Executor executor) { 685 return penaltyListener(executor, listener); 686 } 687 enable(@hreadPolicyMask int mask)688 private Builder enable(@ThreadPolicyMask int mask) { 689 mMask |= mask; 690 return this; 691 } 692 disable(@hreadPolicyMask int mask)693 private Builder disable(@ThreadPolicyMask int mask) { 694 mMask &= ~mask; 695 return this; 696 } 697 698 /** 699 * Construct the ThreadPolicy instance. 700 * 701 * <p>Note: if no penalties are enabled before calling <code>build</code>, {@link 702 * #penaltyLog} is implicitly set. 703 */ build()704 public ThreadPolicy build() { 705 // If there are detection bits set but no violation bits 706 // set, enable simple logging. 707 if (mListener == null 708 && mMask != 0 709 && (mMask 710 & (PENALTY_DEATH 711 | PENALTY_LOG 712 | PENALTY_DROPBOX 713 | PENALTY_DIALOG)) 714 == 0) { 715 penaltyLog(); 716 } 717 return new ThreadPolicy(mMask, mListener, mExecutor); 718 } 719 } 720 } 721 722 /** 723 * {@link StrictMode} policy applied to all threads in the virtual machine's process. 724 * 725 * <p>The policy is enabled by {@link #setVmPolicy}. 726 */ 727 public static final class VmPolicy { 728 /** The default, lax policy which doesn't catch anything. */ 729 public static final VmPolicy LAX = new VmPolicy(0, EMPTY_CLASS_LIMIT_MAP, null, null); 730 731 @UnsupportedAppUsage 732 final @VmPolicyMask int mask; 733 final OnVmViolationListener mListener; 734 final Executor mCallbackExecutor; 735 736 // Map from class to max number of allowed instances in memory. 737 final HashMap<Class, Integer> classInstanceLimit; 738 VmPolicy( @mPolicyMask int mask, HashMap<Class, Integer> classInstanceLimit, OnVmViolationListener listener, Executor executor)739 private VmPolicy( 740 @VmPolicyMask int mask, 741 HashMap<Class, Integer> classInstanceLimit, 742 OnVmViolationListener listener, 743 Executor executor) { 744 if (classInstanceLimit == null) { 745 throw new NullPointerException("classInstanceLimit == null"); 746 } 747 this.mask = mask; 748 this.classInstanceLimit = classInstanceLimit; 749 mListener = listener; 750 mCallbackExecutor = executor; 751 } 752 753 @Override toString()754 public String toString() { 755 return "[StrictMode.VmPolicy; mask=" + mask + "]"; 756 } 757 758 /** 759 * Creates {@link VmPolicy} instances. Methods whose names start with {@code detect} specify 760 * what problems we should look for. Methods whose names start with {@code penalty} specify 761 * what we should do when we detect a problem. 762 * 763 * <p>You can call as many {@code detect} and {@code penalty} methods as you like. Currently 764 * order is insignificant: all penalties apply to all detected problems. 765 * 766 * <p>For example, detect everything and log anything that's found: 767 * 768 * <pre> 769 * StrictMode.VmPolicy policy = new StrictMode.VmPolicy.Builder() 770 * .detectAll() 771 * .penaltyLog() 772 * .build(); 773 * StrictMode.setVmPolicy(policy); 774 * </pre> 775 */ 776 public static final class Builder { 777 @UnsupportedAppUsage 778 private @VmPolicyMask int mMask; 779 private OnVmViolationListener mListener; 780 private Executor mExecutor; 781 782 private HashMap<Class, Integer> mClassInstanceLimit; // null until needed 783 private boolean mClassInstanceLimitNeedCow = false; // need copy-on-write 784 Builder()785 public Builder() { 786 mMask = 0; 787 } 788 789 /** Build upon an existing VmPolicy. */ Builder(VmPolicy base)790 public Builder(VmPolicy base) { 791 mMask = base.mask; 792 mClassInstanceLimitNeedCow = true; 793 mClassInstanceLimit = base.classInstanceLimit; 794 mListener = base.mListener; 795 mExecutor = base.mCallbackExecutor; 796 } 797 798 /** 799 * Set an upper bound on how many instances of a class can be in memory at once. Helps 800 * to prevent object leaks. 801 */ setClassInstanceLimit(Class klass, int instanceLimit)802 public @NonNull Builder setClassInstanceLimit(Class klass, int instanceLimit) { 803 if (klass == null) { 804 throw new NullPointerException("klass == null"); 805 } 806 if (mClassInstanceLimitNeedCow) { 807 if (mClassInstanceLimit.containsKey(klass) 808 && mClassInstanceLimit.get(klass) == instanceLimit) { 809 // no-op; don't break COW 810 return this; 811 } 812 mClassInstanceLimitNeedCow = false; 813 mClassInstanceLimit = (HashMap<Class, Integer>) mClassInstanceLimit.clone(); 814 } else if (mClassInstanceLimit == null) { 815 mClassInstanceLimit = new HashMap<Class, Integer>(); 816 } 817 mMask |= DETECT_VM_INSTANCE_LEAKS; 818 mClassInstanceLimit.put(klass, instanceLimit); 819 return this; 820 } 821 822 /** Detect leaks of {@link android.app.Activity} subclasses. */ detectActivityLeaks()823 public @NonNull Builder detectActivityLeaks() { 824 return enable(DETECT_VM_ACTIVITY_LEAKS); 825 } 826 827 /** @hide */ permitActivityLeaks()828 public @NonNull Builder permitActivityLeaks() { 829 synchronized (StrictMode.class) { 830 sExpectedActivityInstanceCount.clear(); 831 } 832 return disable(DETECT_VM_ACTIVITY_LEAKS); 833 } 834 835 /** 836 * Detect reflective usage of APIs that are not part of the public Android SDK. 837 * 838 * <p>Note that any non-SDK APIs that this processes accesses before this detection is 839 * enabled may not be detected. To ensure that all such API accesses are detected, 840 * you should apply this policy as early as possible after process creation. 841 */ detectNonSdkApiUsage()842 public @NonNull Builder detectNonSdkApiUsage() { 843 return enable(DETECT_VM_NON_SDK_API_USAGE); 844 } 845 846 /** 847 * Permit reflective usage of APIs that are not part of the public Android SDK. Note 848 * that this <b>only</b> affects {@code StrictMode}, the underlying runtime may 849 * continue to restrict or warn on access to methods that are not part of the 850 * public SDK. 851 */ permitNonSdkApiUsage()852 public @NonNull Builder permitNonSdkApiUsage() { 853 return disable(DETECT_VM_NON_SDK_API_USAGE); 854 } 855 856 /** 857 * Detect everything that's potentially suspect. 858 * 859 * <p>In the Honeycomb release this includes leaks of SQLite cursors, Activities, and 860 * other closable objects but will likely expand in future releases. 861 */ 862 @SuppressWarnings("AndroidFrameworkCompatChange") detectAll()863 public @NonNull Builder detectAll() { 864 detectLeakedSqlLiteObjects(); 865 866 final int targetSdk = VMRuntime.getRuntime().getTargetSdkVersion(); 867 if (targetSdk >= Build.VERSION_CODES.HONEYCOMB) { 868 detectActivityLeaks(); 869 detectLeakedClosableObjects(); 870 } 871 if (targetSdk >= Build.VERSION_CODES.JELLY_BEAN) { 872 detectLeakedRegistrationObjects(); 873 } 874 if (targetSdk >= Build.VERSION_CODES.JELLY_BEAN_MR2) { 875 detectFileUriExposure(); 876 } 877 if (targetSdk >= Build.VERSION_CODES.M) { 878 // TODO: always add DETECT_VM_CLEARTEXT_NETWORK once we have 879 // facility for apps to mark sockets that should be ignored 880 if (SystemProperties.getBoolean(CLEARTEXT_PROPERTY, false)) { 881 detectCleartextNetwork(); 882 } 883 } 884 if (targetSdk >= Build.VERSION_CODES.O) { 885 detectContentUriWithoutPermission(); 886 detectUntaggedSockets(); 887 } 888 if (targetSdk >= Build.VERSION_CODES.Q) { 889 detectCredentialProtectedWhileLocked(); 890 } 891 if (targetSdk >= Build.VERSION_CODES.R) { 892 detectIncorrectContextUse(); 893 } 894 if (targetSdk >= Build.VERSION_CODES.S) { 895 detectUnsafeIntentLaunch(); 896 } 897 898 // TODO: Decide whether to detect non SDK API usage beyond a certain API level. 899 // TODO: enable detectImplicitDirectBoot() once system is less noisy 900 901 return this; 902 } 903 904 /** 905 * Detect when an {@link android.database.sqlite.SQLiteCursor} or other SQLite object is 906 * finalized without having been closed. 907 * 908 * <p>You always want to explicitly close your SQLite cursors to avoid unnecessary 909 * database contention and temporary memory leaks. 910 */ detectLeakedSqlLiteObjects()911 public @NonNull Builder detectLeakedSqlLiteObjects() { 912 return enable(DETECT_VM_CURSOR_LEAKS); 913 } 914 915 /** 916 * Detect when an {@link java.io.Closeable} or other object with an explicit termination 917 * method is finalized without having been closed. 918 * 919 * <p>You always want to explicitly close such objects to avoid unnecessary resources 920 * leaks. 921 */ detectLeakedClosableObjects()922 public @NonNull Builder detectLeakedClosableObjects() { 923 return enable(DETECT_VM_CLOSABLE_LEAKS); 924 } 925 926 /** 927 * Detect when a {@link BroadcastReceiver} or {@link ServiceConnection} is leaked during 928 * {@link Context} teardown. 929 */ detectLeakedRegistrationObjects()930 public @NonNull Builder detectLeakedRegistrationObjects() { 931 return enable(DETECT_VM_REGISTRATION_LEAKS); 932 } 933 934 /** 935 * Detect when the calling application exposes a {@code file://} {@link android.net.Uri} 936 * to another app. 937 * 938 * <p>This exposure is discouraged since the receiving app may not have access to the 939 * shared path. For example, the receiving app may not have requested the {@link 940 * android.Manifest.permission#READ_EXTERNAL_STORAGE} runtime permission, or the 941 * platform may be sharing the {@link android.net.Uri} across user profile boundaries. 942 * 943 * <p>Instead, apps should use {@code content://} Uris so the platform can extend 944 * temporary permission for the receiving app to access the resource. 945 * 946 * @see android.support.v4.content.FileProvider 947 * @see Intent#FLAG_GRANT_READ_URI_PERMISSION 948 */ detectFileUriExposure()949 public @NonNull Builder detectFileUriExposure() { 950 return enable(DETECT_VM_FILE_URI_EXPOSURE); 951 } 952 953 /** 954 * Detect any network traffic from the calling app which is not wrapped in SSL/TLS. This 955 * can help you detect places that your app is inadvertently sending cleartext data 956 * across the network. 957 * 958 * <p>Using {@link #penaltyDeath()} or {@link #penaltyDeathOnCleartextNetwork()} will 959 * block further traffic on that socket to prevent accidental data leakage, in addition 960 * to crashing your process. 961 * 962 * <p>Using {@link #penaltyDropBox()} will log the raw contents of the packet that 963 * triggered the violation. 964 * 965 * <p>This inspects both IPv4/IPv6 and TCP/UDP network traffic, but it may be subject to 966 * false positives, such as when STARTTLS protocols or HTTP proxies are used. 967 */ detectCleartextNetwork()968 public @NonNull Builder detectCleartextNetwork() { 969 return enable(DETECT_VM_CLEARTEXT_NETWORK); 970 } 971 972 /** 973 * Detect when the calling application sends a {@code content://} {@link 974 * android.net.Uri} to another app without setting {@link 975 * Intent#FLAG_GRANT_READ_URI_PERMISSION} or {@link 976 * Intent#FLAG_GRANT_WRITE_URI_PERMISSION}. 977 * 978 * <p>Forgetting to include one or more of these flags when sending an intent is 979 * typically an app bug. 980 * 981 * @see Intent#FLAG_GRANT_READ_URI_PERMISSION 982 * @see Intent#FLAG_GRANT_WRITE_URI_PERMISSION 983 */ detectContentUriWithoutPermission()984 public @NonNull Builder detectContentUriWithoutPermission() { 985 return enable(DETECT_VM_CONTENT_URI_WITHOUT_PERMISSION); 986 } 987 988 /** 989 * Detect any sockets in the calling app which have not been tagged using {@link 990 * TrafficStats}. Tagging sockets can help you investigate network usage inside your 991 * app, such as a narrowing down heavy usage to a specific library or component. 992 * 993 * <p>This currently does not detect sockets created in native code. 994 * 995 * @see TrafficStats#setThreadStatsTag(int) 996 * @see TrafficStats#tagSocket(java.net.Socket) 997 * @see TrafficStats#tagDatagramSocket(java.net.DatagramSocket) 998 */ detectUntaggedSockets()999 public @NonNull Builder detectUntaggedSockets() { 1000 return enable(DETECT_VM_UNTAGGED_SOCKET); 1001 } 1002 1003 /** @hide */ permitUntaggedSockets()1004 public @NonNull Builder permitUntaggedSockets() { 1005 return disable(DETECT_VM_UNTAGGED_SOCKET); 1006 } 1007 1008 /** 1009 * Detect any implicit reliance on Direct Boot automatic filtering 1010 * of {@link PackageManager} values. Violations are only triggered 1011 * when implicit calls are made while the user is locked. 1012 * <p> 1013 * Apps becoming Direct Boot aware need to carefully inspect each 1014 * query site and explicitly decide which combination of flags they 1015 * want to use: 1016 * <ul> 1017 * <li>{@link PackageManager#MATCH_DIRECT_BOOT_AWARE} 1018 * <li>{@link PackageManager#MATCH_DIRECT_BOOT_UNAWARE} 1019 * <li>{@link PackageManager#MATCH_DIRECT_BOOT_AUTO} 1020 * </ul> 1021 */ detectImplicitDirectBoot()1022 public @NonNull Builder detectImplicitDirectBoot() { 1023 return enable(DETECT_VM_IMPLICIT_DIRECT_BOOT); 1024 } 1025 1026 /** @hide */ permitImplicitDirectBoot()1027 public @NonNull Builder permitImplicitDirectBoot() { 1028 return disable(DETECT_VM_IMPLICIT_DIRECT_BOOT); 1029 } 1030 1031 /** 1032 * Detect access to filesystem paths stored in credential protected 1033 * storage areas while the user is locked. 1034 * <p> 1035 * When a user is locked, credential protected storage is 1036 * unavailable, and files stored in these locations appear to not 1037 * exist, which can result in subtle app bugs if they assume default 1038 * behaviors or empty states. Instead, apps should store data needed 1039 * while a user is locked under device protected storage areas. 1040 * 1041 * @see Context#createDeviceProtectedStorageContext() 1042 */ detectCredentialProtectedWhileLocked()1043 public @NonNull Builder detectCredentialProtectedWhileLocked() { 1044 return enable(DETECT_VM_CREDENTIAL_PROTECTED_WHILE_LOCKED); 1045 } 1046 1047 /** @hide */ permitCredentialProtectedWhileLocked()1048 public @NonNull Builder permitCredentialProtectedWhileLocked() { 1049 return disable(DETECT_VM_CREDENTIAL_PROTECTED_WHILE_LOCKED); 1050 } 1051 1052 /** 1053 * Detect attempts to invoke a method on a {@link Context} that is not suited for such 1054 * operation. 1055 * <p>An example of this is trying to obtain an instance of UI service (e.g. 1056 * {@link android.view.WindowManager}) from a non-visual {@link Context}. This is not 1057 * allowed, since a non-visual {@link Context} is not adjusted to any visual area, and 1058 * therefore can report incorrect metrics or resources. 1059 * @see Context#getDisplay() 1060 * @see Context#getSystemService(String) 1061 */ detectIncorrectContextUse()1062 public @NonNull Builder detectIncorrectContextUse() { 1063 return enable(DETECT_VM_INCORRECT_CONTEXT_USE); 1064 } 1065 1066 /** 1067 * Disable detection of incorrect context use. 1068 * 1069 * @see #detectIncorrectContextUse() 1070 * 1071 * @hide 1072 */ 1073 @TestApi permitIncorrectContextUse()1074 public @NonNull Builder permitIncorrectContextUse() { 1075 return disable(DETECT_VM_INCORRECT_CONTEXT_USE); 1076 } 1077 1078 /** 1079 * Detect when your app launches an {@link Intent} which originated 1080 * from outside your app. 1081 * <p> 1082 * Violations may indicate security vulnerabilities in the design of 1083 * your app, where a malicious app could trick you into granting 1084 * {@link Uri} permissions or launching unexported components. Here 1085 * are some typical design patterns that can be used to safely 1086 * resolve these violations: 1087 * <ul> 1088 * <li>The ideal approach is to migrate to using a 1089 * {@link android.app.PendingIntent}, which ensures that your launch is 1090 * performed using the identity of the original creator, completely 1091 * avoiding the security issues described above. 1092 * <li>If using a {@link android.app.PendingIntent} isn't feasible, an 1093 * alternative approach is to create a brand new {@link Intent} and 1094 * carefully copy only specific values from the original 1095 * {@link Intent} after careful validation. 1096 * </ul> 1097 * <p> 1098 * Note that this <em>may</em> detect false-positives if your app 1099 * sends itself an {@link Intent} which is first routed through the 1100 * OS, such as using {@link Intent#createChooser}. In these cases, 1101 * careful inspection is required to determine if the return point 1102 * into your app is appropriately protected with a signature 1103 * permission or marked as unexported. If the return point is not 1104 * protected, your app is likely vulnerable to malicious apps. 1105 * 1106 * @see Context#startActivity(Intent) 1107 * @see Context#startService(Intent) 1108 * @see Context#bindService(Intent, ServiceConnection, int) 1109 * @see Context#sendBroadcast(Intent) 1110 * @see android.app.Activity#setResult(int, Intent) 1111 */ detectUnsafeIntentLaunch()1112 public @NonNull Builder detectUnsafeIntentLaunch() { 1113 return enable(DETECT_VM_UNSAFE_INTENT_LAUNCH); 1114 } 1115 1116 /** 1117 * Permit your app to launch any {@link Intent} which originated 1118 * from outside your app. 1119 * <p> 1120 * Disabling this check is <em>strongly discouraged</em>, as 1121 * violations may indicate security vulnerabilities in the design of 1122 * your app, where a malicious app could trick you into granting 1123 * {@link Uri} permissions or launching unexported components. 1124 * 1125 * @see #detectUnsafeIntentLaunch() 1126 */ permitUnsafeIntentLaunch()1127 public @NonNull Builder permitUnsafeIntentLaunch() { 1128 return disable(DETECT_VM_UNSAFE_INTENT_LAUNCH); 1129 } 1130 1131 /** 1132 * Crashes the whole process on violation. This penalty runs at the end of all enabled 1133 * penalties so you'll still get your logging or other violations before the process 1134 * dies. 1135 */ penaltyDeath()1136 public @NonNull Builder penaltyDeath() { 1137 return enable(PENALTY_DEATH); 1138 } 1139 1140 /** 1141 * Crashes the whole process when cleartext network traffic is detected. 1142 * 1143 * @see #detectCleartextNetwork() 1144 */ penaltyDeathOnCleartextNetwork()1145 public @NonNull Builder penaltyDeathOnCleartextNetwork() { 1146 return enable(PENALTY_DEATH_ON_CLEARTEXT_NETWORK); 1147 } 1148 1149 /** 1150 * Crashes the whole process when a {@code file://} {@link android.net.Uri} is exposed 1151 * beyond this app. 1152 * 1153 * @see #detectFileUriExposure() 1154 */ penaltyDeathOnFileUriExposure()1155 public @NonNull Builder penaltyDeathOnFileUriExposure() { 1156 return enable(PENALTY_DEATH_ON_FILE_URI_EXPOSURE); 1157 } 1158 1159 /** Log detected violations to the system log. */ penaltyLog()1160 public @NonNull Builder penaltyLog() { 1161 return enable(PENALTY_LOG); 1162 } 1163 1164 /** 1165 * Enable detected violations log a stacktrace and timing data to the {@link 1166 * android.os.DropBoxManager DropBox} on policy violation. Intended mostly for platform 1167 * integrators doing beta user field data collection. 1168 */ penaltyDropBox()1169 public @NonNull Builder penaltyDropBox() { 1170 return enable(PENALTY_DROPBOX); 1171 } 1172 1173 /** 1174 * Call #{@link OnVmViolationListener#onVmViolation(Violation)} on every violation. 1175 */ penaltyListener( @onNull Executor executor, @NonNull OnVmViolationListener listener)1176 public @NonNull Builder penaltyListener( 1177 @NonNull Executor executor, @NonNull OnVmViolationListener listener) { 1178 if (executor == null) { 1179 throw new NullPointerException("executor must not be null"); 1180 } 1181 mListener = listener; 1182 mExecutor = executor; 1183 return this; 1184 } 1185 1186 /** @removed */ penaltyListener( @onNull OnVmViolationListener listener, @NonNull Executor executor)1187 public @NonNull Builder penaltyListener( 1188 @NonNull OnVmViolationListener listener, @NonNull Executor executor) { 1189 return penaltyListener(executor, listener); 1190 } 1191 enable(@mPolicyMask int mask)1192 private Builder enable(@VmPolicyMask int mask) { 1193 mMask |= mask; 1194 return this; 1195 } 1196 disable(@mPolicyMask int mask)1197 Builder disable(@VmPolicyMask int mask) { 1198 mMask &= ~mask; 1199 return this; 1200 } 1201 1202 /** 1203 * Construct the VmPolicy instance. 1204 * 1205 * <p>Note: if no penalties are enabled before calling <code>build</code>, {@link 1206 * #penaltyLog} is implicitly set. 1207 */ build()1208 public VmPolicy build() { 1209 // If there are detection bits set but no violation bits 1210 // set, enable simple logging. 1211 if (mListener == null 1212 && mMask != 0 1213 && (mMask 1214 & (PENALTY_DEATH 1215 | PENALTY_LOG 1216 | PENALTY_DROPBOX 1217 | PENALTY_DIALOG)) 1218 == 0) { 1219 penaltyLog(); 1220 } 1221 return new VmPolicy( 1222 mMask, 1223 mClassInstanceLimit != null ? mClassInstanceLimit : EMPTY_CLASS_LIMIT_MAP, 1224 mListener, 1225 mExecutor); 1226 } 1227 } 1228 } 1229 1230 /** 1231 * Log of strict mode violation stack traces that have occurred during a Binder call, to be 1232 * serialized back later to the caller via Parcel.writeNoException() (amusingly) where the 1233 * caller can choose how to react. 1234 */ 1235 private static final ThreadLocal<ArrayList<ViolationInfo>> gatheredViolations = 1236 new ThreadLocal<ArrayList<ViolationInfo>>() { 1237 @Override 1238 protected ArrayList<ViolationInfo> initialValue() { 1239 // Starts null to avoid unnecessary allocations when 1240 // checking whether there are any violations or not in 1241 // hasGatheredViolations() below. 1242 return null; 1243 } 1244 }; 1245 1246 /** 1247 * Sets the policy for what actions on the current thread should be detected, as well as the 1248 * penalty if such actions occur. 1249 * 1250 * <p>Internally this sets a thread-local variable which is propagated across cross-process IPC 1251 * calls, meaning you can catch violations when a system service or another process accesses the 1252 * disk or network on your behalf. 1253 * 1254 * @param policy the policy to put into place 1255 */ setThreadPolicy(final ThreadPolicy policy)1256 public static void setThreadPolicy(final ThreadPolicy policy) { 1257 setThreadPolicyMask(policy.mask); 1258 sThreadViolationListener.set(policy.mListener); 1259 sThreadViolationExecutor.set(policy.mCallbackExecutor); 1260 } 1261 1262 /** @hide */ setThreadPolicyMask(@hreadPolicyMask int threadPolicyMask)1263 public static void setThreadPolicyMask(@ThreadPolicyMask int threadPolicyMask) { 1264 // In addition to the Java-level thread-local in Dalvik's 1265 // BlockGuard, we also need to keep a native thread-local in 1266 // Binder in order to propagate the value across Binder calls, 1267 // even across native-only processes. The two are kept in 1268 // sync via the callback to onStrictModePolicyChange, below. 1269 setBlockGuardPolicy(threadPolicyMask); 1270 1271 // And set the Android native version... 1272 Binder.setThreadStrictModePolicy(threadPolicyMask); 1273 } 1274 1275 // Sets the policy in Dalvik/libcore (BlockGuard) setBlockGuardPolicy(@hreadPolicyMask int threadPolicyMask)1276 private static void setBlockGuardPolicy(@ThreadPolicyMask int threadPolicyMask) { 1277 if (threadPolicyMask == 0) { 1278 BlockGuard.setThreadPolicy(BlockGuard.LAX_POLICY); 1279 return; 1280 } 1281 final BlockGuard.Policy policy = BlockGuard.getThreadPolicy(); 1282 final AndroidBlockGuardPolicy androidPolicy; 1283 if (policy instanceof AndroidBlockGuardPolicy) { 1284 androidPolicy = (AndroidBlockGuardPolicy) policy; 1285 } else { 1286 androidPolicy = THREAD_ANDROID_POLICY.get(); 1287 BlockGuard.setThreadPolicy(androidPolicy); 1288 } 1289 androidPolicy.setThreadPolicyMask(threadPolicyMask); 1290 } 1291 setBlockGuardVmPolicy(@mPolicyMask int vmPolicyMask)1292 private static void setBlockGuardVmPolicy(@VmPolicyMask int vmPolicyMask) { 1293 // We only need to install BlockGuard for a small subset of VM policies 1294 vmPolicyMask &= DETECT_VM_CREDENTIAL_PROTECTED_WHILE_LOCKED; 1295 if (vmPolicyMask != 0) { 1296 BlockGuard.setVmPolicy(VM_ANDROID_POLICY); 1297 } else { 1298 BlockGuard.setVmPolicy(BlockGuard.LAX_VM_POLICY); 1299 } 1300 } 1301 1302 // Sets up CloseGuard in Dalvik/libcore setCloseGuardEnabled(boolean enabled)1303 private static void setCloseGuardEnabled(boolean enabled) { 1304 if (!(CloseGuard.getReporter() instanceof AndroidCloseGuardReporter)) { 1305 CloseGuard.setReporter(new AndroidCloseGuardReporter()); 1306 } 1307 CloseGuard.setEnabled(enabled); 1308 } 1309 1310 /** 1311 * Returns the bitmask of the current thread's policy. 1312 * 1313 * @return the bitmask of all the DETECT_* and PENALTY_* bits currently enabled 1314 * @hide 1315 */ 1316 @UnsupportedAppUsage getThreadPolicyMask()1317 public static @ThreadPolicyMask int getThreadPolicyMask() { 1318 final BlockGuard.Policy policy = BlockGuard.getThreadPolicy(); 1319 if (policy instanceof AndroidBlockGuardPolicy) { 1320 return ((AndroidBlockGuardPolicy) policy).getThreadPolicyMask(); 1321 } else { 1322 return 0; 1323 } 1324 } 1325 1326 /** Returns the current thread's policy. */ getThreadPolicy()1327 public static ThreadPolicy getThreadPolicy() { 1328 // TODO: this was a last minute Gingerbread API change (to 1329 // introduce VmPolicy cleanly) but this isn't particularly 1330 // optimal for users who might call this method often. This 1331 // should be in a thread-local and not allocate on each call. 1332 return new ThreadPolicy( 1333 getThreadPolicyMask(), 1334 sThreadViolationListener.get(), 1335 sThreadViolationExecutor.get()); 1336 } 1337 1338 /** 1339 * A convenience wrapper that takes the current {@link ThreadPolicy} from {@link 1340 * #getThreadPolicy}, modifies it to permit both disk reads & writes, and sets the new 1341 * policy with {@link #setThreadPolicy}, returning the old policy so you can restore it at the 1342 * end of a block. 1343 * 1344 * @return the old policy, to be passed to {@link #setThreadPolicy} to restore the policy at the 1345 * end of a block 1346 */ allowThreadDiskWrites()1347 public static ThreadPolicy allowThreadDiskWrites() { 1348 return new ThreadPolicy( 1349 allowThreadDiskWritesMask(), 1350 sThreadViolationListener.get(), 1351 sThreadViolationExecutor.get()); 1352 } 1353 1354 /** @hide */ allowThreadDiskWritesMask()1355 public static @ThreadPolicyMask int allowThreadDiskWritesMask() { 1356 int oldPolicyMask = getThreadPolicyMask(); 1357 int newPolicyMask = oldPolicyMask & ~(DETECT_THREAD_DISK_WRITE | DETECT_THREAD_DISK_READ); 1358 if (newPolicyMask != oldPolicyMask) { 1359 setThreadPolicyMask(newPolicyMask); 1360 } 1361 return oldPolicyMask; 1362 } 1363 1364 /** 1365 * A convenience wrapper that takes the current {@link ThreadPolicy} from {@link 1366 * #getThreadPolicy}, modifies it to permit disk reads, and sets the new policy with {@link 1367 * #setThreadPolicy}, returning the old policy so you can restore it at the end of a block. 1368 * 1369 * @return the old policy, to be passed to setThreadPolicy to restore the policy. 1370 */ allowThreadDiskReads()1371 public static ThreadPolicy allowThreadDiskReads() { 1372 return new ThreadPolicy( 1373 allowThreadDiskReadsMask(), 1374 sThreadViolationListener.get(), 1375 sThreadViolationExecutor.get()); 1376 } 1377 1378 /** @hide */ allowThreadDiskReadsMask()1379 public static @ThreadPolicyMask int allowThreadDiskReadsMask() { 1380 int oldPolicyMask = getThreadPolicyMask(); 1381 int newPolicyMask = oldPolicyMask & ~(DETECT_THREAD_DISK_READ); 1382 if (newPolicyMask != oldPolicyMask) { 1383 setThreadPolicyMask(newPolicyMask); 1384 } 1385 return oldPolicyMask; 1386 } 1387 1388 /** @hide */ allowThreadViolations()1389 public static ThreadPolicy allowThreadViolations() { 1390 ThreadPolicy oldPolicy = getThreadPolicy(); 1391 setThreadPolicyMask(0); 1392 return oldPolicy; 1393 } 1394 1395 /** @hide */ allowVmViolations()1396 public static VmPolicy allowVmViolations() { 1397 VmPolicy oldPolicy = getVmPolicy(); 1398 sVmPolicy = VmPolicy.LAX; 1399 return oldPolicy; 1400 } 1401 1402 /** 1403 * Determine if the given app is "bundled" as part of the system image. These bundled apps are 1404 * developed in lock-step with the OS, and they aren't updated outside of an OTA, so we want to 1405 * chase any {@link StrictMode} regressions by enabling detection when running on {@link 1406 * Build#IS_USERDEBUG} or {@link Build#IS_ENG} builds. 1407 * 1408 * <p>Unbundled apps included in the system image are expected to detect and triage their own 1409 * {@link StrictMode} issues separate from the OS release process, which is why we don't enable 1410 * them here. 1411 * 1412 * @hide 1413 */ isBundledSystemApp(ApplicationInfo ai)1414 public static boolean isBundledSystemApp(ApplicationInfo ai) { 1415 if (ai == null || ai.packageName == null) { 1416 // Probably system server 1417 return true; 1418 } else if (ai.isSystemApp()) { 1419 // Ignore unbundled apps living in the wrong namespace 1420 if (ai.packageName.equals("com.android.vending") 1421 || ai.packageName.equals("com.android.chrome")) { 1422 return false; 1423 } 1424 1425 // Ignore bundled apps that are way too spammy 1426 // STOPSHIP: burn this list down to zero 1427 if (ai.packageName.equals("com.android.phone")) { 1428 return false; 1429 } 1430 1431 if (ai.packageName.equals("android") 1432 || ai.packageName.startsWith("android.") 1433 || ai.packageName.startsWith("com.android.")) { 1434 return true; 1435 } 1436 } 1437 return false; 1438 } 1439 1440 /** 1441 * Initialize default {@link ThreadPolicy} for the current thread. 1442 * 1443 * @hide 1444 */ initThreadDefaults(ApplicationInfo ai)1445 public static void initThreadDefaults(ApplicationInfo ai) { 1446 final ThreadPolicy.Builder builder = new ThreadPolicy.Builder(); 1447 final int targetSdkVersion = 1448 (ai != null) ? ai.targetSdkVersion : Build.VERSION_CODES.CUR_DEVELOPMENT; 1449 1450 // Starting in HC, we don't allow network usage on the main thread 1451 if (targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB) { 1452 builder.detectNetwork(); 1453 builder.penaltyDeathOnNetwork(); 1454 } 1455 1456 if (Build.IS_USER || DISABLE || SystemProperties.getBoolean(DISABLE_PROPERTY, false)) { 1457 // Detect nothing extra 1458 } else if (Build.IS_USERDEBUG) { 1459 // Detect everything in bundled apps 1460 if (isBundledSystemApp(ai)) { 1461 builder.detectAll(); 1462 builder.penaltyDropBox(); 1463 if (SystemProperties.getBoolean(VISUAL_PROPERTY, false)) { 1464 builder.penaltyFlashScreen(); 1465 } 1466 } 1467 } else if (Build.IS_ENG) { 1468 // Detect everything in bundled apps 1469 if (isBundledSystemApp(ai)) { 1470 builder.detectAll(); 1471 builder.penaltyDropBox(); 1472 builder.penaltyLog(); 1473 builder.penaltyFlashScreen(); 1474 } 1475 } 1476 1477 setThreadPolicy(builder.build()); 1478 } 1479 1480 /** 1481 * Initialize default {@link VmPolicy} for the current VM. 1482 * 1483 * @hide 1484 */ initVmDefaults(ApplicationInfo ai)1485 public static void initVmDefaults(ApplicationInfo ai) { 1486 final VmPolicy.Builder builder = new VmPolicy.Builder(); 1487 final int targetSdkVersion = 1488 (ai != null) ? ai.targetSdkVersion : Build.VERSION_CODES.CUR_DEVELOPMENT; 1489 1490 // Starting in N, we don't allow file:// Uri exposure 1491 if (targetSdkVersion >= Build.VERSION_CODES.N) { 1492 builder.detectFileUriExposure(); 1493 builder.penaltyDeathOnFileUriExposure(); 1494 } 1495 1496 if (Build.IS_USER || DISABLE || SystemProperties.getBoolean(DISABLE_PROPERTY, false)) { 1497 // Detect nothing extra 1498 } else if (Build.IS_USERDEBUG) { 1499 // Detect everything in bundled apps (except activity leaks, which 1500 // are expensive to track) 1501 if (isBundledSystemApp(ai)) { 1502 builder.detectAll(); 1503 builder.permitActivityLeaks(); 1504 builder.penaltyDropBox(); 1505 } 1506 } else if (Build.IS_ENG) { 1507 // Detect everything in bundled apps 1508 if (isBundledSystemApp(ai)) { 1509 builder.detectAll(); 1510 builder.penaltyDropBox(); 1511 builder.penaltyLog(); 1512 } 1513 } 1514 1515 setVmPolicy(builder.build()); 1516 } 1517 1518 /** 1519 * Used by the framework to make file usage a fatal error. 1520 * 1521 * @hide 1522 */ 1523 @UnsupportedAppUsage enableDeathOnFileUriExposure()1524 public static void enableDeathOnFileUriExposure() { 1525 sVmPolicy = 1526 new VmPolicy( 1527 sVmPolicy.mask 1528 | DETECT_VM_FILE_URI_EXPOSURE 1529 | PENALTY_DEATH_ON_FILE_URI_EXPOSURE, 1530 sVmPolicy.classInstanceLimit, 1531 sVmPolicy.mListener, 1532 sVmPolicy.mCallbackExecutor); 1533 } 1534 1535 /** 1536 * Used by lame internal apps that haven't done the hard work to get themselves off file:// Uris 1537 * yet. 1538 * 1539 * @hide 1540 */ 1541 @UnsupportedAppUsage disableDeathOnFileUriExposure()1542 public static void disableDeathOnFileUriExposure() { 1543 sVmPolicy = 1544 new VmPolicy( 1545 sVmPolicy.mask 1546 & ~(DETECT_VM_FILE_URI_EXPOSURE 1547 | PENALTY_DEATH_ON_FILE_URI_EXPOSURE), 1548 sVmPolicy.classInstanceLimit, 1549 sVmPolicy.mListener, 1550 sVmPolicy.mCallbackExecutor); 1551 } 1552 1553 @UnsupportedAppUsage 1554 private static final ThreadLocal<ArrayList<ViolationInfo>> violationsBeingTimed = 1555 new ThreadLocal<ArrayList<ViolationInfo>>() { 1556 @Override 1557 protected ArrayList<ViolationInfo> initialValue() { 1558 return new ArrayList<ViolationInfo>(); 1559 } 1560 }; 1561 1562 // Note: only access this once verifying the thread has a Looper. 1563 private static final ThreadLocal<Handler> THREAD_HANDLER = 1564 new ThreadLocal<Handler>() { 1565 @Override 1566 protected Handler initialValue() { 1567 return new Handler(); 1568 } 1569 }; 1570 1571 private static final ThreadLocal<AndroidBlockGuardPolicy> THREAD_ANDROID_POLICY = 1572 new ThreadLocal<AndroidBlockGuardPolicy>() { 1573 @Override 1574 protected AndroidBlockGuardPolicy initialValue() { 1575 return new AndroidBlockGuardPolicy(0); 1576 } 1577 }; 1578 tooManyViolationsThisLoop()1579 private static boolean tooManyViolationsThisLoop() { 1580 return violationsBeingTimed.get().size() >= MAX_OFFENSES_PER_LOOP; 1581 } 1582 1583 private static class AndroidBlockGuardPolicy implements BlockGuard.Policy { 1584 private @ThreadPolicyMask int mThreadPolicyMask; 1585 1586 // Map from violation stacktrace hashcode -> uptimeMillis of 1587 // last violation. No locking needed, as this is only 1588 // accessed by the same thread. 1589 /** Temporarily retained; appears to be missing UnsupportedAppUsage annotation */ 1590 private ArrayMap<Integer, Long> mLastViolationTime; 1591 private SparseLongArray mRealLastViolationTime; 1592 AndroidBlockGuardPolicy(@hreadPolicyMask int threadPolicyMask)1593 public AndroidBlockGuardPolicy(@ThreadPolicyMask int threadPolicyMask) { 1594 mThreadPolicyMask = threadPolicyMask; 1595 } 1596 1597 @Override toString()1598 public String toString() { 1599 return "AndroidBlockGuardPolicy; mPolicyMask=" + mThreadPolicyMask; 1600 } 1601 1602 // Part of BlockGuard.Policy interface: getPolicyMask()1603 public int getPolicyMask() { 1604 return mThreadPolicyMask; 1605 } 1606 1607 // Part of BlockGuard.Policy interface: onWriteToDisk()1608 public void onWriteToDisk() { 1609 if ((mThreadPolicyMask & DETECT_THREAD_DISK_WRITE) == 0) { 1610 return; 1611 } 1612 if (tooManyViolationsThisLoop()) { 1613 return; 1614 } 1615 startHandlingViolationException(new DiskWriteViolation()); 1616 } 1617 1618 // Not part of BlockGuard.Policy; just part of StrictMode: onCustomSlowCall(String name)1619 void onCustomSlowCall(String name) { 1620 if ((mThreadPolicyMask & DETECT_THREAD_CUSTOM) == 0) { 1621 return; 1622 } 1623 if (tooManyViolationsThisLoop()) { 1624 return; 1625 } 1626 startHandlingViolationException(new CustomViolation(name)); 1627 } 1628 1629 // Not part of BlockGuard.Policy; just part of StrictMode: onResourceMismatch(Object tag)1630 void onResourceMismatch(Object tag) { 1631 if ((mThreadPolicyMask & DETECT_THREAD_RESOURCE_MISMATCH) == 0) { 1632 return; 1633 } 1634 if (tooManyViolationsThisLoop()) { 1635 return; 1636 } 1637 startHandlingViolationException(new ResourceMismatchViolation(tag)); 1638 } 1639 1640 // Not part of BlockGuard.Policy; just part of StrictMode: onUnbufferedIO()1641 public void onUnbufferedIO() { 1642 if ((mThreadPolicyMask & DETECT_THREAD_UNBUFFERED_IO) == 0) { 1643 return; 1644 } 1645 if (tooManyViolationsThisLoop()) { 1646 return; 1647 } 1648 startHandlingViolationException(new UnbufferedIoViolation()); 1649 } 1650 1651 // Part of BlockGuard.Policy interface: onReadFromDisk()1652 public void onReadFromDisk() { 1653 if ((mThreadPolicyMask & DETECT_THREAD_DISK_READ) == 0) { 1654 return; 1655 } 1656 if (tooManyViolationsThisLoop()) { 1657 return; 1658 } 1659 startHandlingViolationException(new DiskReadViolation()); 1660 } 1661 1662 // Part of BlockGuard.Policy interface: onNetwork()1663 public void onNetwork() { 1664 if ((mThreadPolicyMask & DETECT_THREAD_NETWORK) == 0) { 1665 return; 1666 } 1667 if ((mThreadPolicyMask & PENALTY_DEATH_ON_NETWORK) != 0) { 1668 throw new NetworkOnMainThreadException(); 1669 } 1670 if (tooManyViolationsThisLoop()) { 1671 return; 1672 } 1673 startHandlingViolationException(new NetworkViolation()); 1674 } 1675 1676 // Part of BlockGuard.Policy interface: onExplicitGc()1677 public void onExplicitGc() { 1678 if ((mThreadPolicyMask & DETECT_THREAD_EXPLICIT_GC) == 0) { 1679 return; 1680 } 1681 if (tooManyViolationsThisLoop()) { 1682 return; 1683 } 1684 startHandlingViolationException(new ExplicitGcViolation()); 1685 } 1686 getThreadPolicyMask()1687 public @ThreadPolicyMask int getThreadPolicyMask() { 1688 return mThreadPolicyMask; 1689 } 1690 setThreadPolicyMask(@hreadPolicyMask int threadPolicyMask)1691 public void setThreadPolicyMask(@ThreadPolicyMask int threadPolicyMask) { 1692 mThreadPolicyMask = threadPolicyMask; 1693 } 1694 1695 // Start handling a violation that just started and hasn't 1696 // actually run yet (e.g. no disk write or network operation 1697 // has yet occurred). This sees if we're in an event loop 1698 // thread and, if so, uses it to roughly measure how long the 1699 // violation took. startHandlingViolationException(Violation e)1700 void startHandlingViolationException(Violation e) { 1701 final int penaltyMask = (mThreadPolicyMask & PENALTY_ALL); 1702 final ViolationInfo info = new ViolationInfo(e, penaltyMask); 1703 info.violationUptimeMillis = SystemClock.uptimeMillis(); 1704 handleViolationWithTimingAttempt(info); 1705 } 1706 1707 // Attempts to fill in the provided ViolationInfo's 1708 // durationMillis field if this thread has a Looper we can use 1709 // to measure with. We measure from the time of violation 1710 // until the time the looper is idle again (right before 1711 // the next epoll_wait) handleViolationWithTimingAttempt(final ViolationInfo info)1712 void handleViolationWithTimingAttempt(final ViolationInfo info) { 1713 Looper looper = Looper.myLooper(); 1714 1715 // Without a Looper, we're unable to time how long the 1716 // violation takes place. This case should be rare, as 1717 // most users will care about timing violations that 1718 // happen on their main UI thread. Note that this case is 1719 // also hit when a violation takes place in a Binder 1720 // thread, in "gather" mode. In this case, the duration 1721 // of the violation is computed by the ultimate caller and 1722 // its Looper, if any. 1723 // 1724 // Also, as a special short-cut case when the only penalty 1725 // bit is death, we die immediately, rather than timing 1726 // the violation's duration. This makes it convenient to 1727 // use in unit tests too, rather than waiting on a Looper. 1728 // 1729 // TODO: if in gather mode, ignore Looper.myLooper() and always 1730 // go into this immediate mode? 1731 if (looper == null || (info.mPenaltyMask == PENALTY_DEATH)) { 1732 info.durationMillis = -1; // unknown (redundant, already set) 1733 onThreadPolicyViolation(info); 1734 return; 1735 } 1736 1737 final ArrayList<ViolationInfo> records = violationsBeingTimed.get(); 1738 if (records.size() >= MAX_OFFENSES_PER_LOOP) { 1739 // Not worth measuring. Too many offenses in one loop. 1740 return; 1741 } 1742 records.add(info); 1743 if (records.size() > 1) { 1744 // There's already been a violation this loop, so we've already 1745 // registered an idle handler to process the list of violations 1746 // at the end of this Looper's loop. 1747 return; 1748 } 1749 1750 final IWindowManager windowManager = 1751 info.penaltyEnabled(PENALTY_FLASH) ? sWindowManager.get() : null; 1752 if (windowManager != null) { 1753 try { 1754 windowManager.showStrictModeViolation(true); 1755 } catch (RemoteException unused) { 1756 } 1757 } 1758 1759 // We post a runnable to a Handler (== delay 0 ms) for 1760 // measuring the end time of a violation instead of using 1761 // an IdleHandler (as was previously used) because an 1762 // IdleHandler may not run for quite a long period of time 1763 // if an ongoing animation is happening and continually 1764 // posting ASAP (0 ms) animation steps. Animations are 1765 // throttled back to 60fps via SurfaceFlinger/View 1766 // invalidates, _not_ by posting frame updates every 16 1767 // milliseconds. 1768 THREAD_HANDLER 1769 .get() 1770 .postAtFrontOfQueue( 1771 () -> { 1772 long loopFinishTime = SystemClock.uptimeMillis(); 1773 1774 // Note: we do this early, before handling the 1775 // violation below, as handling the violation 1776 // may include PENALTY_DEATH and we don't want 1777 // to keep the red border on. 1778 if (windowManager != null) { 1779 try { 1780 windowManager.showStrictModeViolation(false); 1781 } catch (RemoteException unused) { 1782 } 1783 } 1784 1785 for (int n = 0; n < records.size(); ++n) { 1786 ViolationInfo v = records.get(n); 1787 v.violationNumThisLoop = n + 1; 1788 v.durationMillis = 1789 (int) (loopFinishTime - v.violationUptimeMillis); 1790 onThreadPolicyViolation(v); 1791 } 1792 records.clear(); 1793 }); 1794 } 1795 1796 // Note: It's possible (even quite likely) that the 1797 // thread-local policy mask has changed from the time the 1798 // violation fired and now (after the violating code ran) due 1799 // to people who push/pop temporary policy in regions of code, 1800 // hence the policy being passed around. onThreadPolicyViolation(final ViolationInfo info)1801 void onThreadPolicyViolation(final ViolationInfo info) { 1802 if (LOG_V) Log.d(TAG, "onThreadPolicyViolation; penalty=" + info.mPenaltyMask); 1803 1804 if (info.penaltyEnabled(PENALTY_GATHER)) { 1805 ArrayList<ViolationInfo> violations = gatheredViolations.get(); 1806 if (violations == null) { 1807 violations = new ArrayList<>(1); 1808 gatheredViolations.set(violations); 1809 } 1810 for (ViolationInfo previous : violations) { 1811 if (info.getStackTrace().equals(previous.getStackTrace())) { 1812 // Duplicate. Don't log. 1813 return; 1814 } 1815 } 1816 violations.add(info); 1817 return; 1818 } 1819 1820 // Not perfect, but fast and good enough for dup suppression. 1821 Integer crashFingerprint = info.hashCode(); 1822 long lastViolationTime = 0; 1823 long now = SystemClock.uptimeMillis(); 1824 if (sLogger == LOGCAT_LOGGER) { // Don't throttle it if there is a non-default logger 1825 if (mRealLastViolationTime != null) { 1826 Long vtime = mRealLastViolationTime.get(crashFingerprint); 1827 if (vtime != null) { 1828 lastViolationTime = vtime; 1829 } 1830 clampViolationTimeMap(mRealLastViolationTime, Math.max(MIN_LOG_INTERVAL_MS, 1831 Math.max(MIN_DIALOG_INTERVAL_MS, MIN_DROPBOX_INTERVAL_MS))); 1832 } else { 1833 mRealLastViolationTime = new SparseLongArray(1); 1834 } 1835 mRealLastViolationTime.put(crashFingerprint, now); 1836 } 1837 long timeSinceLastViolationMillis = 1838 lastViolationTime == 0 ? Long.MAX_VALUE : (now - lastViolationTime); 1839 1840 if (info.penaltyEnabled(PENALTY_LOG) 1841 && timeSinceLastViolationMillis > MIN_LOG_INTERVAL_MS) { 1842 sLogger.log(info); 1843 } 1844 1845 final Violation violation = info.mViolation; 1846 1847 // Penalties that ActivityManager should execute on our behalf. 1848 int penaltyMask = 0; 1849 1850 if (info.penaltyEnabled(PENALTY_DIALOG) 1851 && timeSinceLastViolationMillis > MIN_DIALOG_INTERVAL_MS) { 1852 penaltyMask |= PENALTY_DIALOG; 1853 } 1854 1855 if (info.penaltyEnabled(PENALTY_DROPBOX) 1856 && timeSinceLastViolationMillis > MIN_DROPBOX_INTERVAL_MS) { 1857 penaltyMask |= PENALTY_DROPBOX; 1858 } 1859 1860 if (penaltyMask != 0) { 1861 final boolean justDropBox = (info.mPenaltyMask == PENALTY_DROPBOX); 1862 if (justDropBox) { 1863 // If all we're going to ask the activity manager 1864 // to do is dropbox it (the common case during 1865 // platform development), we can avoid doing this 1866 // call synchronously which Binder data suggests 1867 // isn't always super fast, despite the implementation 1868 // in the ActivityManager trying to be mostly async. 1869 dropboxViolationAsync(penaltyMask, info); 1870 } else { 1871 handleApplicationStrictModeViolation(penaltyMask, info); 1872 } 1873 } 1874 1875 if (info.penaltyEnabled(PENALTY_DEATH)) { 1876 throw new RuntimeException("StrictMode ThreadPolicy violation", violation); 1877 } 1878 1879 // penaltyDeath will cause penaltyCallback to no-op since we cannot guarantee the 1880 // executor finishes before crashing. 1881 final OnThreadViolationListener listener = sThreadViolationListener.get(); 1882 final Executor executor = sThreadViolationExecutor.get(); 1883 if (listener != null && executor != null) { 1884 try { 1885 executor.execute( 1886 () -> { 1887 // Lift violated policy to prevent infinite recursion. 1888 ThreadPolicy oldPolicy = StrictMode.allowThreadViolations(); 1889 try { 1890 listener.onThreadViolation(violation); 1891 } finally { 1892 StrictMode.setThreadPolicy(oldPolicy); 1893 } 1894 }); 1895 } catch (RejectedExecutionException e) { 1896 Log.e(TAG, "ThreadPolicy penaltyCallback failed", e); 1897 } 1898 } 1899 } 1900 } 1901 1902 private static final BlockGuard.VmPolicy VM_ANDROID_POLICY = new BlockGuard.VmPolicy() { 1903 @Override 1904 public void onPathAccess(String path) { 1905 if (path == null) return; 1906 1907 // NOTE: keep credential-protected paths in sync with Environment.java 1908 if (path.startsWith("/data/user/") 1909 || path.startsWith("/data/media/") 1910 || path.startsWith("/data/system_ce/") 1911 || path.startsWith("/data/misc_ce/") 1912 || path.startsWith("/data/vendor_ce/") 1913 || path.startsWith("/storage/emulated/")) { 1914 final int second = path.indexOf('/', 1); 1915 final int third = path.indexOf('/', second + 1); 1916 final int fourth = path.indexOf('/', third + 1); 1917 if (fourth == -1) return; 1918 1919 try { 1920 final int userId = Integer.parseInt(path.substring(third + 1, fourth)); 1921 onCredentialProtectedPathAccess(path, userId); 1922 } catch (NumberFormatException ignored) { 1923 } 1924 } else if (path.startsWith("/data/data/")) { 1925 onCredentialProtectedPathAccess(path, UserHandle.USER_SYSTEM); 1926 } 1927 } 1928 }; 1929 1930 /** 1931 * In the common case, as set by conditionallyEnableDebugLogging, we're just dropboxing any 1932 * violations but not showing a dialog, not loggging, and not killing the process. In these 1933 * cases we don't need to do a synchronous call to the ActivityManager. This is used by both 1934 * per-thread and vm-wide violations when applicable. 1935 */ dropboxViolationAsync( final int penaltyMask, final ViolationInfo info)1936 private static void dropboxViolationAsync( 1937 final int penaltyMask, final ViolationInfo info) { 1938 int outstanding = sDropboxCallsInFlight.incrementAndGet(); 1939 if (outstanding > 20) { 1940 // What's going on? Let's not make make the situation 1941 // worse and just not log. 1942 sDropboxCallsInFlight.decrementAndGet(); 1943 return; 1944 } 1945 1946 if (LOG_V) Log.d(TAG, "Dropboxing async; in-flight=" + outstanding); 1947 1948 BackgroundThread.getHandler().post(() -> { 1949 handleApplicationStrictModeViolation(penaltyMask, info); 1950 int outstandingInner = sDropboxCallsInFlight.decrementAndGet(); 1951 if (LOG_V) Log.d(TAG, "Dropbox complete; in-flight=" + outstandingInner); 1952 }); 1953 } 1954 handleApplicationStrictModeViolation(int penaltyMask, ViolationInfo info)1955 private static void handleApplicationStrictModeViolation(int penaltyMask, 1956 ViolationInfo info) { 1957 final int oldMask = getThreadPolicyMask(); 1958 try { 1959 // First, remove any policy before we call into the Activity Manager, 1960 // otherwise we'll infinite recurse as we try to log policy violations 1961 // to disk, thus violating policy, thus requiring logging, etc... 1962 // We restore the current policy below, in the finally block. 1963 setThreadPolicyMask(0); 1964 1965 IActivityManager am = ActivityManager.getService(); 1966 if (am == null) { 1967 Log.w(TAG, "No activity manager; failed to Dropbox violation."); 1968 } else { 1969 am.handleApplicationStrictModeViolation( 1970 RuntimeInit.getApplicationObject(), penaltyMask, info); 1971 } 1972 } catch (RemoteException e) { 1973 if (e instanceof DeadObjectException) { 1974 // System process is dead; ignore 1975 } else { 1976 Log.e(TAG, "RemoteException handling StrictMode violation", e); 1977 } 1978 } finally { 1979 setThreadPolicyMask(oldMask); 1980 } 1981 } 1982 1983 private static class AndroidCloseGuardReporter implements CloseGuard.Reporter { 1984 1985 @Override report(String message, Throwable allocationSite)1986 public void report(String message, Throwable allocationSite) { 1987 onVmPolicyViolation(new LeakedClosableViolation(message, allocationSite)); 1988 } 1989 1990 @Override report(String message)1991 public void report(String message) { 1992 onVmPolicyViolation(new LeakedClosableViolation(message)); 1993 } 1994 } 1995 1996 /** Called from Parcel.writeNoException() */ hasGatheredViolations()1997 /* package */ static boolean hasGatheredViolations() { 1998 return gatheredViolations.get() != null; 1999 } 2000 2001 /** 2002 * Called from Parcel.writeException(), so we drop this memory and don't incorrectly attribute 2003 * it to the wrong caller on the next Binder call on this thread. 2004 */ clearGatheredViolations()2005 /* package */ static void clearGatheredViolations() { 2006 gatheredViolations.set(null); 2007 } 2008 2009 /** @hide */ 2010 @UnsupportedAppUsage 2011 @TestApi conditionallyCheckInstanceCounts()2012 public static void conditionallyCheckInstanceCounts() { 2013 VmPolicy policy = getVmPolicy(); 2014 int policySize = policy.classInstanceLimit.size(); 2015 if (policySize == 0) { 2016 return; 2017 } 2018 2019 System.gc(); 2020 System.runFinalization(); 2021 System.gc(); 2022 2023 // Note: classInstanceLimit is immutable, so this is lock-free 2024 // Create the classes array. 2025 Class[] classes = policy.classInstanceLimit.keySet().toArray(new Class[policySize]); 2026 long[] instanceCounts = VMDebug.countInstancesOfClasses(classes, false); 2027 for (int i = 0; i < classes.length; ++i) { 2028 Class klass = classes[i]; 2029 int limit = policy.classInstanceLimit.get(klass); 2030 long instances = instanceCounts[i]; 2031 if (instances > limit) { 2032 onVmPolicyViolation(new InstanceCountViolation(klass, instances, limit)); 2033 } 2034 } 2035 } 2036 2037 private static long sLastInstanceCountCheckMillis = 0; 2038 private static boolean sIsIdlerRegistered = false; // guarded by StrictMode.class 2039 private static final MessageQueue.IdleHandler sProcessIdleHandler = 2040 new MessageQueue.IdleHandler() { 2041 public boolean queueIdle() { 2042 long now = SystemClock.uptimeMillis(); 2043 if (now - sLastInstanceCountCheckMillis > 30 * 1000) { 2044 sLastInstanceCountCheckMillis = now; 2045 conditionallyCheckInstanceCounts(); 2046 } 2047 return true; 2048 } 2049 }; 2050 2051 /** 2052 * Sets the policy for what actions in the VM process (on any thread) should be detected, as 2053 * well as the penalty if such actions occur. 2054 * 2055 * @param policy the policy to put into place 2056 */ setVmPolicy(final VmPolicy policy)2057 public static void setVmPolicy(final VmPolicy policy) { 2058 synchronized (StrictMode.class) { 2059 sVmPolicy = policy; 2060 setCloseGuardEnabled(vmClosableObjectLeaksEnabled()); 2061 2062 Looper looper = Looper.getMainLooper(); 2063 if (looper != null) { 2064 MessageQueue mq = looper.mQueue; 2065 if (policy.classInstanceLimit.size() == 0 2066 || (sVmPolicy.mask & PENALTY_ALL) == 0) { 2067 mq.removeIdleHandler(sProcessIdleHandler); 2068 sIsIdlerRegistered = false; 2069 } else if (!sIsIdlerRegistered) { 2070 mq.addIdleHandler(sProcessIdleHandler); 2071 sIsIdlerRegistered = true; 2072 } 2073 } 2074 2075 int networkPolicy = NETWORK_POLICY_ACCEPT; 2076 if ((sVmPolicy.mask & DETECT_VM_CLEARTEXT_NETWORK) != 0) { 2077 if ((sVmPolicy.mask & PENALTY_DEATH) != 0 2078 || (sVmPolicy.mask & PENALTY_DEATH_ON_CLEARTEXT_NETWORK) != 0) { 2079 networkPolicy = NETWORK_POLICY_REJECT; 2080 } else { 2081 networkPolicy = NETWORK_POLICY_LOG; 2082 } 2083 } 2084 2085 final INetworkManagementService netd = 2086 INetworkManagementService.Stub.asInterface( 2087 ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE)); 2088 if (netd != null) { 2089 try { 2090 netd.setUidCleartextNetworkPolicy(android.os.Process.myUid(), networkPolicy); 2091 } catch (RemoteException ignored) { 2092 } 2093 } else if (networkPolicy != NETWORK_POLICY_ACCEPT) { 2094 Log.w(TAG, "Dropping requested network policy due to missing service!"); 2095 } 2096 2097 2098 if ((sVmPolicy.mask & DETECT_VM_NON_SDK_API_USAGE) != 0) { 2099 VMRuntime.setNonSdkApiUsageConsumer(sNonSdkApiUsageConsumer); 2100 VMRuntime.setDedupeHiddenApiWarnings(false); 2101 } else { 2102 VMRuntime.setNonSdkApiUsageConsumer(null); 2103 VMRuntime.setDedupeHiddenApiWarnings(true); 2104 } 2105 2106 setBlockGuardVmPolicy(sVmPolicy.mask); 2107 } 2108 } 2109 2110 /** Gets the current VM policy. */ getVmPolicy()2111 public static VmPolicy getVmPolicy() { 2112 synchronized (StrictMode.class) { 2113 return sVmPolicy; 2114 } 2115 } 2116 2117 /** 2118 * Enable the recommended StrictMode defaults, with violations just being logged. 2119 * 2120 * <p>This catches disk and network access on the main thread, as well as leaked SQLite cursors 2121 * and unclosed resources. This is simply a wrapper around {@link #setVmPolicy} and {@link 2122 * #setThreadPolicy}. 2123 */ enableDefaults()2124 public static void enableDefaults() { 2125 setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog().build()); 2126 setVmPolicy(new StrictMode.VmPolicy.Builder().detectAll().penaltyLog().build()); 2127 } 2128 2129 /** @hide */ vmSqliteObjectLeaksEnabled()2130 public static boolean vmSqliteObjectLeaksEnabled() { 2131 return (sVmPolicy.mask & DETECT_VM_CURSOR_LEAKS) != 0; 2132 } 2133 2134 /** @hide */ vmClosableObjectLeaksEnabled()2135 public static boolean vmClosableObjectLeaksEnabled() { 2136 return (sVmPolicy.mask & DETECT_VM_CLOSABLE_LEAKS) != 0; 2137 } 2138 2139 /** @hide */ vmRegistrationLeaksEnabled()2140 public static boolean vmRegistrationLeaksEnabled() { 2141 return (sVmPolicy.mask & DETECT_VM_REGISTRATION_LEAKS) != 0; 2142 } 2143 2144 /** @hide */ vmFileUriExposureEnabled()2145 public static boolean vmFileUriExposureEnabled() { 2146 return (sVmPolicy.mask & DETECT_VM_FILE_URI_EXPOSURE) != 0; 2147 } 2148 2149 /** @hide */ vmCleartextNetworkEnabled()2150 public static boolean vmCleartextNetworkEnabled() { 2151 return (sVmPolicy.mask & DETECT_VM_CLEARTEXT_NETWORK) != 0; 2152 } 2153 2154 /** @hide */ vmContentUriWithoutPermissionEnabled()2155 public static boolean vmContentUriWithoutPermissionEnabled() { 2156 return (sVmPolicy.mask & DETECT_VM_CONTENT_URI_WITHOUT_PERMISSION) != 0; 2157 } 2158 2159 /** @hide */ vmUntaggedSocketEnabled()2160 public static boolean vmUntaggedSocketEnabled() { 2161 return (sVmPolicy.mask & DETECT_VM_UNTAGGED_SOCKET) != 0; 2162 } 2163 2164 /** @hide */ vmImplicitDirectBootEnabled()2165 public static boolean vmImplicitDirectBootEnabled() { 2166 return (sVmPolicy.mask & DETECT_VM_IMPLICIT_DIRECT_BOOT) != 0; 2167 } 2168 2169 /** @hide */ vmCredentialProtectedWhileLockedEnabled()2170 public static boolean vmCredentialProtectedWhileLockedEnabled() { 2171 return (sVmPolicy.mask & DETECT_VM_CREDENTIAL_PROTECTED_WHILE_LOCKED) != 0; 2172 } 2173 2174 /** @hide */ vmIncorrectContextUseEnabled()2175 public static boolean vmIncorrectContextUseEnabled() { 2176 return (sVmPolicy.mask & DETECT_VM_INCORRECT_CONTEXT_USE) != 0; 2177 } 2178 2179 /** @hide */ vmUnsafeIntentLaunchEnabled()2180 public static boolean vmUnsafeIntentLaunchEnabled() { 2181 return (sVmPolicy.mask & DETECT_VM_UNSAFE_INTENT_LAUNCH) != 0; 2182 } 2183 2184 /** @hide */ onSqliteObjectLeaked(String message, Throwable originStack)2185 public static void onSqliteObjectLeaked(String message, Throwable originStack) { 2186 onVmPolicyViolation(new SqliteObjectLeakedViolation(message, originStack)); 2187 } 2188 2189 /** @hide */ 2190 @UnsupportedAppUsage onWebViewMethodCalledOnWrongThread(Throwable originStack)2191 public static void onWebViewMethodCalledOnWrongThread(Throwable originStack) { 2192 onVmPolicyViolation(new WebViewMethodCalledOnWrongThreadViolation(originStack)); 2193 } 2194 2195 /** @hide */ onIntentReceiverLeaked(Throwable originStack)2196 public static void onIntentReceiverLeaked(Throwable originStack) { 2197 onVmPolicyViolation(new IntentReceiverLeakedViolation(originStack)); 2198 } 2199 2200 /** @hide */ onServiceConnectionLeaked(Throwable originStack)2201 public static void onServiceConnectionLeaked(Throwable originStack) { 2202 onVmPolicyViolation(new ServiceConnectionLeakedViolation(originStack)); 2203 } 2204 2205 /** @hide */ onFileUriExposed(Uri uri, String location)2206 public static void onFileUriExposed(Uri uri, String location) { 2207 final String message = uri + " exposed beyond app through " + location; 2208 if ((sVmPolicy.mask & PENALTY_DEATH_ON_FILE_URI_EXPOSURE) != 0) { 2209 throw new FileUriExposedException(message); 2210 } else { 2211 onVmPolicyViolation(new FileUriExposedViolation(message)); 2212 } 2213 } 2214 2215 /** @hide */ onContentUriWithoutPermission(Uri uri, String location)2216 public static void onContentUriWithoutPermission(Uri uri, String location) { 2217 onVmPolicyViolation(new ContentUriWithoutPermissionViolation(uri, location)); 2218 } 2219 2220 /** @hide */ onCleartextNetworkDetected(byte[] firstPacket)2221 public static void onCleartextNetworkDetected(byte[] firstPacket) { 2222 byte[] rawAddr = null; 2223 if (firstPacket != null) { 2224 if (firstPacket.length >= 20 && (firstPacket[0] & 0xf0) == 0x40) { 2225 // IPv4 2226 rawAddr = new byte[4]; 2227 System.arraycopy(firstPacket, 16, rawAddr, 0, 4); 2228 } else if (firstPacket.length >= 40 && (firstPacket[0] & 0xf0) == 0x60) { 2229 // IPv6 2230 rawAddr = new byte[16]; 2231 System.arraycopy(firstPacket, 24, rawAddr, 0, 16); 2232 } 2233 } 2234 2235 final int uid = android.os.Process.myUid(); 2236 final StringBuilder msg = new StringBuilder("Detected cleartext network traffic from UID ") 2237 .append(uid); 2238 if (rawAddr != null) { 2239 try { 2240 msg.append(" to ").append(InetAddress.getByAddress(rawAddr)); 2241 } catch (UnknownHostException ignored) { 2242 } 2243 } 2244 msg.append(HexDump.dumpHexString(firstPacket).trim()).append(' '); 2245 final boolean forceDeath = (sVmPolicy.mask & PENALTY_DEATH_ON_CLEARTEXT_NETWORK) != 0; 2246 onVmPolicyViolation(new CleartextNetworkViolation(msg.toString()), forceDeath); 2247 } 2248 2249 /** @hide */ onUntaggedSocket()2250 public static void onUntaggedSocket() { 2251 onVmPolicyViolation(new UntaggedSocketViolation()); 2252 } 2253 2254 /** @hide */ onImplicitDirectBoot()2255 public static void onImplicitDirectBoot() { 2256 onVmPolicyViolation(new ImplicitDirectBootViolation()); 2257 } 2258 2259 /** @hide */ onIncorrectContextUsed(String message, Throwable originStack)2260 public static void onIncorrectContextUsed(String message, Throwable originStack) { 2261 onVmPolicyViolation(new IncorrectContextUseViolation(message, originStack)); 2262 } 2263 2264 /** 2265 * A helper method to verify if the {@code context} has a proper {@link Configuration} to obtain 2266 * {@link android.view.LayoutInflater}, {@link android.view.ViewConfiguration} or 2267 * {@link android.view.GestureDetector}. Throw {@link IncorrectContextUseViolation} if the 2268 * {@code context} doesn't have a proper configuration. 2269 * <p> 2270 * Note that the context created via {@link Context#createConfigurationContext(Configuration)} 2271 * is also regarded as a context with a proper configuration because the {@link Configuration} 2272 * is handled by developers. 2273 * </p> 2274 * @param context The context to verify if it is a display associative context 2275 * @param methodName The asserted method name 2276 * 2277 * @see Context#isConfigurationContext() 2278 * @see Context#createConfigurationContext(Configuration) 2279 * @see Context#getSystemService(String) 2280 * @see Context#LAYOUT_INFLATER_SERVICE 2281 * @see android.view.ViewConfiguration#get(Context) 2282 * @see android.view.LayoutInflater#from(Context) 2283 * @see IncorrectContextUseViolation 2284 * 2285 * @hide 2286 */ assertConfigurationContext(@onNull Context context, @NonNull String methodName)2287 public static void assertConfigurationContext(@NonNull Context context, 2288 @NonNull String methodName) { 2289 if (vmIncorrectContextUseEnabled() && !context.isConfigurationContext()) { 2290 final String errorMessage = "Tried to access the API:" + methodName + " which needs to" 2291 + " have proper configuration from a non-UI Context:" + context; 2292 final String message = "The API:" + methodName + " needs a proper configuration." 2293 + " Use UI contexts such as an activity or a context created" 2294 + " via createWindowContext(Display, int, Bundle) or " 2295 + " createConfigurationContext(Configuration) with a proper configuration."; 2296 final Exception exception = new IllegalAccessException(errorMessage); 2297 StrictMode.onIncorrectContextUsed(message, exception); 2298 Log.e(TAG, errorMessage + " " + message, exception); 2299 } 2300 } 2301 2302 /** 2303 * A helper method to verify if the {@code context} is a UI context and throw 2304 * {@link IncorrectContextUseViolation} if the {@code context} is not a UI context. 2305 * 2306 * @param context The context to verify if it is a UI context 2307 * @param methodName The asserted method name 2308 * 2309 * @see Context#isUiContext() 2310 * @see IncorrectContextUseViolation 2311 * 2312 * @hide 2313 */ assertUiContext(@onNull Context context, @NonNull String methodName)2314 public static void assertUiContext(@NonNull Context context, @NonNull String methodName) { 2315 if (vmIncorrectContextUseEnabled() && !context.isUiContext()) { 2316 final String errorMessage = "Tried to access UI related API:" + methodName 2317 + " from a non-UI Context:" + context; 2318 final String message = methodName + " should be accessed from Activity or other UI " 2319 + "Contexts. Use an Activity or a Context created with " 2320 + "Context#createWindowContext(int, Bundle), which are adjusted to " 2321 + "the configuration and visual bounds of an area on screen."; 2322 final Exception exception = new IllegalAccessException(errorMessage); 2323 StrictMode.onIncorrectContextUsed(message, exception); 2324 Log.e(TAG, errorMessage + " " + message, exception); 2325 } 2326 } 2327 2328 /** @hide */ onUnsafeIntentLaunch(Intent intent)2329 public static void onUnsafeIntentLaunch(Intent intent) { 2330 onVmPolicyViolation(new UnsafeIntentLaunchViolation(intent)); 2331 } 2332 2333 /** Assume locked until we hear otherwise */ 2334 private static volatile boolean sUserKeyUnlocked = false; 2335 isUserKeyUnlocked(int userId)2336 private static boolean isUserKeyUnlocked(int userId) { 2337 final IStorageManager storage = IStorageManager.Stub 2338 .asInterface(ServiceManager.getService("mount")); 2339 if (storage != null) { 2340 try { 2341 return storage.isUserKeyUnlocked(userId); 2342 } catch (RemoteException ignored) { 2343 } 2344 } 2345 return false; 2346 } 2347 2348 /** @hide */ onCredentialProtectedPathAccess(String path, int userId)2349 private static void onCredentialProtectedPathAccess(String path, int userId) { 2350 // We can cache the unlocked state for the userId we're running as, 2351 // since any relocking of that user will always result in our 2352 // process being killed to release any CE FDs we're holding onto. 2353 if (userId == UserHandle.myUserId()) { 2354 if (sUserKeyUnlocked) { 2355 return; 2356 } else if (isUserKeyUnlocked(userId)) { 2357 sUserKeyUnlocked = true; 2358 return; 2359 } 2360 } else if (isUserKeyUnlocked(userId)) { 2361 return; 2362 } 2363 2364 onVmPolicyViolation(new CredentialProtectedWhileLockedViolation( 2365 "Accessed credential protected path " + path + " while user " + userId 2366 + " was locked")); 2367 } 2368 2369 // Map from VM violation fingerprint to uptime millis. 2370 @UnsupportedAppUsage 2371 private static final HashMap<Integer, Long> sLastVmViolationTime = new HashMap<>(); 2372 private static final SparseLongArray sRealLastVmViolationTime = new SparseLongArray(); 2373 2374 /** 2375 * Clamp the given map by removing elements with timestamp older than the given retainSince. 2376 */ clampViolationTimeMap(final @NonNull SparseLongArray violationTime, final long retainSince)2377 private static void clampViolationTimeMap(final @NonNull SparseLongArray violationTime, 2378 final long retainSince) { 2379 for (int i = 0; i < violationTime.size(); ) { 2380 if (violationTime.valueAt(i) < retainSince) { 2381 // Remove stale entries 2382 violationTime.removeAt(i); 2383 } else { 2384 i++; 2385 } 2386 } 2387 // Ideally we'd cap the total size of the map, though it'll involve quickselect of topK, 2388 // seems not worth it (saving some space immediately but they will be obsoleted soon anyway) 2389 } 2390 2391 /** @hide */ onVmPolicyViolation(Violation originStack)2392 public static void onVmPolicyViolation(Violation originStack) { 2393 onVmPolicyViolation(originStack, false); 2394 } 2395 2396 /** @hide */ onVmPolicyViolation(Violation violation, boolean forceDeath)2397 public static void onVmPolicyViolation(Violation violation, boolean forceDeath) { 2398 final boolean penaltyDropbox = (sVmPolicy.mask & PENALTY_DROPBOX) != 0; 2399 final boolean penaltyDeath = ((sVmPolicy.mask & PENALTY_DEATH) != 0) || forceDeath; 2400 final boolean penaltyLog = (sVmPolicy.mask & PENALTY_LOG) != 0; 2401 2402 final int penaltyMask = (sVmPolicy.mask & PENALTY_ALL); 2403 final ViolationInfo info = new ViolationInfo(violation, penaltyMask); 2404 2405 // Erase stuff not relevant for process-wide violations 2406 info.numAnimationsRunning = 0; 2407 info.tags = null; 2408 info.broadcastIntentAction = null; 2409 2410 final Integer fingerprint = info.hashCode(); 2411 final long now = SystemClock.uptimeMillis(); 2412 long lastViolationTime; 2413 long timeSinceLastViolationMillis = Long.MAX_VALUE; 2414 if (sLogger == LOGCAT_LOGGER) { // Don't throttle it if there is a non-default logger 2415 synchronized (sRealLastVmViolationTime) { 2416 if (sRealLastVmViolationTime.indexOfKey(fingerprint) >= 0) { 2417 lastViolationTime = sRealLastVmViolationTime.get(fingerprint); 2418 timeSinceLastViolationMillis = now - lastViolationTime; 2419 } 2420 if (timeSinceLastViolationMillis > MIN_VM_INTERVAL_MS) { 2421 sRealLastVmViolationTime.put(fingerprint, now); 2422 } 2423 clampViolationTimeMap(sRealLastVmViolationTime, 2424 now - Math.max(MIN_VM_INTERVAL_MS, MIN_LOG_INTERVAL_MS)); 2425 } 2426 } 2427 if (timeSinceLastViolationMillis <= MIN_VM_INTERVAL_MS) { 2428 // Rate limit all penalties. 2429 return; 2430 } 2431 2432 if (penaltyLog && sLogger != null && timeSinceLastViolationMillis > MIN_LOG_INTERVAL_MS) { 2433 sLogger.log(info); 2434 } 2435 2436 if (penaltyDropbox) { 2437 if (penaltyDeath) { 2438 handleApplicationStrictModeViolation(PENALTY_DROPBOX, info); 2439 } else { 2440 // Common case for userdebug/eng builds. If no death and 2441 // just dropboxing, we can do the ActivityManager call 2442 // asynchronously. 2443 dropboxViolationAsync(PENALTY_DROPBOX, info); 2444 } 2445 } 2446 2447 if (penaltyDeath) { 2448 System.err.println("StrictMode VmPolicy violation with POLICY_DEATH; shutting down."); 2449 Process.killProcess(Process.myPid()); 2450 System.exit(10); 2451 } 2452 2453 // If penaltyDeath, we can't guarantee this callback finishes before the process dies for 2454 // all executors. penaltyDeath supersedes penaltyCallback. 2455 if (sVmPolicy.mListener != null && sVmPolicy.mCallbackExecutor != null) { 2456 final OnVmViolationListener listener = sVmPolicy.mListener; 2457 try { 2458 sVmPolicy.mCallbackExecutor.execute( 2459 () -> { 2460 // Lift violated policy to prevent infinite recursion. 2461 VmPolicy oldPolicy = allowVmViolations(); 2462 try { 2463 listener.onVmViolation(violation); 2464 } finally { 2465 setVmPolicy(oldPolicy); 2466 } 2467 }); 2468 } catch (RejectedExecutionException e) { 2469 Log.e(TAG, "VmPolicy penaltyCallback failed", e); 2470 } 2471 } 2472 } 2473 2474 /** Called from Parcel.writeNoException() */ writeGatheredViolationsToParcel(Parcel p)2475 /* package */ static void writeGatheredViolationsToParcel(Parcel p) { 2476 ArrayList<ViolationInfo> violations = gatheredViolations.get(); 2477 if (violations == null) { 2478 p.writeInt(0); 2479 } else { 2480 // To avoid taking up too much transaction space, only include 2481 // details for the first 3 violations. Deep inside, CrashInfo 2482 // will truncate each stack trace to ~20kB. 2483 final int size = Math.min(violations.size(), 3); 2484 p.writeInt(size); 2485 for (int i = 0; i < size; i++) { 2486 violations.get(i).writeToParcel(p, 0); 2487 } 2488 } 2489 gatheredViolations.set(null); 2490 } 2491 2492 /** 2493 * Called from Parcel.readException() when the exception is EX_STRICT_MODE_VIOLATIONS, we here 2494 * read back all the encoded violations. 2495 */ readAndHandleBinderCallViolations(Parcel p)2496 /* package */ static void readAndHandleBinderCallViolations(Parcel p) { 2497 Throwable localCallSite = new Throwable(); 2498 final int policyMask = getThreadPolicyMask(); 2499 final boolean currentlyGathering = (policyMask & PENALTY_GATHER) != 0; 2500 2501 final int size = p.readInt(); 2502 for (int i = 0; i < size; i++) { 2503 final ViolationInfo info = new ViolationInfo(p, !currentlyGathering); 2504 info.addLocalStack(localCallSite); 2505 BlockGuard.Policy policy = BlockGuard.getThreadPolicy(); 2506 if (policy instanceof AndroidBlockGuardPolicy) { 2507 ((AndroidBlockGuardPolicy) policy).handleViolationWithTimingAttempt(info); 2508 } 2509 } 2510 } 2511 2512 /** 2513 * Called from android_util_Binder.cpp's android_os_Parcel_enforceInterface when an incoming 2514 * Binder call requires changing the StrictMode policy mask. The role of this function is to ask 2515 * Binder for its current (native) thread-local policy value and synchronize it to libcore's 2516 * (Java) thread-local policy value. 2517 */ 2518 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) onBinderStrictModePolicyChange(@hreadPolicyMask int newPolicy)2519 private static void onBinderStrictModePolicyChange(@ThreadPolicyMask int newPolicy) { 2520 setBlockGuardPolicy(newPolicy); 2521 } 2522 2523 /** 2524 * A tracked, critical time span. (e.g. during an animation.) 2525 * 2526 * <p>The object itself is a linked list node, to avoid any allocations during rapid span 2527 * entries and exits. 2528 * 2529 * @hide 2530 */ 2531 public static class Span { 2532 private String mName; 2533 private long mCreateMillis; 2534 private Span mNext; 2535 private Span mPrev; // not used when in freeList, only active 2536 private final ThreadSpanState mContainerState; 2537 Span(ThreadSpanState threadState)2538 Span(ThreadSpanState threadState) { 2539 mContainerState = threadState; 2540 } 2541 2542 // Empty constructor for the NO_OP_SPAN Span()2543 protected Span() { 2544 mContainerState = null; 2545 } 2546 2547 /** 2548 * To be called when the critical span is complete (i.e. the animation is done animating). 2549 * This can be called on any thread (even a different one from where the animation was 2550 * taking place), but that's only a defensive implementation measure. It really makes no 2551 * sense for you to call this on thread other than that where you created it. 2552 * 2553 * @hide 2554 */ 2555 @UnsupportedAppUsage finish()2556 public void finish() { 2557 ThreadSpanState state = mContainerState; 2558 synchronized (state) { 2559 if (mName == null) { 2560 // Duplicate finish call. Ignore. 2561 return; 2562 } 2563 2564 // Remove ourselves from the active list. 2565 if (mPrev != null) { 2566 mPrev.mNext = mNext; 2567 } 2568 if (mNext != null) { 2569 mNext.mPrev = mPrev; 2570 } 2571 if (state.mActiveHead == this) { 2572 state.mActiveHead = mNext; 2573 } 2574 2575 state.mActiveSize--; 2576 2577 if (LOG_V) Log.d(TAG, "Span finished=" + mName + "; size=" + state.mActiveSize); 2578 2579 this.mCreateMillis = -1; 2580 this.mName = null; 2581 this.mPrev = null; 2582 this.mNext = null; 2583 2584 // Add ourselves to the freeList, if it's not already 2585 // too big. 2586 if (state.mFreeListSize < 5) { 2587 this.mNext = state.mFreeListHead; 2588 state.mFreeListHead = this; 2589 state.mFreeListSize++; 2590 } 2591 } 2592 } 2593 } 2594 2595 // The no-op span that's used in user builds. 2596 private static final Span NO_OP_SPAN = 2597 new Span() { 2598 public void finish() { 2599 // Do nothing. 2600 } 2601 }; 2602 2603 /** 2604 * Linked lists of active spans and a freelist. 2605 * 2606 * <p>Locking notes: there's one of these structures per thread and all members of this 2607 * structure (as well as the Span nodes under it) are guarded by the ThreadSpanState object 2608 * instance. While in theory there'd be no locking required because it's all local per-thread, 2609 * the finish() method above is defensive against people calling it on a different thread from 2610 * where they created the Span, hence the locking. 2611 */ 2612 private static class ThreadSpanState { 2613 public Span mActiveHead; // doubly-linked list. 2614 public int mActiveSize; 2615 public Span mFreeListHead; // singly-linked list. only changes at head. 2616 public int mFreeListSize; 2617 } 2618 2619 private static final ThreadLocal<ThreadSpanState> sThisThreadSpanState = 2620 new ThreadLocal<ThreadSpanState>() { 2621 @Override 2622 protected ThreadSpanState initialValue() { 2623 return new ThreadSpanState(); 2624 } 2625 }; 2626 2627 @UnsupportedAppUsage 2628 private static Singleton<IWindowManager> sWindowManager = 2629 new Singleton<IWindowManager>() { 2630 protected IWindowManager create() { 2631 return IWindowManager.Stub.asInterface(ServiceManager.getService("window")); 2632 } 2633 }; 2634 2635 /** 2636 * Enter a named critical span (e.g. an animation) 2637 * 2638 * <p>The name is an arbitary label (or tag) that will be applied to any strictmode violation 2639 * that happens while this span is active. You must call finish() on the span when done. 2640 * 2641 * <p>This will never return null, but on devices without debugging enabled, this may return a 2642 * placeholder object on which the finish() method is a no-op. 2643 * 2644 * <p>TODO: add CloseGuard to this, verifying callers call finish. 2645 * 2646 * @hide 2647 */ 2648 @UnsupportedAppUsage enterCriticalSpan(String name)2649 public static Span enterCriticalSpan(String name) { 2650 if (Build.IS_USER) { 2651 return NO_OP_SPAN; 2652 } 2653 if (name == null || name.isEmpty()) { 2654 throw new IllegalArgumentException("name must be non-null and non-empty"); 2655 } 2656 ThreadSpanState state = sThisThreadSpanState.get(); 2657 Span span = null; 2658 synchronized (state) { 2659 if (state.mFreeListHead != null) { 2660 span = state.mFreeListHead; 2661 state.mFreeListHead = span.mNext; 2662 state.mFreeListSize--; 2663 } else { 2664 // Shouldn't have to do this often. 2665 span = new Span(state); 2666 } 2667 span.mName = name; 2668 span.mCreateMillis = SystemClock.uptimeMillis(); 2669 span.mNext = state.mActiveHead; 2670 span.mPrev = null; 2671 state.mActiveHead = span; 2672 state.mActiveSize++; 2673 if (span.mNext != null) { 2674 span.mNext.mPrev = span; 2675 } 2676 if (LOG_V) Log.d(TAG, "Span enter=" + name + "; size=" + state.mActiveSize); 2677 } 2678 return span; 2679 } 2680 2681 /** 2682 * For code to note that it's slow. This is a no-op unless the current thread's {@link 2683 * android.os.StrictMode.ThreadPolicy} has {@link 2684 * android.os.StrictMode.ThreadPolicy.Builder#detectCustomSlowCalls} enabled. 2685 * 2686 * @param name a short string for the exception stack trace that's built if when this fires. 2687 */ noteSlowCall(String name)2688 public static void noteSlowCall(String name) { 2689 BlockGuard.Policy policy = BlockGuard.getThreadPolicy(); 2690 if (!(policy instanceof AndroidBlockGuardPolicy)) { 2691 // StrictMode not enabled. 2692 return; 2693 } 2694 ((AndroidBlockGuardPolicy) policy).onCustomSlowCall(name); 2695 } 2696 2697 /** 2698 * For code to note that a resource was obtained using a type other than its defined type. This 2699 * is a no-op unless the current thread's {@link android.os.StrictMode.ThreadPolicy} has {@link 2700 * android.os.StrictMode.ThreadPolicy.Builder#detectResourceMismatches()} enabled. 2701 * 2702 * @param tag an object for the exception stack trace that's built if when this fires. 2703 * @hide 2704 */ noteResourceMismatch(Object tag)2705 public static void noteResourceMismatch(Object tag) { 2706 BlockGuard.Policy policy = BlockGuard.getThreadPolicy(); 2707 if (!(policy instanceof AndroidBlockGuardPolicy)) { 2708 // StrictMode not enabled. 2709 return; 2710 } 2711 ((AndroidBlockGuardPolicy) policy).onResourceMismatch(tag); 2712 } 2713 2714 /** @hide */ noteUnbufferedIO()2715 public static void noteUnbufferedIO() { 2716 BlockGuard.Policy policy = BlockGuard.getThreadPolicy(); 2717 if (!(policy instanceof AndroidBlockGuardPolicy)) { 2718 // StrictMode not enabled. 2719 return; 2720 } 2721 policy.onUnbufferedIO(); 2722 } 2723 2724 /** @hide */ noteDiskRead()2725 public static void noteDiskRead() { 2726 BlockGuard.Policy policy = BlockGuard.getThreadPolicy(); 2727 if (!(policy instanceof AndroidBlockGuardPolicy)) { 2728 // StrictMode not enabled. 2729 return; 2730 } 2731 policy.onReadFromDisk(); 2732 } 2733 2734 /** @hide */ noteDiskWrite()2735 public static void noteDiskWrite() { 2736 BlockGuard.Policy policy = BlockGuard.getThreadPolicy(); 2737 if (!(policy instanceof AndroidBlockGuardPolicy)) { 2738 // StrictMode not enabled. 2739 return; 2740 } 2741 policy.onWriteToDisk(); 2742 } 2743 2744 @GuardedBy("StrictMode.class") 2745 private static final HashMap<Class, Integer> sExpectedActivityInstanceCount = new HashMap<>(); 2746 2747 /** 2748 * Returns an object that is used to track instances of activites. The activity should store a 2749 * reference to the tracker object in one of its fields. 2750 * 2751 * @hide 2752 */ trackActivity(Object instance)2753 public static Object trackActivity(Object instance) { 2754 return new InstanceTracker(instance); 2755 } 2756 2757 /** @hide */ 2758 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) incrementExpectedActivityCount(Class klass)2759 public static void incrementExpectedActivityCount(Class klass) { 2760 if (klass == null) { 2761 return; 2762 } 2763 2764 synchronized (StrictMode.class) { 2765 if ((sVmPolicy.mask & DETECT_VM_ACTIVITY_LEAKS) == 0) { 2766 return; 2767 } 2768 2769 // Use the instance count from InstanceTracker as initial value. 2770 Integer expected = sExpectedActivityInstanceCount.get(klass); 2771 Integer newExpected = 2772 expected == null ? InstanceTracker.getInstanceCount(klass) + 1 : expected + 1; 2773 sExpectedActivityInstanceCount.put(klass, newExpected); 2774 } 2775 } 2776 2777 /** @hide */ decrementExpectedActivityCount(Class klass)2778 public static void decrementExpectedActivityCount(Class klass) { 2779 if (klass == null) { 2780 return; 2781 } 2782 2783 final int limit; 2784 synchronized (StrictMode.class) { 2785 if ((sVmPolicy.mask & DETECT_VM_ACTIVITY_LEAKS) == 0) { 2786 return; 2787 } 2788 2789 Integer expected = sExpectedActivityInstanceCount.get(klass); 2790 int newExpected = (expected == null || expected == 0) ? 0 : expected - 1; 2791 if (newExpected == 0) { 2792 sExpectedActivityInstanceCount.remove(klass); 2793 } else { 2794 sExpectedActivityInstanceCount.put(klass, newExpected); 2795 } 2796 2797 // Note: adding 1 here to give some breathing room during 2798 // orientation changes. (shouldn't be necessary, though?) 2799 limit = newExpected + 1; 2800 } 2801 2802 // Quick check. 2803 int actual = InstanceTracker.getInstanceCount(klass); 2804 if (actual <= limit) { 2805 return; 2806 } 2807 2808 // Do a GC and explicit count to double-check. 2809 // This is the work that we are trying to avoid by tracking the object instances 2810 // explicity. Running an explicit GC can be expensive (80ms) and so can walking 2811 // the heap to count instance (30ms). This extra work can make the system feel 2812 // noticeably less responsive during orientation changes when activities are 2813 // being restarted. Granted, it is only a problem when StrictMode is enabled 2814 // but it is annoying. 2815 2816 System.gc(); 2817 System.runFinalization(); 2818 System.gc(); 2819 2820 long instances = VMDebug.countInstancesOfClass(klass, false); 2821 if (instances > limit) { 2822 onVmPolicyViolation(new InstanceCountViolation(klass, instances, limit)); 2823 } 2824 } 2825 2826 /** 2827 * Parcelable that gets sent in Binder call headers back to callers to report violations that 2828 * happened during a cross-process call. 2829 * 2830 * @hide 2831 */ 2832 @TestApi 2833 public static final class ViolationInfo implements Parcelable { 2834 /** Stack and violation details. */ 2835 private final Violation mViolation; 2836 2837 /** Path leading to a violation that occurred across binder. */ 2838 private final Deque<StackTraceElement[]> mBinderStack = new ArrayDeque<>(); 2839 2840 /** Memoized stack trace of full violation. */ 2841 @Nullable private String mStackTrace; 2842 2843 /** The strict mode penalty mask at the time of violation. */ 2844 private final int mPenaltyMask; 2845 2846 /** The wall time duration of the violation, when known. -1 when not known. */ 2847 public int durationMillis = -1; 2848 2849 /** The number of animations currently running. */ 2850 public int numAnimationsRunning = 0; 2851 2852 /** List of tags from active Span instances during this violation, or null for none. */ 2853 public String[] tags; 2854 2855 /** 2856 * Which violation number this was (1-based) since the last Looper loop, from the 2857 * perspective of the root caller (if it crossed any processes via Binder calls). The value 2858 * is 0 if the root caller wasn't on a Looper thread. 2859 */ 2860 public int violationNumThisLoop; 2861 2862 /** The time (in terms of SystemClock.uptimeMillis()) that the violation occurred. */ 2863 public long violationUptimeMillis; 2864 2865 /** 2866 * The action of the Intent being broadcast to somebody's onReceive on this thread right 2867 * now, or null. 2868 */ 2869 public String broadcastIntentAction; 2870 2871 /** If this is a instance count violation, the number of instances in memory, else -1. */ 2872 public long numInstances = -1; 2873 2874 /** Create an instance of ViolationInfo initialized from an exception. */ ViolationInfo(Violation tr, int penaltyMask)2875 ViolationInfo(Violation tr, int penaltyMask) { 2876 this.mViolation = tr; 2877 this.mPenaltyMask = penaltyMask; 2878 violationUptimeMillis = SystemClock.uptimeMillis(); 2879 this.numAnimationsRunning = ValueAnimator.getCurrentAnimationsCount(); 2880 Intent broadcastIntent = ActivityThread.getIntentBeingBroadcast(); 2881 if (broadcastIntent != null) { 2882 broadcastIntentAction = broadcastIntent.getAction(); 2883 } 2884 ThreadSpanState state = sThisThreadSpanState.get(); 2885 if (tr instanceof InstanceCountViolation) { 2886 this.numInstances = ((InstanceCountViolation) tr).getNumberOfInstances(); 2887 } 2888 synchronized (state) { 2889 int spanActiveCount = state.mActiveSize; 2890 if (spanActiveCount > MAX_SPAN_TAGS) { 2891 spanActiveCount = MAX_SPAN_TAGS; 2892 } 2893 if (spanActiveCount != 0) { 2894 this.tags = new String[spanActiveCount]; 2895 Span iter = state.mActiveHead; 2896 int index = 0; 2897 while (iter != null && index < spanActiveCount) { 2898 this.tags[index] = iter.mName; 2899 index++; 2900 iter = iter.mNext; 2901 } 2902 } 2903 } 2904 } 2905 2906 /** 2907 * Equivalent output to 2908 * {@link android.app.ApplicationErrorReport.CrashInfo#stackTrace}. 2909 */ getStackTrace()2910 public String getStackTrace() { 2911 if (mStackTrace == null) { 2912 StringWriter sw = new StringWriter(); 2913 PrintWriter pw = new FastPrintWriter(sw, false, 256); 2914 mViolation.printStackTrace(pw); 2915 for (StackTraceElement[] traces : mBinderStack) { 2916 pw.append("# via Binder call with stack:\n"); 2917 for (StackTraceElement traceElement : traces) { 2918 pw.append("\tat "); 2919 pw.append(traceElement.toString()); 2920 pw.append('\n'); 2921 } 2922 } 2923 pw.flush(); 2924 pw.close(); 2925 mStackTrace = sw.toString(); 2926 } 2927 return mStackTrace; 2928 } 2929 getViolationClass()2930 public Class<? extends Violation> getViolationClass() { 2931 return mViolation.getClass(); 2932 } 2933 2934 /** 2935 * Optional message describing this violation. 2936 * 2937 * @hide 2938 */ 2939 @TestApi getViolationDetails()2940 public String getViolationDetails() { 2941 return mViolation.getMessage(); 2942 } 2943 penaltyEnabled(int p)2944 boolean penaltyEnabled(int p) { 2945 return (mPenaltyMask & p) != 0; 2946 } 2947 2948 /** 2949 * Add a {@link Throwable} from the current process that caused the underlying violation. We 2950 * only preserve the stack trace elements. 2951 * 2952 * @hide 2953 */ addLocalStack(Throwable t)2954 void addLocalStack(Throwable t) { 2955 mBinderStack.addFirst(t.getStackTrace()); 2956 } 2957 2958 @Override hashCode()2959 public int hashCode() { 2960 int result = 17; 2961 if (mViolation != null) { 2962 result = 37 * result + mViolation.hashCode(); 2963 } 2964 if (numAnimationsRunning != 0) { 2965 result *= 37; 2966 } 2967 if (broadcastIntentAction != null) { 2968 result = 37 * result + broadcastIntentAction.hashCode(); 2969 } 2970 if (tags != null) { 2971 for (String tag : tags) { 2972 result = 37 * result + tag.hashCode(); 2973 } 2974 } 2975 return result; 2976 } 2977 2978 /** Create an instance of ViolationInfo initialized from a Parcel. */ 2979 @UnsupportedAppUsage ViolationInfo(Parcel in)2980 public ViolationInfo(Parcel in) { 2981 this(in, false); 2982 } 2983 2984 /** 2985 * Create an instance of ViolationInfo initialized from a Parcel. 2986 * 2987 * @param unsetGatheringBit if true, the caller is the root caller and the gathering penalty 2988 * should be removed. 2989 */ ViolationInfo(Parcel in, boolean unsetGatheringBit)2990 public ViolationInfo(Parcel in, boolean unsetGatheringBit) { 2991 mViolation = (Violation) in.readSerializable(); 2992 int binderStackSize = in.readInt(); 2993 for (int i = 0; i < binderStackSize; i++) { 2994 StackTraceElement[] traceElements = new StackTraceElement[in.readInt()]; 2995 for (int j = 0; j < traceElements.length; j++) { 2996 StackTraceElement element = 2997 new StackTraceElement( 2998 in.readString(), 2999 in.readString(), 3000 in.readString(), 3001 in.readInt()); 3002 traceElements[j] = element; 3003 } 3004 mBinderStack.add(traceElements); 3005 } 3006 int rawPenaltyMask = in.readInt(); 3007 if (unsetGatheringBit) { 3008 mPenaltyMask = rawPenaltyMask & ~PENALTY_GATHER; 3009 } else { 3010 mPenaltyMask = rawPenaltyMask; 3011 } 3012 durationMillis = in.readInt(); 3013 violationNumThisLoop = in.readInt(); 3014 numAnimationsRunning = in.readInt(); 3015 violationUptimeMillis = in.readLong(); 3016 numInstances = in.readLong(); 3017 broadcastIntentAction = in.readString(); 3018 tags = in.readStringArray(); 3019 } 3020 3021 /** Save a ViolationInfo instance to a parcel. */ 3022 @Override writeToParcel(Parcel dest, int flags)3023 public void writeToParcel(Parcel dest, int flags) { 3024 dest.writeSerializable(mViolation); 3025 dest.writeInt(mBinderStack.size()); 3026 for (StackTraceElement[] traceElements : mBinderStack) { 3027 dest.writeInt(traceElements.length); 3028 for (StackTraceElement element : traceElements) { 3029 dest.writeString(element.getClassName()); 3030 dest.writeString(element.getMethodName()); 3031 dest.writeString(element.getFileName()); 3032 dest.writeInt(element.getLineNumber()); 3033 } 3034 } 3035 int start = dest.dataPosition(); 3036 dest.writeInt(mPenaltyMask); 3037 dest.writeInt(durationMillis); 3038 dest.writeInt(violationNumThisLoop); 3039 dest.writeInt(numAnimationsRunning); 3040 dest.writeLong(violationUptimeMillis); 3041 dest.writeLong(numInstances); 3042 dest.writeString(broadcastIntentAction); 3043 dest.writeStringArray(tags); 3044 int total = dest.dataPosition() - start; 3045 if (Binder.CHECK_PARCEL_SIZE && total > 10 * 1024) { 3046 Slog.d( 3047 TAG, 3048 "VIO: penalty=" 3049 + mPenaltyMask 3050 + " dur=" 3051 + durationMillis 3052 + " numLoop=" 3053 + violationNumThisLoop 3054 + " anim=" 3055 + numAnimationsRunning 3056 + " uptime=" 3057 + violationUptimeMillis 3058 + " numInst=" 3059 + numInstances); 3060 Slog.d(TAG, "VIO: action=" + broadcastIntentAction); 3061 Slog.d(TAG, "VIO: tags=" + Arrays.toString(tags)); 3062 Slog.d(TAG, "VIO: TOTAL BYTES WRITTEN: " + (dest.dataPosition() - start)); 3063 } 3064 } 3065 3066 /** Dump a ViolationInfo instance to a Printer. */ dump(Printer pw, String prefix)3067 public void dump(Printer pw, String prefix) { 3068 pw.println(prefix + "stackTrace: " + getStackTrace()); 3069 pw.println(prefix + "penalty: " + mPenaltyMask); 3070 if (durationMillis != -1) { 3071 pw.println(prefix + "durationMillis: " + durationMillis); 3072 } 3073 if (numInstances != -1) { 3074 pw.println(prefix + "numInstances: " + numInstances); 3075 } 3076 if (violationNumThisLoop != 0) { 3077 pw.println(prefix + "violationNumThisLoop: " + violationNumThisLoop); 3078 } 3079 if (numAnimationsRunning != 0) { 3080 pw.println(prefix + "numAnimationsRunning: " + numAnimationsRunning); 3081 } 3082 pw.println(prefix + "violationUptimeMillis: " + violationUptimeMillis); 3083 if (broadcastIntentAction != null) { 3084 pw.println(prefix + "broadcastIntentAction: " + broadcastIntentAction); 3085 } 3086 if (tags != null) { 3087 int index = 0; 3088 for (String tag : tags) { 3089 pw.println(prefix + "tag[" + (index++) + "]: " + tag); 3090 } 3091 } 3092 } 3093 3094 @Override describeContents()3095 public int describeContents() { 3096 return 0; 3097 } 3098 3099 public static final @android.annotation.NonNull Parcelable.Creator<ViolationInfo> CREATOR = 3100 new Parcelable.Creator<ViolationInfo>() { 3101 @Override 3102 public ViolationInfo createFromParcel(Parcel in) { 3103 return new ViolationInfo(in); 3104 } 3105 3106 @Override 3107 public ViolationInfo[] newArray(int size) { 3108 return new ViolationInfo[size]; 3109 } 3110 }; 3111 } 3112 3113 private static final class InstanceTracker { 3114 private static final HashMap<Class<?>, Integer> sInstanceCounts = 3115 new HashMap<Class<?>, Integer>(); 3116 3117 private final Class<?> mKlass; 3118 InstanceTracker(Object instance)3119 public InstanceTracker(Object instance) { 3120 mKlass = instance.getClass(); 3121 3122 synchronized (sInstanceCounts) { 3123 final Integer value = sInstanceCounts.get(mKlass); 3124 final int newValue = value != null ? value + 1 : 1; 3125 sInstanceCounts.put(mKlass, newValue); 3126 } 3127 } 3128 3129 @Override finalize()3130 protected void finalize() throws Throwable { 3131 try { 3132 synchronized (sInstanceCounts) { 3133 final Integer value = sInstanceCounts.get(mKlass); 3134 if (value != null) { 3135 final int newValue = value - 1; 3136 if (newValue > 0) { 3137 sInstanceCounts.put(mKlass, newValue); 3138 } else { 3139 sInstanceCounts.remove(mKlass); 3140 } 3141 } 3142 } 3143 } finally { 3144 super.finalize(); 3145 } 3146 } 3147 getInstanceCount(Class<?> klass)3148 public static int getInstanceCount(Class<?> klass) { 3149 synchronized (sInstanceCounts) { 3150 final Integer value = sInstanceCounts.get(klass); 3151 return value != null ? value : 0; 3152 } 3153 } 3154 } 3155 } 3156