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.annotation.UnsupportedAppUsage; 24 import android.app.ActivityManager; 25 import android.app.ActivityThread; 26 import android.app.IActivityManager; 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#createCredentialProtectedStorageContext() 1019 * @see Context#createDeviceProtectedStorageContext() 1020 */ detectCredentialProtectedWhileLocked()1021 public @NonNull Builder detectCredentialProtectedWhileLocked() { 1022 return enable(DETECT_VM_CREDENTIAL_PROTECTED_WHILE_LOCKED); 1023 } 1024 1025 /** @hide */ permitCredentialProtectedWhileLocked()1026 public @NonNull Builder permitCredentialProtectedWhileLocked() { 1027 return disable(DETECT_VM_CREDENTIAL_PROTECTED_WHILE_LOCKED); 1028 } 1029 1030 /** 1031 * Crashes the whole process on violation. This penalty runs at the end of all enabled 1032 * penalties so you'll still get your logging or other violations before the process 1033 * dies. 1034 */ penaltyDeath()1035 public @NonNull Builder penaltyDeath() { 1036 return enable(PENALTY_DEATH); 1037 } 1038 1039 /** 1040 * Crashes the whole process when cleartext network traffic is detected. 1041 * 1042 * @see #detectCleartextNetwork() 1043 */ penaltyDeathOnCleartextNetwork()1044 public @NonNull Builder penaltyDeathOnCleartextNetwork() { 1045 return enable(PENALTY_DEATH_ON_CLEARTEXT_NETWORK); 1046 } 1047 1048 /** 1049 * Crashes the whole process when a {@code file://} {@link android.net.Uri} is exposed 1050 * beyond this app. 1051 * 1052 * @see #detectFileUriExposure() 1053 */ penaltyDeathOnFileUriExposure()1054 public @NonNull Builder penaltyDeathOnFileUriExposure() { 1055 return enable(PENALTY_DEATH_ON_FILE_URI_EXPOSURE); 1056 } 1057 1058 /** Log detected violations to the system log. */ penaltyLog()1059 public @NonNull Builder penaltyLog() { 1060 return enable(PENALTY_LOG); 1061 } 1062 1063 /** 1064 * Enable detected violations log a stacktrace and timing data to the {@link 1065 * android.os.DropBoxManager DropBox} on policy violation. Intended mostly for platform 1066 * integrators doing beta user field data collection. 1067 */ penaltyDropBox()1068 public @NonNull Builder penaltyDropBox() { 1069 return enable(PENALTY_DROPBOX); 1070 } 1071 1072 /** 1073 * Call #{@link OnVmViolationListener#onVmViolation(Violation)} on every violation. 1074 */ penaltyListener( @onNull Executor executor, @NonNull OnVmViolationListener listener)1075 public @NonNull Builder penaltyListener( 1076 @NonNull Executor executor, @NonNull OnVmViolationListener listener) { 1077 if (executor == null) { 1078 throw new NullPointerException("executor must not be null"); 1079 } 1080 mListener = listener; 1081 mExecutor = executor; 1082 return this; 1083 } 1084 1085 /** @removed */ penaltyListener( @onNull OnVmViolationListener listener, @NonNull Executor executor)1086 public @NonNull Builder penaltyListener( 1087 @NonNull OnVmViolationListener listener, @NonNull Executor executor) { 1088 return penaltyListener(executor, listener); 1089 } 1090 enable(@mPolicyMask int mask)1091 private Builder enable(@VmPolicyMask int mask) { 1092 mMask |= mask; 1093 return this; 1094 } 1095 disable(@mPolicyMask int mask)1096 Builder disable(@VmPolicyMask int mask) { 1097 mMask &= ~mask; 1098 return this; 1099 } 1100 1101 /** 1102 * Construct the VmPolicy instance. 1103 * 1104 * <p>Note: if no penalties are enabled before calling <code>build</code>, {@link 1105 * #penaltyLog} is implicitly set. 1106 */ build()1107 public VmPolicy build() { 1108 // If there are detection bits set but no violation bits 1109 // set, enable simple logging. 1110 if (mListener == null 1111 && mMask != 0 1112 && (mMask 1113 & (PENALTY_DEATH 1114 | PENALTY_LOG 1115 | PENALTY_DROPBOX 1116 | PENALTY_DIALOG)) 1117 == 0) { 1118 penaltyLog(); 1119 } 1120 return new VmPolicy( 1121 mMask, 1122 mClassInstanceLimit != null ? mClassInstanceLimit : EMPTY_CLASS_LIMIT_MAP, 1123 mListener, 1124 mExecutor); 1125 } 1126 } 1127 } 1128 1129 /** 1130 * Log of strict mode violation stack traces that have occurred during a Binder call, to be 1131 * serialized back later to the caller via Parcel.writeNoException() (amusingly) where the 1132 * caller can choose how to react. 1133 */ 1134 private static final ThreadLocal<ArrayList<ViolationInfo>> gatheredViolations = 1135 new ThreadLocal<ArrayList<ViolationInfo>>() { 1136 @Override 1137 protected ArrayList<ViolationInfo> initialValue() { 1138 // Starts null to avoid unnecessary allocations when 1139 // checking whether there are any violations or not in 1140 // hasGatheredViolations() below. 1141 return null; 1142 } 1143 }; 1144 1145 /** 1146 * Sets the policy for what actions on the current thread should be detected, as well as the 1147 * penalty if such actions occur. 1148 * 1149 * <p>Internally this sets a thread-local variable which is propagated across cross-process IPC 1150 * calls, meaning you can catch violations when a system service or another process accesses the 1151 * disk or network on your behalf. 1152 * 1153 * @param policy the policy to put into place 1154 */ setThreadPolicy(final ThreadPolicy policy)1155 public static void setThreadPolicy(final ThreadPolicy policy) { 1156 setThreadPolicyMask(policy.mask); 1157 sThreadViolationListener.set(policy.mListener); 1158 sThreadViolationExecutor.set(policy.mCallbackExecutor); 1159 } 1160 1161 /** @hide */ setThreadPolicyMask(@hreadPolicyMask int threadPolicyMask)1162 public static void setThreadPolicyMask(@ThreadPolicyMask int threadPolicyMask) { 1163 // In addition to the Java-level thread-local in Dalvik's 1164 // BlockGuard, we also need to keep a native thread-local in 1165 // Binder in order to propagate the value across Binder calls, 1166 // even across native-only processes. The two are kept in 1167 // sync via the callback to onStrictModePolicyChange, below. 1168 setBlockGuardPolicy(threadPolicyMask); 1169 1170 // And set the Android native version... 1171 Binder.setThreadStrictModePolicy(threadPolicyMask); 1172 } 1173 1174 // Sets the policy in Dalvik/libcore (BlockGuard) setBlockGuardPolicy(@hreadPolicyMask int threadPolicyMask)1175 private static void setBlockGuardPolicy(@ThreadPolicyMask int threadPolicyMask) { 1176 if (threadPolicyMask == 0) { 1177 BlockGuard.setThreadPolicy(BlockGuard.LAX_POLICY); 1178 return; 1179 } 1180 final BlockGuard.Policy policy = BlockGuard.getThreadPolicy(); 1181 final AndroidBlockGuardPolicy androidPolicy; 1182 if (policy instanceof AndroidBlockGuardPolicy) { 1183 androidPolicy = (AndroidBlockGuardPolicy) policy; 1184 } else { 1185 androidPolicy = THREAD_ANDROID_POLICY.get(); 1186 BlockGuard.setThreadPolicy(androidPolicy); 1187 } 1188 androidPolicy.setThreadPolicyMask(threadPolicyMask); 1189 } 1190 setBlockGuardVmPolicy(@mPolicyMask int vmPolicyMask)1191 private static void setBlockGuardVmPolicy(@VmPolicyMask int vmPolicyMask) { 1192 // We only need to install BlockGuard for a small subset of VM policies 1193 vmPolicyMask &= DETECT_VM_CREDENTIAL_PROTECTED_WHILE_LOCKED; 1194 if (vmPolicyMask != 0) { 1195 BlockGuard.setVmPolicy(VM_ANDROID_POLICY); 1196 } else { 1197 BlockGuard.setVmPolicy(BlockGuard.LAX_VM_POLICY); 1198 } 1199 } 1200 1201 // Sets up CloseGuard in Dalvik/libcore setCloseGuardEnabled(boolean enabled)1202 private static void setCloseGuardEnabled(boolean enabled) { 1203 if (!(CloseGuard.getReporter() instanceof AndroidCloseGuardReporter)) { 1204 CloseGuard.setReporter(new AndroidCloseGuardReporter()); 1205 } 1206 CloseGuard.setEnabled(enabled); 1207 } 1208 1209 /** 1210 * Returns the bitmask of the current thread's policy. 1211 * 1212 * @return the bitmask of all the DETECT_* and PENALTY_* bits currently enabled 1213 * @hide 1214 */ 1215 @UnsupportedAppUsage getThreadPolicyMask()1216 public static @ThreadPolicyMask int getThreadPolicyMask() { 1217 final BlockGuard.Policy policy = BlockGuard.getThreadPolicy(); 1218 if (policy instanceof AndroidBlockGuardPolicy) { 1219 return ((AndroidBlockGuardPolicy) policy).getThreadPolicyMask(); 1220 } else { 1221 return 0; 1222 } 1223 } 1224 1225 /** Returns the current thread's policy. */ getThreadPolicy()1226 public static ThreadPolicy getThreadPolicy() { 1227 // TODO: this was a last minute Gingerbread API change (to 1228 // introduce VmPolicy cleanly) but this isn't particularly 1229 // optimal for users who might call this method often. This 1230 // should be in a thread-local and not allocate on each call. 1231 return new ThreadPolicy( 1232 getThreadPolicyMask(), 1233 sThreadViolationListener.get(), 1234 sThreadViolationExecutor.get()); 1235 } 1236 1237 /** 1238 * A convenience wrapper that takes the current {@link ThreadPolicy} from {@link 1239 * #getThreadPolicy}, modifies it to permit both disk reads & writes, and sets the new 1240 * policy with {@link #setThreadPolicy}, returning the old policy so you can restore it at the 1241 * end of a block. 1242 * 1243 * @return the old policy, to be passed to {@link #setThreadPolicy} to restore the policy at the 1244 * end of a block 1245 */ allowThreadDiskWrites()1246 public static ThreadPolicy allowThreadDiskWrites() { 1247 return new ThreadPolicy( 1248 allowThreadDiskWritesMask(), 1249 sThreadViolationListener.get(), 1250 sThreadViolationExecutor.get()); 1251 } 1252 1253 /** @hide */ allowThreadDiskWritesMask()1254 public static @ThreadPolicyMask int allowThreadDiskWritesMask() { 1255 int oldPolicyMask = getThreadPolicyMask(); 1256 int newPolicyMask = oldPolicyMask & ~(DETECT_THREAD_DISK_WRITE | DETECT_THREAD_DISK_READ); 1257 if (newPolicyMask != oldPolicyMask) { 1258 setThreadPolicyMask(newPolicyMask); 1259 } 1260 return oldPolicyMask; 1261 } 1262 1263 /** 1264 * A convenience wrapper that takes the current {@link ThreadPolicy} from {@link 1265 * #getThreadPolicy}, modifies it to permit disk reads, and sets the new policy with {@link 1266 * #setThreadPolicy}, returning the old policy so you can restore it at the end of a block. 1267 * 1268 * @return the old policy, to be passed to setThreadPolicy to restore the policy. 1269 */ allowThreadDiskReads()1270 public static ThreadPolicy allowThreadDiskReads() { 1271 return new ThreadPolicy( 1272 allowThreadDiskReadsMask(), 1273 sThreadViolationListener.get(), 1274 sThreadViolationExecutor.get()); 1275 } 1276 1277 /** @hide */ allowThreadDiskReadsMask()1278 public static @ThreadPolicyMask int allowThreadDiskReadsMask() { 1279 int oldPolicyMask = getThreadPolicyMask(); 1280 int newPolicyMask = oldPolicyMask & ~(DETECT_THREAD_DISK_READ); 1281 if (newPolicyMask != oldPolicyMask) { 1282 setThreadPolicyMask(newPolicyMask); 1283 } 1284 return oldPolicyMask; 1285 } 1286 1287 /** @hide */ allowThreadViolations()1288 public static ThreadPolicy allowThreadViolations() { 1289 ThreadPolicy oldPolicy = getThreadPolicy(); 1290 setThreadPolicyMask(0); 1291 return oldPolicy; 1292 } 1293 1294 /** @hide */ allowVmViolations()1295 public static VmPolicy allowVmViolations() { 1296 VmPolicy oldPolicy = getVmPolicy(); 1297 sVmPolicy = VmPolicy.LAX; 1298 return oldPolicy; 1299 } 1300 1301 /** 1302 * Determine if the given app is "bundled" as part of the system image. These bundled apps are 1303 * developed in lock-step with the OS, and they aren't updated outside of an OTA, so we want to 1304 * chase any {@link StrictMode} regressions by enabling detection when running on {@link 1305 * Build#IS_USERDEBUG} or {@link Build#IS_ENG} builds. 1306 * 1307 * <p>Unbundled apps included in the system image are expected to detect and triage their own 1308 * {@link StrictMode} issues separate from the OS release process, which is why we don't enable 1309 * them here. 1310 * 1311 * @hide 1312 */ isBundledSystemApp(ApplicationInfo ai)1313 public static boolean isBundledSystemApp(ApplicationInfo ai) { 1314 if (ai == null || ai.packageName == null) { 1315 // Probably system server 1316 return true; 1317 } else if (ai.isSystemApp()) { 1318 // Ignore unbundled apps living in the wrong namespace 1319 if (ai.packageName.equals("com.android.vending") 1320 || ai.packageName.equals("com.android.chrome")) { 1321 return false; 1322 } 1323 1324 // Ignore bundled apps that are way too spammy 1325 // STOPSHIP: burn this list down to zero 1326 if (ai.packageName.equals("com.android.phone")) { 1327 return false; 1328 } 1329 1330 if (ai.packageName.equals("android") 1331 || ai.packageName.startsWith("android.") 1332 || ai.packageName.startsWith("com.android.")) { 1333 return true; 1334 } 1335 } 1336 return false; 1337 } 1338 1339 /** 1340 * Initialize default {@link ThreadPolicy} for the current thread. 1341 * 1342 * @hide 1343 */ initThreadDefaults(ApplicationInfo ai)1344 public static void initThreadDefaults(ApplicationInfo ai) { 1345 final ThreadPolicy.Builder builder = new ThreadPolicy.Builder(); 1346 final int targetSdkVersion = 1347 (ai != null) ? ai.targetSdkVersion : Build.VERSION_CODES.CUR_DEVELOPMENT; 1348 1349 // Starting in HC, we don't allow network usage on the main thread 1350 if (targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB) { 1351 builder.detectNetwork(); 1352 builder.penaltyDeathOnNetwork(); 1353 } 1354 1355 if (Build.IS_USER || DISABLE || SystemProperties.getBoolean(DISABLE_PROPERTY, false)) { 1356 // Detect nothing extra 1357 } else if (Build.IS_USERDEBUG) { 1358 // Detect everything in bundled apps 1359 if (isBundledSystemApp(ai)) { 1360 builder.detectAll(); 1361 builder.penaltyDropBox(); 1362 if (SystemProperties.getBoolean(VISUAL_PROPERTY, false)) { 1363 builder.penaltyFlashScreen(); 1364 } 1365 } 1366 } else if (Build.IS_ENG) { 1367 // Detect everything in bundled apps 1368 if (isBundledSystemApp(ai)) { 1369 builder.detectAll(); 1370 builder.penaltyDropBox(); 1371 builder.penaltyLog(); 1372 builder.penaltyFlashScreen(); 1373 } 1374 } 1375 1376 setThreadPolicy(builder.build()); 1377 } 1378 1379 /** 1380 * Initialize default {@link VmPolicy} for the current VM. 1381 * 1382 * @hide 1383 */ initVmDefaults(ApplicationInfo ai)1384 public static void initVmDefaults(ApplicationInfo ai) { 1385 final VmPolicy.Builder builder = new VmPolicy.Builder(); 1386 final int targetSdkVersion = 1387 (ai != null) ? ai.targetSdkVersion : Build.VERSION_CODES.CUR_DEVELOPMENT; 1388 1389 // Starting in N, we don't allow file:// Uri exposure 1390 if (targetSdkVersion >= Build.VERSION_CODES.N) { 1391 builder.detectFileUriExposure(); 1392 builder.penaltyDeathOnFileUriExposure(); 1393 } 1394 1395 if (Build.IS_USER || DISABLE || SystemProperties.getBoolean(DISABLE_PROPERTY, false)) { 1396 // Detect nothing extra 1397 } else if (Build.IS_USERDEBUG) { 1398 // Detect everything in bundled apps (except activity leaks, which 1399 // are expensive to track) 1400 if (isBundledSystemApp(ai)) { 1401 builder.detectAll(); 1402 builder.permitActivityLeaks(); 1403 builder.penaltyDropBox(); 1404 } 1405 } else if (Build.IS_ENG) { 1406 // Detect everything in bundled apps 1407 if (isBundledSystemApp(ai)) { 1408 builder.detectAll(); 1409 builder.penaltyDropBox(); 1410 builder.penaltyLog(); 1411 } 1412 } 1413 1414 setVmPolicy(builder.build()); 1415 } 1416 1417 /** 1418 * Used by the framework to make file usage a fatal error. 1419 * 1420 * @hide 1421 */ 1422 @UnsupportedAppUsage enableDeathOnFileUriExposure()1423 public static void enableDeathOnFileUriExposure() { 1424 sVmPolicy = 1425 new VmPolicy( 1426 sVmPolicy.mask 1427 | DETECT_VM_FILE_URI_EXPOSURE 1428 | PENALTY_DEATH_ON_FILE_URI_EXPOSURE, 1429 sVmPolicy.classInstanceLimit, 1430 sVmPolicy.mListener, 1431 sVmPolicy.mCallbackExecutor); 1432 } 1433 1434 /** 1435 * Used by lame internal apps that haven't done the hard work to get themselves off file:// Uris 1436 * yet. 1437 * 1438 * @hide 1439 */ 1440 @UnsupportedAppUsage disableDeathOnFileUriExposure()1441 public static void disableDeathOnFileUriExposure() { 1442 sVmPolicy = 1443 new VmPolicy( 1444 sVmPolicy.mask 1445 & ~(DETECT_VM_FILE_URI_EXPOSURE 1446 | PENALTY_DEATH_ON_FILE_URI_EXPOSURE), 1447 sVmPolicy.classInstanceLimit, 1448 sVmPolicy.mListener, 1449 sVmPolicy.mCallbackExecutor); 1450 } 1451 1452 @UnsupportedAppUsage 1453 private static final ThreadLocal<ArrayList<ViolationInfo>> violationsBeingTimed = 1454 new ThreadLocal<ArrayList<ViolationInfo>>() { 1455 @Override 1456 protected ArrayList<ViolationInfo> initialValue() { 1457 return new ArrayList<ViolationInfo>(); 1458 } 1459 }; 1460 1461 // Note: only access this once verifying the thread has a Looper. 1462 private static final ThreadLocal<Handler> THREAD_HANDLER = 1463 new ThreadLocal<Handler>() { 1464 @Override 1465 protected Handler initialValue() { 1466 return new Handler(); 1467 } 1468 }; 1469 1470 private static final ThreadLocal<AndroidBlockGuardPolicy> THREAD_ANDROID_POLICY = 1471 new ThreadLocal<AndroidBlockGuardPolicy>() { 1472 @Override 1473 protected AndroidBlockGuardPolicy initialValue() { 1474 return new AndroidBlockGuardPolicy(0); 1475 } 1476 }; 1477 tooManyViolationsThisLoop()1478 private static boolean tooManyViolationsThisLoop() { 1479 return violationsBeingTimed.get().size() >= MAX_OFFENSES_PER_LOOP; 1480 } 1481 1482 private static class AndroidBlockGuardPolicy implements BlockGuard.Policy { 1483 private @ThreadPolicyMask int mThreadPolicyMask; 1484 1485 // Map from violation stacktrace hashcode -> uptimeMillis of 1486 // last violation. No locking needed, as this is only 1487 // accessed by the same thread. 1488 private ArrayMap<Integer, Long> mLastViolationTime; 1489 AndroidBlockGuardPolicy(@hreadPolicyMask int threadPolicyMask)1490 public AndroidBlockGuardPolicy(@ThreadPolicyMask int threadPolicyMask) { 1491 mThreadPolicyMask = threadPolicyMask; 1492 } 1493 1494 @Override toString()1495 public String toString() { 1496 return "AndroidBlockGuardPolicy; mPolicyMask=" + mThreadPolicyMask; 1497 } 1498 1499 // Part of BlockGuard.Policy interface: getPolicyMask()1500 public int getPolicyMask() { 1501 return mThreadPolicyMask; 1502 } 1503 1504 // Part of BlockGuard.Policy interface: onWriteToDisk()1505 public void onWriteToDisk() { 1506 if ((mThreadPolicyMask & DETECT_THREAD_DISK_WRITE) == 0) { 1507 return; 1508 } 1509 if (tooManyViolationsThisLoop()) { 1510 return; 1511 } 1512 startHandlingViolationException(new DiskWriteViolation()); 1513 } 1514 1515 // Not part of BlockGuard.Policy; just part of StrictMode: onCustomSlowCall(String name)1516 void onCustomSlowCall(String name) { 1517 if ((mThreadPolicyMask & DETECT_THREAD_CUSTOM) == 0) { 1518 return; 1519 } 1520 if (tooManyViolationsThisLoop()) { 1521 return; 1522 } 1523 startHandlingViolationException(new CustomViolation(name)); 1524 } 1525 1526 // Not part of BlockGuard.Policy; just part of StrictMode: onResourceMismatch(Object tag)1527 void onResourceMismatch(Object tag) { 1528 if ((mThreadPolicyMask & DETECT_THREAD_RESOURCE_MISMATCH) == 0) { 1529 return; 1530 } 1531 if (tooManyViolationsThisLoop()) { 1532 return; 1533 } 1534 startHandlingViolationException(new ResourceMismatchViolation(tag)); 1535 } 1536 1537 // Not part of BlockGuard.Policy; just part of StrictMode: onUnbufferedIO()1538 public void onUnbufferedIO() { 1539 if ((mThreadPolicyMask & DETECT_THREAD_UNBUFFERED_IO) == 0) { 1540 return; 1541 } 1542 if (tooManyViolationsThisLoop()) { 1543 return; 1544 } 1545 startHandlingViolationException(new UnbufferedIoViolation()); 1546 } 1547 1548 // Part of BlockGuard.Policy interface: onReadFromDisk()1549 public void onReadFromDisk() { 1550 if ((mThreadPolicyMask & DETECT_THREAD_DISK_READ) == 0) { 1551 return; 1552 } 1553 if (tooManyViolationsThisLoop()) { 1554 return; 1555 } 1556 startHandlingViolationException(new DiskReadViolation()); 1557 } 1558 1559 // Part of BlockGuard.Policy interface: onNetwork()1560 public void onNetwork() { 1561 if ((mThreadPolicyMask & DETECT_THREAD_NETWORK) == 0) { 1562 return; 1563 } 1564 if ((mThreadPolicyMask & PENALTY_DEATH_ON_NETWORK) != 0) { 1565 throw new NetworkOnMainThreadException(); 1566 } 1567 if (tooManyViolationsThisLoop()) { 1568 return; 1569 } 1570 startHandlingViolationException(new NetworkViolation()); 1571 } 1572 1573 // Part of BlockGuard.Policy interface: onExplicitGc()1574 public void onExplicitGc() { 1575 if ((mThreadPolicyMask & DETECT_THREAD_EXPLICIT_GC) == 0) { 1576 return; 1577 } 1578 if (tooManyViolationsThisLoop()) { 1579 return; 1580 } 1581 startHandlingViolationException(new ExplicitGcViolation()); 1582 } 1583 getThreadPolicyMask()1584 public @ThreadPolicyMask int getThreadPolicyMask() { 1585 return mThreadPolicyMask; 1586 } 1587 setThreadPolicyMask(@hreadPolicyMask int threadPolicyMask)1588 public void setThreadPolicyMask(@ThreadPolicyMask int threadPolicyMask) { 1589 mThreadPolicyMask = threadPolicyMask; 1590 } 1591 1592 // Start handling a violation that just started and hasn't 1593 // actually run yet (e.g. no disk write or network operation 1594 // has yet occurred). This sees if we're in an event loop 1595 // thread and, if so, uses it to roughly measure how long the 1596 // violation took. startHandlingViolationException(Violation e)1597 void startHandlingViolationException(Violation e) { 1598 final int penaltyMask = (mThreadPolicyMask & PENALTY_ALL); 1599 final ViolationInfo info = new ViolationInfo(e, penaltyMask); 1600 info.violationUptimeMillis = SystemClock.uptimeMillis(); 1601 handleViolationWithTimingAttempt(info); 1602 } 1603 1604 // Attempts to fill in the provided ViolationInfo's 1605 // durationMillis field if this thread has a Looper we can use 1606 // to measure with. We measure from the time of violation 1607 // until the time the looper is idle again (right before 1608 // the next epoll_wait) handleViolationWithTimingAttempt(final ViolationInfo info)1609 void handleViolationWithTimingAttempt(final ViolationInfo info) { 1610 Looper looper = Looper.myLooper(); 1611 1612 // Without a Looper, we're unable to time how long the 1613 // violation takes place. This case should be rare, as 1614 // most users will care about timing violations that 1615 // happen on their main UI thread. Note that this case is 1616 // also hit when a violation takes place in a Binder 1617 // thread, in "gather" mode. In this case, the duration 1618 // of the violation is computed by the ultimate caller and 1619 // its Looper, if any. 1620 // 1621 // Also, as a special short-cut case when the only penalty 1622 // bit is death, we die immediately, rather than timing 1623 // the violation's duration. This makes it convenient to 1624 // use in unit tests too, rather than waiting on a Looper. 1625 // 1626 // TODO: if in gather mode, ignore Looper.myLooper() and always 1627 // go into this immediate mode? 1628 if (looper == null || (info.mPenaltyMask == PENALTY_DEATH)) { 1629 info.durationMillis = -1; // unknown (redundant, already set) 1630 onThreadPolicyViolation(info); 1631 return; 1632 } 1633 1634 final ArrayList<ViolationInfo> records = violationsBeingTimed.get(); 1635 if (records.size() >= MAX_OFFENSES_PER_LOOP) { 1636 // Not worth measuring. Too many offenses in one loop. 1637 return; 1638 } 1639 records.add(info); 1640 if (records.size() > 1) { 1641 // There's already been a violation this loop, so we've already 1642 // registered an idle handler to process the list of violations 1643 // at the end of this Looper's loop. 1644 return; 1645 } 1646 1647 final IWindowManager windowManager = 1648 info.penaltyEnabled(PENALTY_FLASH) ? sWindowManager.get() : null; 1649 if (windowManager != null) { 1650 try { 1651 windowManager.showStrictModeViolation(true); 1652 } catch (RemoteException unused) { 1653 } 1654 } 1655 1656 // We post a runnable to a Handler (== delay 0 ms) for 1657 // measuring the end time of a violation instead of using 1658 // an IdleHandler (as was previously used) because an 1659 // IdleHandler may not run for quite a long period of time 1660 // if an ongoing animation is happening and continually 1661 // posting ASAP (0 ms) animation steps. Animations are 1662 // throttled back to 60fps via SurfaceFlinger/View 1663 // invalidates, _not_ by posting frame updates every 16 1664 // milliseconds. 1665 THREAD_HANDLER 1666 .get() 1667 .postAtFrontOfQueue( 1668 () -> { 1669 long loopFinishTime = SystemClock.uptimeMillis(); 1670 1671 // Note: we do this early, before handling the 1672 // violation below, as handling the violation 1673 // may include PENALTY_DEATH and we don't want 1674 // to keep the red border on. 1675 if (windowManager != null) { 1676 try { 1677 windowManager.showStrictModeViolation(false); 1678 } catch (RemoteException unused) { 1679 } 1680 } 1681 1682 for (int n = 0; n < records.size(); ++n) { 1683 ViolationInfo v = records.get(n); 1684 v.violationNumThisLoop = n + 1; 1685 v.durationMillis = 1686 (int) (loopFinishTime - v.violationUptimeMillis); 1687 onThreadPolicyViolation(v); 1688 } 1689 records.clear(); 1690 }); 1691 } 1692 1693 // Note: It's possible (even quite likely) that the 1694 // thread-local policy mask has changed from the time the 1695 // violation fired and now (after the violating code ran) due 1696 // to people who push/pop temporary policy in regions of code, 1697 // hence the policy being passed around. onThreadPolicyViolation(final ViolationInfo info)1698 void onThreadPolicyViolation(final ViolationInfo info) { 1699 if (LOG_V) Log.d(TAG, "onThreadPolicyViolation; penalty=" + info.mPenaltyMask); 1700 1701 if (info.penaltyEnabled(PENALTY_GATHER)) { 1702 ArrayList<ViolationInfo> violations = gatheredViolations.get(); 1703 if (violations == null) { 1704 violations = new ArrayList<>(1); 1705 gatheredViolations.set(violations); 1706 } 1707 for (ViolationInfo previous : violations) { 1708 if (info.getStackTrace().equals(previous.getStackTrace())) { 1709 // Duplicate. Don't log. 1710 return; 1711 } 1712 } 1713 violations.add(info); 1714 return; 1715 } 1716 1717 // Not perfect, but fast and good enough for dup suppression. 1718 Integer crashFingerprint = info.hashCode(); 1719 long lastViolationTime = 0; 1720 if (mLastViolationTime != null) { 1721 Long vtime = mLastViolationTime.get(crashFingerprint); 1722 if (vtime != null) { 1723 lastViolationTime = vtime; 1724 } 1725 } else { 1726 mLastViolationTime = new ArrayMap<>(1); 1727 } 1728 long now = SystemClock.uptimeMillis(); 1729 mLastViolationTime.put(crashFingerprint, now); 1730 long timeSinceLastViolationMillis = 1731 lastViolationTime == 0 ? Long.MAX_VALUE : (now - lastViolationTime); 1732 1733 if (info.penaltyEnabled(PENALTY_LOG) 1734 && timeSinceLastViolationMillis > MIN_LOG_INTERVAL_MS) { 1735 sLogger.log(info); 1736 } 1737 1738 final Violation violation = info.mViolation; 1739 1740 // Penalties that ActivityManager should execute on our behalf. 1741 int penaltyMask = 0; 1742 1743 if (info.penaltyEnabled(PENALTY_DIALOG) 1744 && timeSinceLastViolationMillis > MIN_DIALOG_INTERVAL_MS) { 1745 penaltyMask |= PENALTY_DIALOG; 1746 } 1747 1748 if (info.penaltyEnabled(PENALTY_DROPBOX) && lastViolationTime == 0) { 1749 penaltyMask |= PENALTY_DROPBOX; 1750 } 1751 1752 if (penaltyMask != 0) { 1753 final boolean justDropBox = (info.mPenaltyMask == PENALTY_DROPBOX); 1754 if (justDropBox) { 1755 // If all we're going to ask the activity manager 1756 // to do is dropbox it (the common case during 1757 // platform development), we can avoid doing this 1758 // call synchronously which Binder data suggests 1759 // isn't always super fast, despite the implementation 1760 // in the ActivityManager trying to be mostly async. 1761 dropboxViolationAsync(penaltyMask, info); 1762 } else { 1763 handleApplicationStrictModeViolation(penaltyMask, info); 1764 } 1765 } 1766 1767 if (info.penaltyEnabled(PENALTY_DEATH)) { 1768 throw new RuntimeException("StrictMode ThreadPolicy violation", violation); 1769 } 1770 1771 // penaltyDeath will cause penaltyCallback to no-op since we cannot guarantee the 1772 // executor finishes before crashing. 1773 final OnThreadViolationListener listener = sThreadViolationListener.get(); 1774 final Executor executor = sThreadViolationExecutor.get(); 1775 if (listener != null && executor != null) { 1776 try { 1777 executor.execute( 1778 () -> { 1779 // Lift violated policy to prevent infinite recursion. 1780 ThreadPolicy oldPolicy = StrictMode.allowThreadViolations(); 1781 try { 1782 listener.onThreadViolation(violation); 1783 } finally { 1784 StrictMode.setThreadPolicy(oldPolicy); 1785 } 1786 }); 1787 } catch (RejectedExecutionException e) { 1788 Log.e(TAG, "ThreadPolicy penaltyCallback failed", e); 1789 } 1790 } 1791 } 1792 } 1793 1794 private static final BlockGuard.VmPolicy VM_ANDROID_POLICY = new BlockGuard.VmPolicy() { 1795 @Override 1796 public void onPathAccess(String path) { 1797 if (path == null) return; 1798 1799 // NOTE: keep credential-protected paths in sync with Environment.java 1800 if (path.startsWith("/data/user/") 1801 || path.startsWith("/data/media/") 1802 || path.startsWith("/data/system_ce/") 1803 || path.startsWith("/data/misc_ce/") 1804 || path.startsWith("/data/vendor_ce/") 1805 || path.startsWith("/storage/emulated/")) { 1806 final int second = path.indexOf('/', 1); 1807 final int third = path.indexOf('/', second + 1); 1808 final int fourth = path.indexOf('/', third + 1); 1809 if (fourth == -1) return; 1810 1811 try { 1812 final int userId = Integer.parseInt(path.substring(third + 1, fourth)); 1813 onCredentialProtectedPathAccess(path, userId); 1814 } catch (NumberFormatException ignored) { 1815 } 1816 } else if (path.startsWith("/data/data/")) { 1817 onCredentialProtectedPathAccess(path, UserHandle.USER_SYSTEM); 1818 } 1819 } 1820 }; 1821 1822 /** 1823 * In the common case, as set by conditionallyEnableDebugLogging, we're just dropboxing any 1824 * violations but not showing a dialog, not loggging, and not killing the process. In these 1825 * cases we don't need to do a synchronous call to the ActivityManager. This is used by both 1826 * per-thread and vm-wide violations when applicable. 1827 */ dropboxViolationAsync( final int penaltyMask, final ViolationInfo info)1828 private static void dropboxViolationAsync( 1829 final int penaltyMask, final ViolationInfo info) { 1830 int outstanding = sDropboxCallsInFlight.incrementAndGet(); 1831 if (outstanding > 20) { 1832 // What's going on? Let's not make make the situation 1833 // worse and just not log. 1834 sDropboxCallsInFlight.decrementAndGet(); 1835 return; 1836 } 1837 1838 if (LOG_V) Log.d(TAG, "Dropboxing async; in-flight=" + outstanding); 1839 1840 BackgroundThread.getHandler().post(() -> { 1841 handleApplicationStrictModeViolation(penaltyMask, info); 1842 int outstandingInner = sDropboxCallsInFlight.decrementAndGet(); 1843 if (LOG_V) Log.d(TAG, "Dropbox complete; in-flight=" + outstandingInner); 1844 }); 1845 } 1846 handleApplicationStrictModeViolation(int penaltyMask, ViolationInfo info)1847 private static void handleApplicationStrictModeViolation(int penaltyMask, 1848 ViolationInfo info) { 1849 final int oldMask = getThreadPolicyMask(); 1850 try { 1851 // First, remove any policy before we call into the Activity Manager, 1852 // otherwise we'll infinite recurse as we try to log policy violations 1853 // to disk, thus violating policy, thus requiring logging, etc... 1854 // We restore the current policy below, in the finally block. 1855 setThreadPolicyMask(0); 1856 1857 IActivityManager am = ActivityManager.getService(); 1858 if (am == null) { 1859 Log.w(TAG, "No activity manager; failed to Dropbox violation."); 1860 } else { 1861 am.handleApplicationStrictModeViolation( 1862 RuntimeInit.getApplicationObject(), penaltyMask, info); 1863 } 1864 } catch (RemoteException e) { 1865 if (e instanceof DeadObjectException) { 1866 // System process is dead; ignore 1867 } else { 1868 Log.e(TAG, "RemoteException handling StrictMode violation", e); 1869 } 1870 } finally { 1871 setThreadPolicyMask(oldMask); 1872 } 1873 } 1874 1875 private static class AndroidCloseGuardReporter implements CloseGuard.Reporter { report(String message, Throwable allocationSite)1876 public void report(String message, Throwable allocationSite) { 1877 onVmPolicyViolation(new LeakedClosableViolation(message, allocationSite)); 1878 } 1879 } 1880 1881 /** Called from Parcel.writeNoException() */ hasGatheredViolations()1882 /* package */ static boolean hasGatheredViolations() { 1883 return gatheredViolations.get() != null; 1884 } 1885 1886 /** 1887 * Called from Parcel.writeException(), so we drop this memory and don't incorrectly attribute 1888 * it to the wrong caller on the next Binder call on this thread. 1889 */ clearGatheredViolations()1890 /* package */ static void clearGatheredViolations() { 1891 gatheredViolations.set(null); 1892 } 1893 1894 /** @hide */ 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. */ ViolationInfo(Parcel in)2754 public ViolationInfo(Parcel in) { 2755 this(in, false); 2756 } 2757 2758 /** 2759 * Create an instance of ViolationInfo initialized from a Parcel. 2760 * 2761 * @param unsetGatheringBit if true, the caller is the root caller and the gathering penalty 2762 * should be removed. 2763 */ ViolationInfo(Parcel in, boolean unsetGatheringBit)2764 public ViolationInfo(Parcel in, boolean unsetGatheringBit) { 2765 mViolation = (Violation) in.readSerializable(); 2766 int binderStackSize = in.readInt(); 2767 for (int i = 0; i < binderStackSize; i++) { 2768 StackTraceElement[] traceElements = new StackTraceElement[in.readInt()]; 2769 for (int j = 0; j < traceElements.length; j++) { 2770 StackTraceElement element = 2771 new StackTraceElement( 2772 in.readString(), 2773 in.readString(), 2774 in.readString(), 2775 in.readInt()); 2776 traceElements[j] = element; 2777 } 2778 mBinderStack.add(traceElements); 2779 } 2780 int rawPenaltyMask = in.readInt(); 2781 if (unsetGatheringBit) { 2782 mPenaltyMask = rawPenaltyMask & ~PENALTY_GATHER; 2783 } else { 2784 mPenaltyMask = rawPenaltyMask; 2785 } 2786 durationMillis = in.readInt(); 2787 violationNumThisLoop = in.readInt(); 2788 numAnimationsRunning = in.readInt(); 2789 violationUptimeMillis = in.readLong(); 2790 numInstances = in.readLong(); 2791 broadcastIntentAction = in.readString(); 2792 tags = in.readStringArray(); 2793 } 2794 2795 /** Save a ViolationInfo instance to a parcel. */ 2796 @Override writeToParcel(Parcel dest, int flags)2797 public void writeToParcel(Parcel dest, int flags) { 2798 dest.writeSerializable(mViolation); 2799 dest.writeInt(mBinderStack.size()); 2800 for (StackTraceElement[] traceElements : mBinderStack) { 2801 dest.writeInt(traceElements.length); 2802 for (StackTraceElement element : traceElements) { 2803 dest.writeString(element.getClassName()); 2804 dest.writeString(element.getMethodName()); 2805 dest.writeString(element.getFileName()); 2806 dest.writeInt(element.getLineNumber()); 2807 } 2808 } 2809 int start = dest.dataPosition(); 2810 dest.writeInt(mPenaltyMask); 2811 dest.writeInt(durationMillis); 2812 dest.writeInt(violationNumThisLoop); 2813 dest.writeInt(numAnimationsRunning); 2814 dest.writeLong(violationUptimeMillis); 2815 dest.writeLong(numInstances); 2816 dest.writeString(broadcastIntentAction); 2817 dest.writeStringArray(tags); 2818 int total = dest.dataPosition() - start; 2819 if (Binder.CHECK_PARCEL_SIZE && total > 10 * 1024) { 2820 Slog.d( 2821 TAG, 2822 "VIO: penalty=" 2823 + mPenaltyMask 2824 + " dur=" 2825 + durationMillis 2826 + " numLoop=" 2827 + violationNumThisLoop 2828 + " anim=" 2829 + numAnimationsRunning 2830 + " uptime=" 2831 + violationUptimeMillis 2832 + " numInst=" 2833 + numInstances); 2834 Slog.d(TAG, "VIO: action=" + broadcastIntentAction); 2835 Slog.d(TAG, "VIO: tags=" + Arrays.toString(tags)); 2836 Slog.d(TAG, "VIO: TOTAL BYTES WRITTEN: " + (dest.dataPosition() - start)); 2837 } 2838 } 2839 2840 /** Dump a ViolationInfo instance to a Printer. */ dump(Printer pw, String prefix)2841 public void dump(Printer pw, String prefix) { 2842 pw.println(prefix + "stackTrace: " + getStackTrace()); 2843 pw.println(prefix + "penalty: " + mPenaltyMask); 2844 if (durationMillis != -1) { 2845 pw.println(prefix + "durationMillis: " + durationMillis); 2846 } 2847 if (numInstances != -1) { 2848 pw.println(prefix + "numInstances: " + numInstances); 2849 } 2850 if (violationNumThisLoop != 0) { 2851 pw.println(prefix + "violationNumThisLoop: " + violationNumThisLoop); 2852 } 2853 if (numAnimationsRunning != 0) { 2854 pw.println(prefix + "numAnimationsRunning: " + numAnimationsRunning); 2855 } 2856 pw.println(prefix + "violationUptimeMillis: " + violationUptimeMillis); 2857 if (broadcastIntentAction != null) { 2858 pw.println(prefix + "broadcastIntentAction: " + broadcastIntentAction); 2859 } 2860 if (tags != null) { 2861 int index = 0; 2862 for (String tag : tags) { 2863 pw.println(prefix + "tag[" + (index++) + "]: " + tag); 2864 } 2865 } 2866 } 2867 2868 @Override describeContents()2869 public int describeContents() { 2870 return 0; 2871 } 2872 2873 public static final @android.annotation.NonNull Parcelable.Creator<ViolationInfo> CREATOR = 2874 new Parcelable.Creator<ViolationInfo>() { 2875 @Override 2876 public ViolationInfo createFromParcel(Parcel in) { 2877 return new ViolationInfo(in); 2878 } 2879 2880 @Override 2881 public ViolationInfo[] newArray(int size) { 2882 return new ViolationInfo[size]; 2883 } 2884 }; 2885 } 2886 2887 private static final class InstanceTracker { 2888 private static final HashMap<Class<?>, Integer> sInstanceCounts = 2889 new HashMap<Class<?>, Integer>(); 2890 2891 private final Class<?> mKlass; 2892 InstanceTracker(Object instance)2893 public InstanceTracker(Object instance) { 2894 mKlass = instance.getClass(); 2895 2896 synchronized (sInstanceCounts) { 2897 final Integer value = sInstanceCounts.get(mKlass); 2898 final int newValue = value != null ? value + 1 : 1; 2899 sInstanceCounts.put(mKlass, newValue); 2900 } 2901 } 2902 2903 @Override finalize()2904 protected void finalize() throws Throwable { 2905 try { 2906 synchronized (sInstanceCounts) { 2907 final Integer value = sInstanceCounts.get(mKlass); 2908 if (value != null) { 2909 final int newValue = value - 1; 2910 if (newValue > 0) { 2911 sInstanceCounts.put(mKlass, newValue); 2912 } else { 2913 sInstanceCounts.remove(mKlass); 2914 } 2915 } 2916 } 2917 } finally { 2918 super.finalize(); 2919 } 2920 } 2921 getInstanceCount(Class<?> klass)2922 public static int getInstanceCount(Class<?> klass) { 2923 synchronized (sInstanceCounts) { 2924 final Integer value = sInstanceCounts.get(klass); 2925 return value != null ? value : 0; 2926 } 2927 } 2928 } 2929 } 2930