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