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