StrictMode.java revision c1a968a8ed45181312f7d4bcdbba0cc8ddc201ba
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 */ 16package android.os; 17 18import android.animation.ValueAnimator; 19import android.app.ActivityManagerNative; 20import android.app.ActivityThread; 21import android.app.ApplicationErrorReport; 22import android.app.IActivityManager; 23import android.content.Intent; 24import android.util.Log; 25import android.util.Printer; 26import android.util.Singleton; 27import android.view.IWindowManager; 28 29import com.android.internal.os.RuntimeInit; 30 31import dalvik.system.BlockGuard; 32import dalvik.system.CloseGuard; 33 34import java.io.PrintWriter; 35import java.io.StringWriter; 36import java.util.ArrayList; 37import java.util.HashMap; 38import java.util.concurrent.atomic.AtomicInteger; 39 40/** 41 * <p>StrictMode is a developer tool which detects things you might be 42 * doing by accident and brings them to your attention so you can fix 43 * them. 44 * 45 * <p>StrictMode is most commonly used to catch accidental disk or 46 * network access on the application's main thread, where UI 47 * operations are received and animations take place. Keeping disk 48 * and network operations off the main thread makes for much smoother, 49 * more responsive applications. By keeping your application's main thread 50 * responsive, you also prevent 51 * <a href="{@docRoot}guide/practices/design/responsiveness.html">ANR dialogs</a> 52 * from being shown to users. 53 * 54 * <p class="note">Note that even though an Android device's disk is 55 * often on flash memory, many devices run a filesystem on top of that 56 * memory with very limited concurrency. It's often the case that 57 * almost all disk accesses are fast, but may in individual cases be 58 * dramatically slower when certain I/O is happening in the background 59 * from other processes. If possible, it's best to assume that such 60 * things are not fast.</p> 61 * 62 * <p>Example code to enable from early in your 63 * {@link android.app.Application}, {@link android.app.Activity}, or 64 * other application component's 65 * {@link android.app.Application#onCreate} method: 66 * 67 * <pre> 68 * public void onCreate() { 69 * if (DEVELOPER_MODE) { 70 * StrictMode.setThreadPolicy(new {@link ThreadPolicy.Builder StrictMode.ThreadPolicy.Builder}() 71 * .detectDiskReads() 72 * .detectDiskWrites() 73 * .detectNetwork() // or .detectAll() for all detectable problems 74 * .penaltyLog() 75 * .build()); 76 * StrictMode.setVmPolicy(new {@link VmPolicy.Builder StrictMode.VmPolicy.Builder}() 77 * .detectLeakedSqlLiteObjects() 78 * .detectLeakedClosableObjects() 79 * .penaltyLog() 80 * .penaltyDeath() 81 * .build()); 82 * } 83 * super.onCreate(); 84 * } 85 * </pre> 86 * 87 * <p>You can decide what should happen when a violation is detected. 88 * For example, using {@link ThreadPolicy.Builder#penaltyLog} you can 89 * watch the output of <code>adb logcat</code> while you use your 90 * application to see the violations as they happen. 91 * 92 * <p>If you find violations that you feel are problematic, there are 93 * a variety of tools to help solve them: threads, {@link android.os.Handler}, 94 * {@link android.os.AsyncTask}, {@link android.app.IntentService}, etc. 95 * But don't feel compelled to fix everything that StrictMode finds. In particular, 96 * many cases of disk access are often necessary during the normal activity lifecycle. Use 97 * StrictMode to find things you did by accident. Network requests on the UI thread 98 * are almost always a problem, though. 99 * 100 * <p class="note">StrictMode is not a security mechanism and is not 101 * guaranteed to find all disk or network accesses. While it does 102 * propagate its state across process boundaries when doing 103 * {@link android.os.Binder} calls, it's still ultimately a best 104 * effort mechanism. Notably, disk or network access from JNI calls 105 * won't necessarily trigger it. Future versions of Android may catch 106 * more (or fewer) operations, so you should never leave StrictMode 107 * enabled in shipping applications on the Android Market. 108 */ 109public final class StrictMode { 110 private static final String TAG = "StrictMode"; 111 private static final boolean LOG_V = Log.isLoggable(TAG, Log.VERBOSE); 112 113 private static final boolean IS_USER_BUILD = "user".equals(Build.TYPE); 114 private static final boolean IS_ENG_BUILD = "eng".equals(Build.TYPE); 115 116 /** 117 * The boolean system property to control screen flashes on violations. 118 * 119 * @hide 120 */ 121 public static final String VISUAL_PROPERTY = "persist.sys.strictmode.visual"; 122 123 // Only log a duplicate stack trace to the logs every second. 124 private static final long MIN_LOG_INTERVAL_MS = 1000; 125 126 // Only show an annoying dialog at most every 30 seconds 127 private static final long MIN_DIALOG_INTERVAL_MS = 30000; 128 129 // How many Span tags (e.g. animations) to report. 130 private static final int MAX_SPAN_TAGS = 20; 131 132 // How many offending stacks to keep track of (and time) per loop 133 // of the Looper. 134 private static final int MAX_OFFENSES_PER_LOOP = 10; 135 136 // Thread-policy: 137 138 /** 139 * @hide 140 */ 141 public static final int DETECT_DISK_WRITE = 0x01; // for ThreadPolicy 142 143 /** 144 * @hide 145 */ 146 public static final int DETECT_DISK_READ = 0x02; // for ThreadPolicy 147 148 /** 149 * @hide 150 */ 151 public static final int DETECT_NETWORK = 0x04; // for ThreadPolicy 152 153 // Process-policy: 154 155 /** 156 * Note, a "VM_" bit, not thread. 157 * @hide 158 */ 159 public static final int DETECT_VM_CURSOR_LEAKS = 0x200; // for ProcessPolicy 160 161 /** 162 * Note, a "VM_" bit, not thread. 163 * @hide 164 */ 165 public static final int DETECT_VM_CLOSABLE_LEAKS = 0x400; // for ProcessPolicy 166 167 /** 168 * @hide 169 */ 170 public static final int PENALTY_LOG = 0x10; // normal android.util.Log 171 172 // Used for both process and thread policy: 173 174 /** 175 * @hide 176 */ 177 public static final int PENALTY_DIALOG = 0x20; 178 179 /** 180 * Death on any detected violation. 181 * 182 * @hide 183 */ 184 public static final int PENALTY_DEATH = 0x40; 185 186 /** 187 * Death just for detected network usage. 188 * 189 * @hide 190 */ 191 public static final int PENALTY_DEATH_ON_NETWORK = 0x200; 192 193 /** 194 * Flash the screen during violations. 195 * 196 * @hide 197 */ 198 public static final int PENALTY_FLASH = 0x800; 199 200 /** 201 * @hide 202 */ 203 public static final int PENALTY_DROPBOX = 0x80; 204 205 /** 206 * Non-public penalty mode which overrides all the other penalty 207 * bits and signals that we're in a Binder call and we should 208 * ignore the other penalty bits and instead serialize back all 209 * our offending stack traces to the caller to ultimately handle 210 * in the originating process. 211 * 212 * This must be kept in sync with the constant in libs/binder/Parcel.cpp 213 * 214 * @hide 215 */ 216 public static final int PENALTY_GATHER = 0x100; 217 218 /** 219 * Mask of all the penalty bits. 220 */ 221 private static final int PENALTY_MASK = 222 PENALTY_LOG | PENALTY_DIALOG | PENALTY_DEATH | PENALTY_DROPBOX | PENALTY_GATHER | 223 PENALTY_DEATH_ON_NETWORK | PENALTY_FLASH; 224 225 /** 226 * The current VmPolicy in effect. 227 */ 228 private static volatile int sVmPolicyMask = 0; 229 230 /** 231 * The number of threads trying to do an async dropbox write. 232 * Just to limit ourselves out of paranoia. 233 */ 234 private static final AtomicInteger sDropboxCallsInFlight = new AtomicInteger(0); 235 236 private StrictMode() {} 237 238 /** 239 * {@link StrictMode} policy applied to a certain thread. 240 * 241 * <p>The policy is enabled by {@link #setThreadPolicy}. The current policy 242 * can be retrieved with {@link #getThreadPolicy}. 243 * 244 * <p>Note that multiple penalties may be provided and they're run 245 * in order from least to most severe (logging before process 246 * death, for example). There's currently no mechanism to choose 247 * different penalties for different detected actions. 248 */ 249 public static final class ThreadPolicy { 250 /** 251 * The default, lax policy which doesn't catch anything. 252 */ 253 public static final ThreadPolicy LAX = new ThreadPolicy(0); 254 255 final int mask; 256 257 private ThreadPolicy(int mask) { 258 this.mask = mask; 259 } 260 261 @Override 262 public String toString() { 263 return "[StrictMode.ThreadPolicy; mask=" + mask + "]"; 264 } 265 266 /** 267 * Creates ThreadPolicy instances. Methods whose names start 268 * with {@code detect} specify what problems we should look 269 * for. Methods whose names start with {@code penalty} specify what 270 * we should do when we detect a problem. 271 * 272 * <p>You can call as many {@code detect} and {@code penalty} 273 * methods as you like. Currently order is insignificant: all 274 * penalties apply to all detected problems. 275 * 276 * <p>For example, detect everything and log anything that's found: 277 * <pre> 278 * StrictMode.VmPolicy policy = new StrictMode.VmPolicy.Builder() 279 * .detectAll() 280 * .penaltyLog() 281 * .build(); 282 * StrictMode.setVmPolicy(policy); 283 * </pre> 284 */ 285 public static final class Builder { 286 private int mMask = 0; 287 288 /** 289 * Create a Builder that detects nothing and has no 290 * violations. (but note that {@link #build} will default 291 * to enabling {@link #penaltyLog} if no other penalties 292 * are specified) 293 */ 294 public Builder() { 295 mMask = 0; 296 } 297 298 /** 299 * Initialize a Builder from an existing ThreadPolicy. 300 */ 301 public Builder(ThreadPolicy policy) { 302 mMask = policy.mask; 303 } 304 305 /** 306 * Detect everything that's potentially suspect. 307 * 308 * <p>As of the Gingerbread release this includes network and 309 * disk operations but will likely expand in future releases. 310 */ 311 public Builder detectAll() { 312 return enable(DETECT_DISK_WRITE | DETECT_DISK_READ | DETECT_NETWORK); 313 } 314 315 /** 316 * Disable the detection of everything. 317 */ 318 public Builder permitAll() { 319 return disable(DETECT_DISK_WRITE | DETECT_DISK_READ | DETECT_NETWORK); 320 } 321 322 /** 323 * Enable detection of network operations. 324 */ 325 public Builder detectNetwork() { 326 return enable(DETECT_NETWORK); 327 } 328 329 /** 330 * Disable detection of network operations. 331 */ 332 public Builder permitNetwork() { 333 return disable(DETECT_NETWORK); 334 } 335 336 /** 337 * Enable detection of disk reads. 338 */ 339 public Builder detectDiskReads() { 340 return enable(DETECT_DISK_READ); 341 } 342 343 /** 344 * Disable detection of disk reads. 345 */ 346 public Builder permitDiskReads() { 347 return disable(DETECT_DISK_READ); 348 } 349 350 /** 351 * Enable detection of disk writes. 352 */ 353 public Builder detectDiskWrites() { 354 return enable(DETECT_DISK_WRITE); 355 } 356 357 /** 358 * Disable detection of disk writes. 359 */ 360 public Builder permitDiskWrites() { 361 return disable(DETECT_DISK_WRITE); 362 } 363 364 /** 365 * Show an annoying dialog to the developer on detected 366 * violations, rate-limited to be only a little annoying. 367 */ 368 public Builder penaltyDialog() { 369 return enable(PENALTY_DIALOG); 370 } 371 372 /** 373 * Crash the whole process on violation. This penalty runs at 374 * the end of all enabled penalties so you'll still get 375 * see logging or other violations before the process dies. 376 * 377 * <p>Unlike {@link #penaltyDeathOnNetwork}, this applies 378 * to disk reads, disk writes, and network usage if their 379 * corresponding detect flags are set. 380 */ 381 public Builder penaltyDeath() { 382 return enable(PENALTY_DEATH); 383 } 384 385 /** 386 * Crash the whole process on any network usage. Unlike 387 * {@link #penaltyDeath}, this penalty runs 388 * <em>before</em> anything else. You must still have 389 * called {@link #detectNetwork} to enable this. 390 * 391 * <p>In the Honeycomb or later SDKs, this is on by default. 392 */ 393 public Builder penaltyDeathOnNetwork() { 394 return enable(PENALTY_DEATH_ON_NETWORK); 395 } 396 397 /** 398 * Flash the screen during a violation. 399 */ 400 public Builder penaltyFlashScreen() { 401 return enable(PENALTY_FLASH); 402 } 403 404 /** 405 * Log detected violations to the system log. 406 */ 407 public Builder penaltyLog() { 408 return enable(PENALTY_LOG); 409 } 410 411 /** 412 * Enable detected violations log a stacktrace and timing data 413 * to the {@link android.os.DropBoxManager DropBox} on policy 414 * violation. Intended mostly for platform integrators doing 415 * beta user field data collection. 416 */ 417 public Builder penaltyDropBox() { 418 return enable(PENALTY_DROPBOX); 419 } 420 421 private Builder enable(int bit) { 422 mMask |= bit; 423 return this; 424 } 425 426 private Builder disable(int bit) { 427 mMask &= ~bit; 428 return this; 429 } 430 431 /** 432 * Construct the ThreadPolicy instance. 433 * 434 * <p>Note: if no penalties are enabled before calling 435 * <code>build</code>, {@link #penaltyLog} is implicitly 436 * set. 437 */ 438 public ThreadPolicy build() { 439 // If there are detection bits set but no violation bits 440 // set, enable simple logging. 441 if (mMask != 0 && 442 (mMask & (PENALTY_DEATH | PENALTY_LOG | 443 PENALTY_DROPBOX | PENALTY_DIALOG)) == 0) { 444 penaltyLog(); 445 } 446 return new ThreadPolicy(mMask); 447 } 448 } 449 } 450 451 /** 452 * {@link StrictMode} policy applied to all threads in the virtual machine's process. 453 * 454 * <p>The policy is enabled by {@link #setVmPolicy}. 455 */ 456 public static final class VmPolicy { 457 /** 458 * The default, lax policy which doesn't catch anything. 459 */ 460 public static final VmPolicy LAX = new VmPolicy(0); 461 462 final int mask; 463 464 private VmPolicy(int mask) { 465 this.mask = mask; 466 } 467 468 @Override 469 public String toString() { 470 return "[StrictMode.VmPolicy; mask=" + mask + "]"; 471 } 472 473 /** 474 * Creates {@link VmPolicy} instances. Methods whose names start 475 * with {@code detect} specify what problems we should look 476 * for. Methods whose names start with {@code penalty} specify what 477 * we should do when we detect a problem. 478 * 479 * <p>You can call as many {@code detect} and {@code penalty} 480 * methods as you like. Currently order is insignificant: all 481 * penalties apply to all detected problems. 482 * 483 * <p>For example, detect everything and log anything that's found: 484 * <pre> 485 * StrictMode.VmPolicy policy = new StrictMode.VmPolicy.Builder() 486 * .detectAll() 487 * .penaltyLog() 488 * .build(); 489 * StrictMode.setVmPolicy(policy); 490 * </pre> 491 */ 492 public static final class Builder { 493 private int mMask; 494 495 /** 496 * Detect everything that's potentially suspect. 497 * 498 * <p>In the Honeycomb release this includes leaks of 499 * SQLite cursors and other closable objects but will 500 * likely expand in future releases. 501 */ 502 public Builder detectAll() { 503 return enable(DETECT_VM_CURSOR_LEAKS | DETECT_VM_CLOSABLE_LEAKS); 504 } 505 506 /** 507 * Detect when an 508 * {@link android.database.sqlite.SQLiteCursor} or other 509 * SQLite object is finalized without having been closed. 510 * 511 * <p>You always want to explicitly close your SQLite 512 * cursors to avoid unnecessary database contention and 513 * temporary memory leaks. 514 */ 515 public Builder detectLeakedSqlLiteObjects() { 516 return enable(DETECT_VM_CURSOR_LEAKS); 517 } 518 519 /** 520 * Detect when an {@link java.io.Closeable} or other 521 * object with a explict termination method is finalized 522 * without having been closed. 523 * 524 * <p>You always want to explicitly close such objects to 525 * avoid unnecessary resources leaks. 526 */ 527 public Builder detectLeakedClosableObjects() { 528 return enable(DETECT_VM_CLOSABLE_LEAKS); 529 } 530 531 /** 532 * Crashes the whole process on violation. This penalty runs at 533 * the end of all enabled penalties so yo you'll still get 534 * your logging or other violations before the process dies. 535 */ 536 public Builder penaltyDeath() { 537 return enable(PENALTY_DEATH); 538 } 539 540 /** 541 * Log detected violations to the system log. 542 */ 543 public Builder penaltyLog() { 544 return enable(PENALTY_LOG); 545 } 546 547 /** 548 * Enable detected violations log a stacktrace and timing data 549 * to the {@link android.os.DropBoxManager DropBox} on policy 550 * violation. Intended mostly for platform integrators doing 551 * beta user field data collection. 552 */ 553 public Builder penaltyDropBox() { 554 return enable(PENALTY_DROPBOX); 555 } 556 557 private Builder enable(int bit) { 558 mMask |= bit; 559 return this; 560 } 561 562 /** 563 * Construct the VmPolicy instance. 564 * 565 * <p>Note: if no penalties are enabled before calling 566 * <code>build</code>, {@link #penaltyLog} is implicitly 567 * set. 568 */ 569 public VmPolicy build() { 570 // If there are detection bits set but no violation bits 571 // set, enable simple logging. 572 if (mMask != 0 && 573 (mMask & (PENALTY_DEATH | PENALTY_LOG | 574 PENALTY_DROPBOX | PENALTY_DIALOG)) == 0) { 575 penaltyLog(); 576 } 577 return new VmPolicy(mMask); 578 } 579 } 580 } 581 582 /** 583 * Log of strict mode violation stack traces that have occurred 584 * during a Binder call, to be serialized back later to the caller 585 * via Parcel.writeNoException() (amusingly) where the caller can 586 * choose how to react. 587 */ 588 private static final ThreadLocal<ArrayList<ViolationInfo>> gatheredViolations = 589 new ThreadLocal<ArrayList<ViolationInfo>>() { 590 @Override protected ArrayList<ViolationInfo> initialValue() { 591 // Starts null to avoid unnecessary allocations when 592 // checking whether there are any violations or not in 593 // hasGatheredViolations() below. 594 return null; 595 } 596 }; 597 598 /** 599 * Sets the policy for what actions on the current thread should 600 * be detected, as well as the penalty if such actions occur. 601 * 602 * <p>Internally this sets a thread-local variable which is 603 * propagated across cross-process IPC calls, meaning you can 604 * catch violations when a system service or another process 605 * accesses the disk or network on your behalf. 606 * 607 * @param policy the policy to put into place 608 */ 609 public static void setThreadPolicy(final ThreadPolicy policy) { 610 setThreadPolicyMask(policy.mask); 611 } 612 613 private static void setThreadPolicyMask(final int policyMask) { 614 // In addition to the Java-level thread-local in Dalvik's 615 // BlockGuard, we also need to keep a native thread-local in 616 // Binder in order to propagate the value across Binder calls, 617 // even across native-only processes. The two are kept in 618 // sync via the callback to onStrictModePolicyChange, below. 619 setBlockGuardPolicy(policyMask); 620 621 // And set the Android native version... 622 Binder.setThreadStrictModePolicy(policyMask); 623 } 624 625 // Sets the policy in Dalvik/libcore (BlockGuard) 626 private static void setBlockGuardPolicy(final int policyMask) { 627 if (policyMask == 0) { 628 BlockGuard.setThreadPolicy(BlockGuard.LAX_POLICY); 629 return; 630 } 631 BlockGuard.Policy policy = BlockGuard.getThreadPolicy(); 632 if (!(policy instanceof AndroidBlockGuardPolicy)) { 633 BlockGuard.setThreadPolicy(new AndroidBlockGuardPolicy(policyMask)); 634 } else { 635 AndroidBlockGuardPolicy androidPolicy = (AndroidBlockGuardPolicy) policy; 636 androidPolicy.setPolicyMask(policyMask); 637 } 638 } 639 640 // Sets up CloseGuard in Dalvik/libcore 641 private static void setCloseGuardEnabled(boolean enabled) { 642 if (!(CloseGuard.getReporter() instanceof AndroidCloseGuardReporter)) { 643 CloseGuard.setReporter(new AndroidCloseGuardReporter()); 644 } 645 CloseGuard.setEnabled(enabled); 646 } 647 648 private static class StrictModeNetworkViolation extends BlockGuard.BlockGuardPolicyException { 649 public StrictModeNetworkViolation(int policyMask) { 650 super(policyMask, DETECT_NETWORK); 651 } 652 } 653 654 private static class StrictModeDiskReadViolation extends BlockGuard.BlockGuardPolicyException { 655 public StrictModeDiskReadViolation(int policyMask) { 656 super(policyMask, DETECT_DISK_READ); 657 } 658 } 659 660 private static class StrictModeDiskWriteViolation extends BlockGuard.BlockGuardPolicyException { 661 public StrictModeDiskWriteViolation(int policyMask) { 662 super(policyMask, DETECT_DISK_WRITE); 663 } 664 } 665 666 /** 667 * Returns the bitmask of the current thread's policy. 668 * 669 * @return the bitmask of all the DETECT_* and PENALTY_* bits currently enabled 670 * 671 * @hide 672 */ 673 public static int getThreadPolicyMask() { 674 return BlockGuard.getThreadPolicy().getPolicyMask(); 675 } 676 677 /** 678 * Returns the current thread's policy. 679 */ 680 public static ThreadPolicy getThreadPolicy() { 681 return new ThreadPolicy(getThreadPolicyMask()); 682 } 683 684 /** 685 * A convenience wrapper that takes the current 686 * {@link ThreadPolicy} from {@link #getThreadPolicy}, modifies it 687 * to permit both disk reads & writes, and sets the new policy 688 * with {@link #setThreadPolicy}, returning the old policy so you 689 * can restore it at the end of a block. 690 * 691 * @return the old policy, to be passed to {@link #setThreadPolicy} to 692 * restore the policy at the end of a block 693 */ 694 public static ThreadPolicy allowThreadDiskWrites() { 695 int oldPolicyMask = getThreadPolicyMask(); 696 int newPolicyMask = oldPolicyMask & ~(DETECT_DISK_WRITE | DETECT_DISK_READ); 697 if (newPolicyMask != oldPolicyMask) { 698 setThreadPolicyMask(newPolicyMask); 699 } 700 return new ThreadPolicy(oldPolicyMask); 701 } 702 703 /** 704 * A convenience wrapper that takes the current 705 * {@link ThreadPolicy} from {@link #getThreadPolicy}, modifies it 706 * to permit disk reads, and sets the new policy 707 * with {@link #setThreadPolicy}, returning the old policy so you 708 * can restore it at the end of a block. 709 * 710 * @return the old policy, to be passed to setThreadPolicy to 711 * restore the policy. 712 */ 713 public static ThreadPolicy allowThreadDiskReads() { 714 int oldPolicyMask = getThreadPolicyMask(); 715 int newPolicyMask = oldPolicyMask & ~(DETECT_DISK_READ); 716 if (newPolicyMask != oldPolicyMask) { 717 setThreadPolicyMask(newPolicyMask); 718 } 719 return new ThreadPolicy(oldPolicyMask); 720 } 721 722 /** 723 * Enable DropBox logging for debug phone builds. 724 * 725 * @hide 726 */ 727 public static boolean conditionallyEnableDebugLogging() { 728 boolean doFlashes = SystemProperties.getBoolean(VISUAL_PROPERTY, IS_ENG_BUILD); 729 730 // For debug builds, log event loop stalls to dropbox for analysis. 731 // Similar logic also appears in ActivityThread.java for system apps. 732 if (IS_USER_BUILD && !doFlashes) { 733 setCloseGuardEnabled(false); 734 return false; 735 } 736 737 int threadPolicyMask = StrictMode.DETECT_DISK_WRITE | 738 StrictMode.DETECT_DISK_READ | 739 StrictMode.DETECT_NETWORK; 740 741 if (!IS_USER_BUILD) { 742 threadPolicyMask |= StrictMode.PENALTY_DROPBOX; 743 } 744 if (doFlashes) { 745 threadPolicyMask |= StrictMode.PENALTY_FLASH; 746 } 747 748 StrictMode.setThreadPolicyMask(threadPolicyMask); 749 750 if (IS_USER_BUILD) { 751 setCloseGuardEnabled(false); 752 } else { 753 sVmPolicyMask = StrictMode.DETECT_VM_CURSOR_LEAKS | 754 StrictMode.DETECT_VM_CLOSABLE_LEAKS | 755 StrictMode.PENALTY_DROPBOX; 756 setCloseGuardEnabled(vmClosableObjectLeaksEnabled()); 757 } 758 return true; 759 } 760 761 /** 762 * Used by the framework to make network usage on the main 763 * thread a fatal error. 764 * 765 * @hide 766 */ 767 public static void enableDeathOnNetwork() { 768 int oldPolicy = getThreadPolicyMask(); 769 int newPolicy = oldPolicy | DETECT_NETWORK | PENALTY_DEATH_ON_NETWORK; 770 setThreadPolicyMask(newPolicy); 771 } 772 773 /** 774 * Parses the BlockGuard policy mask out from the Exception's 775 * getMessage() String value. Kinda gross, but least 776 * invasive. :/ 777 * 778 * Input is of form "policy=137 violation=64" 779 * 780 * Returns 0 on failure, which is a valid policy, but not a 781 * valid policy during a violation (else there must've been 782 * some policy in effect to violate). 783 */ 784 private static int parsePolicyFromMessage(String message) { 785 if (message == null || !message.startsWith("policy=")) { 786 return 0; 787 } 788 int spaceIndex = message.indexOf(' '); 789 if (spaceIndex == -1) { 790 return 0; 791 } 792 String policyString = message.substring(7, spaceIndex); 793 try { 794 return Integer.valueOf(policyString).intValue(); 795 } catch (NumberFormatException e) { 796 return 0; 797 } 798 } 799 800 /** 801 * Like parsePolicyFromMessage(), but returns the violation. 802 */ 803 private static int parseViolationFromMessage(String message) { 804 if (message == null) { 805 return 0; 806 } 807 int violationIndex = message.indexOf("violation="); 808 if (violationIndex == -1) { 809 return 0; 810 } 811 String violationString = message.substring(violationIndex + 10); 812 try { 813 return Integer.valueOf(violationString).intValue(); 814 } catch (NumberFormatException e) { 815 return 0; 816 } 817 } 818 819 private static final ThreadLocal<ArrayList<ViolationInfo>> violationsBeingTimed = 820 new ThreadLocal<ArrayList<ViolationInfo>>() { 821 @Override protected ArrayList<ViolationInfo> initialValue() { 822 return new ArrayList<ViolationInfo>(); 823 } 824 }; 825 826 private static boolean tooManyViolationsThisLoop() { 827 return violationsBeingTimed.get().size() >= MAX_OFFENSES_PER_LOOP; 828 } 829 830 private static class AndroidBlockGuardPolicy implements BlockGuard.Policy { 831 private int mPolicyMask; 832 833 // Map from violation stacktrace hashcode -> uptimeMillis of 834 // last violation. No locking needed, as this is only 835 // accessed by the same thread. 836 private final HashMap<Integer, Long> mLastViolationTime = new HashMap<Integer, Long>(); 837 838 public AndroidBlockGuardPolicy(final int policyMask) { 839 mPolicyMask = policyMask; 840 } 841 842 @Override 843 public String toString() { 844 return "AndroidBlockGuardPolicy; mPolicyMask=" + mPolicyMask; 845 } 846 847 // Part of BlockGuard.Policy interface: 848 public int getPolicyMask() { 849 return mPolicyMask; 850 } 851 852 // Part of BlockGuard.Policy interface: 853 public void onWriteToDisk() { 854 if ((mPolicyMask & DETECT_DISK_WRITE) == 0) { 855 return; 856 } 857 if (tooManyViolationsThisLoop()) { 858 return; 859 } 860 BlockGuard.BlockGuardPolicyException e = new StrictModeDiskWriteViolation(mPolicyMask); 861 e.fillInStackTrace(); 862 startHandlingViolationException(e); 863 } 864 865 // Part of BlockGuard.Policy interface: 866 public void onReadFromDisk() { 867 if ((mPolicyMask & DETECT_DISK_READ) == 0) { 868 return; 869 } 870 if (tooManyViolationsThisLoop()) { 871 return; 872 } 873 BlockGuard.BlockGuardPolicyException e = new StrictModeDiskReadViolation(mPolicyMask); 874 e.fillInStackTrace(); 875 startHandlingViolationException(e); 876 } 877 878 // Part of BlockGuard.Policy interface: 879 public void onNetwork() { 880 if ((mPolicyMask & DETECT_NETWORK) == 0) { 881 return; 882 } 883 if ((mPolicyMask & PENALTY_DEATH_ON_NETWORK) != 0) { 884 throw new NetworkOnMainThreadException(); 885 } 886 if (tooManyViolationsThisLoop()) { 887 return; 888 } 889 BlockGuard.BlockGuardPolicyException e = new StrictModeNetworkViolation(mPolicyMask); 890 e.fillInStackTrace(); 891 startHandlingViolationException(e); 892 } 893 894 public void setPolicyMask(int policyMask) { 895 mPolicyMask = policyMask; 896 } 897 898 // Start handling a violation that just started and hasn't 899 // actually run yet (e.g. no disk write or network operation 900 // has yet occurred). This sees if we're in an event loop 901 // thread and, if so, uses it to roughly measure how long the 902 // violation took. 903 void startHandlingViolationException(BlockGuard.BlockGuardPolicyException e) { 904 final ViolationInfo info = new ViolationInfo(e, e.getPolicy()); 905 info.violationUptimeMillis = SystemClock.uptimeMillis(); 906 handleViolationWithTimingAttempt(info); 907 } 908 909 // Attempts to fill in the provided ViolationInfo's 910 // durationMillis field if this thread has a Looper we can use 911 // to measure with. We measure from the time of violation 912 // until the time the looper is idle again (right before 913 // the next epoll_wait) 914 void handleViolationWithTimingAttempt(final ViolationInfo info) { 915 Looper looper = Looper.myLooper(); 916 917 // Without a Looper, we're unable to time how long the 918 // violation takes place. This case should be rare, as 919 // most users will care about timing violations that 920 // happen on their main UI thread. Note that this case is 921 // also hit when a violation takes place in a Binder 922 // thread, in "gather" mode. In this case, the duration 923 // of the violation is computed by the ultimate caller and 924 // its Looper, if any. 925 // TODO: if in gather mode, ignore Looper.myLooper() and always 926 // go into this immediate mode? 927 if (looper == null) { 928 info.durationMillis = -1; // unknown (redundant, already set) 929 handleViolation(info); 930 return; 931 } 932 933 MessageQueue queue = Looper.myQueue(); 934 final ArrayList<ViolationInfo> records = violationsBeingTimed.get(); 935 if (records.size() >= MAX_OFFENSES_PER_LOOP) { 936 // Not worth measuring. Too many offenses in one loop. 937 return; 938 } 939 records.add(info); 940 if (records.size() > 1) { 941 // There's already been a violation this loop, so we've already 942 // registered an idle handler to process the list of violations 943 // at the end of this Looper's loop. 944 return; 945 } 946 947 final IWindowManager windowManager = (info.policy & PENALTY_FLASH) != 0 ? 948 sWindowManager.get() : null; 949 if (windowManager != null) { 950 try { 951 windowManager.showStrictModeViolation(true); 952 } catch (RemoteException unused) { 953 } 954 } 955 956 queue.addIdleHandler(new MessageQueue.IdleHandler() { 957 public boolean queueIdle() { 958 long loopFinishTime = SystemClock.uptimeMillis(); 959 for (int n = 0; n < records.size(); ++n) { 960 ViolationInfo v = records.get(n); 961 v.violationNumThisLoop = n + 1; 962 v.durationMillis = 963 (int) (loopFinishTime - v.violationUptimeMillis); 964 handleViolation(v); 965 } 966 records.clear(); 967 if (windowManager != null) { 968 try { 969 windowManager.showStrictModeViolation(false); 970 } catch (RemoteException unused) { 971 } 972 } 973 return false; // remove this idle handler from the array 974 } 975 }); 976 } 977 978 // Note: It's possible (even quite likely) that the 979 // thread-local policy mask has changed from the time the 980 // violation fired and now (after the violating code ran) due 981 // to people who push/pop temporary policy in regions of code, 982 // hence the policy being passed around. 983 void handleViolation(final ViolationInfo info) { 984 if (info == null || info.crashInfo == null || info.crashInfo.stackTrace == null) { 985 Log.wtf(TAG, "unexpected null stacktrace"); 986 return; 987 } 988 989 if (LOG_V) Log.d(TAG, "handleViolation; policy=" + info.policy); 990 991 if ((info.policy & PENALTY_GATHER) != 0) { 992 ArrayList<ViolationInfo> violations = gatheredViolations.get(); 993 if (violations == null) { 994 violations = new ArrayList<ViolationInfo>(1); 995 gatheredViolations.set(violations); 996 } else if (violations.size() >= 5) { 997 // Too many. In a loop or something? Don't gather them all. 998 return; 999 } 1000 for (ViolationInfo previous : violations) { 1001 if (info.crashInfo.stackTrace.equals(previous.crashInfo.stackTrace)) { 1002 // Duplicate. Don't log. 1003 return; 1004 } 1005 } 1006 violations.add(info); 1007 return; 1008 } 1009 1010 // Not perfect, but fast and good enough for dup suppression. 1011 Integer crashFingerprint = info.hashCode(); 1012 long lastViolationTime = 0; 1013 if (mLastViolationTime.containsKey(crashFingerprint)) { 1014 lastViolationTime = mLastViolationTime.get(crashFingerprint); 1015 } 1016 long now = SystemClock.uptimeMillis(); 1017 mLastViolationTime.put(crashFingerprint, now); 1018 long timeSinceLastViolationMillis = lastViolationTime == 0 ? 1019 Long.MAX_VALUE : (now - lastViolationTime); 1020 1021 if ((info.policy & PENALTY_LOG) != 0 && 1022 timeSinceLastViolationMillis > MIN_LOG_INTERVAL_MS) { 1023 if (info.durationMillis != -1) { 1024 Log.d(TAG, "StrictMode policy violation; ~duration=" + 1025 info.durationMillis + " ms: " + info.crashInfo.stackTrace); 1026 } else { 1027 Log.d(TAG, "StrictMode policy violation: " + info.crashInfo.stackTrace); 1028 } 1029 } 1030 1031 // The violationMaskSubset, passed to ActivityManager, is a 1032 // subset of the original StrictMode policy bitmask, with 1033 // only the bit violated and penalty bits to be executed 1034 // by the ActivityManagerService remaining set. 1035 int violationMaskSubset = 0; 1036 1037 if ((info.policy & PENALTY_DIALOG) != 0 && 1038 timeSinceLastViolationMillis > MIN_DIALOG_INTERVAL_MS) { 1039 violationMaskSubset |= PENALTY_DIALOG; 1040 } 1041 1042 if ((info.policy & PENALTY_DROPBOX) != 0 && lastViolationTime == 0) { 1043 violationMaskSubset |= PENALTY_DROPBOX; 1044 } 1045 1046 if (violationMaskSubset != 0) { 1047 int violationBit = parseViolationFromMessage(info.crashInfo.exceptionMessage); 1048 violationMaskSubset |= violationBit; 1049 final int savedPolicyMask = getThreadPolicyMask(); 1050 1051 final boolean justDropBox = (info.policy & PENALTY_MASK) == PENALTY_DROPBOX; 1052 if (justDropBox) { 1053 // If all we're going to ask the activity manager 1054 // to do is dropbox it (the common case during 1055 // platform development), we can avoid doing this 1056 // call synchronously which Binder data suggests 1057 // isn't always super fast, despite the implementation 1058 // in the ActivityManager trying to be mostly async. 1059 dropboxViolationAsync(violationMaskSubset, info); 1060 return; 1061 } 1062 1063 // Normal synchronous call to the ActivityManager. 1064 try { 1065 // First, remove any policy before we call into the Activity Manager, 1066 // otherwise we'll infinite recurse as we try to log policy violations 1067 // to disk, thus violating policy, thus requiring logging, etc... 1068 // We restore the current policy below, in the finally block. 1069 setThreadPolicyMask(0); 1070 1071 ActivityManagerNative.getDefault().handleApplicationStrictModeViolation( 1072 RuntimeInit.getApplicationObject(), 1073 violationMaskSubset, 1074 info); 1075 } catch (RemoteException e) { 1076 Log.e(TAG, "RemoteException trying to handle StrictMode violation", e); 1077 } finally { 1078 // Restore the policy. 1079 setThreadPolicyMask(savedPolicyMask); 1080 } 1081 } 1082 1083 if ((info.policy & PENALTY_DEATH) != 0) { 1084 System.err.println("StrictMode policy violation with POLICY_DEATH; shutting down."); 1085 Process.killProcess(Process.myPid()); 1086 System.exit(10); 1087 } 1088 } 1089 } 1090 1091 /** 1092 * In the common case, as set by conditionallyEnableDebugLogging, 1093 * we're just dropboxing any violations but not showing a dialog, 1094 * not loggging, and not killing the process. In these cases we 1095 * don't need to do a synchronous call to the ActivityManager. 1096 * This is used by both per-thread and vm-wide violations when 1097 * applicable. 1098 */ 1099 private static void dropboxViolationAsync( 1100 final int violationMaskSubset, final ViolationInfo info) { 1101 int outstanding = sDropboxCallsInFlight.incrementAndGet(); 1102 if (outstanding > 20) { 1103 // What's going on? Let's not make make the situation 1104 // worse and just not log. 1105 sDropboxCallsInFlight.decrementAndGet(); 1106 return; 1107 } 1108 1109 if (LOG_V) Log.d(TAG, "Dropboxing async; in-flight=" + outstanding); 1110 1111 new Thread("callActivityManagerForStrictModeDropbox") { 1112 public void run() { 1113 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); 1114 try { 1115 IActivityManager am = ActivityManagerNative.getDefault(); 1116 if (am == null) { 1117 Log.d(TAG, "No activity manager; failed to Dropbox violation."); 1118 } else { 1119 am.handleApplicationStrictModeViolation( 1120 RuntimeInit.getApplicationObject(), 1121 violationMaskSubset, 1122 info); 1123 } 1124 } catch (RemoteException e) { 1125 Log.e(TAG, "RemoteException handling StrictMode violation", e); 1126 } 1127 int outstanding = sDropboxCallsInFlight.decrementAndGet(); 1128 if (LOG_V) Log.d(TAG, "Dropbox complete; in-flight=" + outstanding); 1129 } 1130 }.start(); 1131 } 1132 1133 private static class AndroidCloseGuardReporter implements CloseGuard.Reporter { 1134 public void report (String message, Throwable allocationSite) { 1135 onVmPolicyViolation(message, allocationSite); 1136 } 1137 } 1138 1139 /** 1140 * Called from Parcel.writeNoException() 1141 */ 1142 /* package */ static boolean hasGatheredViolations() { 1143 return gatheredViolations.get() != null; 1144 } 1145 1146 /** 1147 * Called from Parcel.writeException(), so we drop this memory and 1148 * don't incorrectly attribute it to the wrong caller on the next 1149 * Binder call on this thread. 1150 */ 1151 /* package */ static void clearGatheredViolations() { 1152 gatheredViolations.set(null); 1153 } 1154 1155 /** 1156 * Sets the policy for what actions in the VM process (on any 1157 * thread) should be detected, as well as the penalty if such 1158 * actions occur. 1159 * 1160 * @param policy the policy to put into place 1161 */ 1162 public static void setVmPolicy(final VmPolicy policy) { 1163 sVmPolicyMask = policy.mask; 1164 setCloseGuardEnabled(vmClosableObjectLeaksEnabled()); 1165 } 1166 1167 /** 1168 * Gets the current VM policy. 1169 */ 1170 public static VmPolicy getVmPolicy() { 1171 return new VmPolicy(sVmPolicyMask); 1172 } 1173 1174 /** 1175 * Enable the recommended StrictMode defaults, with violations just being logged. 1176 * 1177 * <p>This catches disk and network access on the main thread, as 1178 * well as leaked SQLite cursors and unclosed resources. This is 1179 * simply a wrapper around {@link #setVmPolicy} and {@link 1180 * #setThreadPolicy}. 1181 */ 1182 public static void enableDefaults() { 1183 StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() 1184 .detectAll() 1185 .penaltyLog() 1186 .build()); 1187 StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder() 1188 .detectLeakedSqlLiteObjects() 1189 .detectLeakedClosableObjects() 1190 .penaltyLog() 1191 .build()); 1192 } 1193 1194 /** 1195 * @hide 1196 */ 1197 public static boolean vmSqliteObjectLeaksEnabled() { 1198 return (sVmPolicyMask & DETECT_VM_CURSOR_LEAKS) != 0; 1199 } 1200 1201 /** 1202 * @hide 1203 */ 1204 public static boolean vmClosableObjectLeaksEnabled() { 1205 return (sVmPolicyMask & DETECT_VM_CLOSABLE_LEAKS) != 0; 1206 } 1207 1208 /** 1209 * @hide 1210 */ 1211 public static void onSqliteObjectLeaked(String message, Throwable originStack) { 1212 onVmPolicyViolation(message, originStack); 1213 } 1214 1215 /** 1216 * @hide 1217 */ 1218 public static void onVmPolicyViolation(String message, Throwable originStack) { 1219 if ((sVmPolicyMask & PENALTY_LOG) != 0) { 1220 Log.e(TAG, message, originStack); 1221 } 1222 1223 boolean penaltyDropbox = (sVmPolicyMask & PENALTY_DROPBOX) != 0; 1224 boolean penaltyDeath = (sVmPolicyMask & PENALTY_DEATH) != 0; 1225 1226 int violationMaskSubset = PENALTY_DROPBOX | DETECT_VM_CURSOR_LEAKS; 1227 ViolationInfo info = new ViolationInfo(originStack, sVmPolicyMask); 1228 1229 if (penaltyDropbox && !penaltyDeath) { 1230 // Common case for userdebug/eng builds. If no death and 1231 // just dropboxing, we can do the ActivityManager call 1232 // asynchronously. 1233 dropboxViolationAsync(violationMaskSubset, info); 1234 return; 1235 } 1236 1237 if (penaltyDropbox) { 1238 // The violationMask, passed to ActivityManager, is a 1239 // subset of the original StrictMode policy bitmask, with 1240 // only the bit violated and penalty bits to be executed 1241 // by the ActivityManagerService remaining set. 1242 final int savedPolicyMask = getThreadPolicyMask(); 1243 try { 1244 // First, remove any policy before we call into the Activity Manager, 1245 // otherwise we'll infinite recurse as we try to log policy violations 1246 // to disk, thus violating policy, thus requiring logging, etc... 1247 // We restore the current policy below, in the finally block. 1248 setThreadPolicyMask(0); 1249 1250 ActivityManagerNative.getDefault().handleApplicationStrictModeViolation( 1251 RuntimeInit.getApplicationObject(), 1252 violationMaskSubset, 1253 info); 1254 } catch (RemoteException e) { 1255 Log.e(TAG, "RemoteException trying to handle StrictMode violation", e); 1256 } finally { 1257 // Restore the policy. 1258 setThreadPolicyMask(savedPolicyMask); 1259 } 1260 } 1261 1262 if (penaltyDeath) { 1263 System.err.println("StrictMode VmPolicy violation with POLICY_DEATH; shutting down."); 1264 Process.killProcess(Process.myPid()); 1265 System.exit(10); 1266 } 1267 } 1268 1269 /** 1270 * Called from Parcel.writeNoException() 1271 */ 1272 /* package */ static void writeGatheredViolationsToParcel(Parcel p) { 1273 ArrayList<ViolationInfo> violations = gatheredViolations.get(); 1274 if (violations == null) { 1275 p.writeInt(0); 1276 } else { 1277 p.writeInt(violations.size()); 1278 for (int i = 0; i < violations.size(); ++i) { 1279 violations.get(i).writeToParcel(p, 0 /* unused flags? */); 1280 } 1281 if (LOG_V) Log.d(TAG, "wrote violations to response parcel; num=" + violations.size()); 1282 violations.clear(); // somewhat redundant, as we're about to null the threadlocal 1283 } 1284 gatheredViolations.set(null); 1285 } 1286 1287 private static class LogStackTrace extends Exception {} 1288 1289 /** 1290 * Called from Parcel.readException() when the exception is EX_STRICT_MODE_VIOLATIONS, 1291 * we here read back all the encoded violations. 1292 */ 1293 /* package */ static void readAndHandleBinderCallViolations(Parcel p) { 1294 // Our own stack trace to append 1295 StringWriter sw = new StringWriter(); 1296 new LogStackTrace().printStackTrace(new PrintWriter(sw)); 1297 String ourStack = sw.toString(); 1298 1299 int policyMask = getThreadPolicyMask(); 1300 boolean currentlyGathering = (policyMask & PENALTY_GATHER) != 0; 1301 1302 int numViolations = p.readInt(); 1303 for (int i = 0; i < numViolations; ++i) { 1304 if (LOG_V) Log.d(TAG, "strict mode violation stacks read from binder call. i=" + i); 1305 ViolationInfo info = new ViolationInfo(p, !currentlyGathering); 1306 info.crashInfo.stackTrace += "# via Binder call with stack:\n" + ourStack; 1307 BlockGuard.Policy policy = BlockGuard.getThreadPolicy(); 1308 if (policy instanceof AndroidBlockGuardPolicy) { 1309 ((AndroidBlockGuardPolicy) policy).handleViolationWithTimingAttempt(info); 1310 } 1311 } 1312 } 1313 1314 /** 1315 * Called from android_util_Binder.cpp's 1316 * android_os_Parcel_enforceInterface when an incoming Binder call 1317 * requires changing the StrictMode policy mask. The role of this 1318 * function is to ask Binder for its current (native) thread-local 1319 * policy value and synchronize it to libcore's (Java) 1320 * thread-local policy value. 1321 */ 1322 private static void onBinderStrictModePolicyChange(int newPolicy) { 1323 setBlockGuardPolicy(newPolicy); 1324 } 1325 1326 /** 1327 * A tracked, critical time span. (e.g. during an animation.) 1328 * 1329 * The object itself is a linked list node, to avoid any allocations 1330 * during rapid span entries and exits. 1331 * 1332 * @hide 1333 */ 1334 public static class Span { 1335 private String mName; 1336 private long mCreateMillis; 1337 private Span mNext; 1338 private Span mPrev; // not used when in freeList, only active 1339 private final ThreadSpanState mContainerState; 1340 1341 Span(ThreadSpanState threadState) { 1342 mContainerState = threadState; 1343 } 1344 1345 // Empty constructor for the NO_OP_SPAN 1346 protected Span() { 1347 mContainerState = null; 1348 } 1349 1350 /** 1351 * To be called when the critical span is complete (i.e. the 1352 * animation is done animating). This can be called on any 1353 * thread (even a different one from where the animation was 1354 * taking place), but that's only a defensive implementation 1355 * measure. It really makes no sense for you to call this on 1356 * thread other than that where you created it. 1357 * 1358 * @hide 1359 */ 1360 public void finish() { 1361 ThreadSpanState state = mContainerState; 1362 synchronized (state) { 1363 if (mName == null) { 1364 // Duplicate finish call. Ignore. 1365 return; 1366 } 1367 1368 // Remove ourselves from the active list. 1369 if (mPrev != null) { 1370 mPrev.mNext = mNext; 1371 } 1372 if (mNext != null) { 1373 mNext.mPrev = mPrev; 1374 } 1375 if (state.mActiveHead == this) { 1376 state.mActiveHead = mNext; 1377 } 1378 1379 state.mActiveSize--; 1380 1381 if (LOG_V) Log.d(TAG, "Span finished=" + mName + "; size=" + state.mActiveSize); 1382 1383 this.mCreateMillis = -1; 1384 this.mName = null; 1385 this.mPrev = null; 1386 this.mNext = null; 1387 1388 // Add ourselves to the freeList, if it's not already 1389 // too big. 1390 if (state.mFreeListSize < 5) { 1391 this.mNext = state.mFreeListHead; 1392 state.mFreeListHead = this; 1393 state.mFreeListSize++; 1394 } 1395 } 1396 } 1397 } 1398 1399 // The no-op span that's used in user builds. 1400 private static final Span NO_OP_SPAN = new Span() { 1401 public void finish() { 1402 // Do nothing. 1403 } 1404 }; 1405 1406 /** 1407 * Linked lists of active spans and a freelist. 1408 * 1409 * Locking notes: there's one of these structures per thread and 1410 * all members of this structure (as well as the Span nodes under 1411 * it) are guarded by the ThreadSpanState object instance. While 1412 * in theory there'd be no locking required because it's all local 1413 * per-thread, the finish() method above is defensive against 1414 * people calling it on a different thread from where they created 1415 * the Span, hence the locking. 1416 */ 1417 private static class ThreadSpanState { 1418 public Span mActiveHead; // doubly-linked list. 1419 public int mActiveSize; 1420 public Span mFreeListHead; // singly-linked list. only changes at head. 1421 public int mFreeListSize; 1422 } 1423 1424 private static final ThreadLocal<ThreadSpanState> sThisThreadSpanState = 1425 new ThreadLocal<ThreadSpanState>() { 1426 @Override protected ThreadSpanState initialValue() { 1427 return new ThreadSpanState(); 1428 } 1429 }; 1430 1431 private static Singleton<IWindowManager> sWindowManager = new Singleton<IWindowManager>() { 1432 protected IWindowManager create() { 1433 return IWindowManager.Stub.asInterface(ServiceManager.getService("window")); 1434 } 1435 }; 1436 1437 /** 1438 * Enter a named critical span (e.g. an animation) 1439 * 1440 * <p>The name is an arbitary label (or tag) that will be applied 1441 * to any strictmode violation that happens while this span is 1442 * active. You must call finish() on the span when done. 1443 * 1444 * <p>This will never return null, but on devices without debugging 1445 * enabled, this may return a dummy object on which the finish() 1446 * method is a no-op. 1447 * 1448 * <p>TODO: add CloseGuard to this, verifying callers call finish. 1449 * 1450 * @hide 1451 */ 1452 public static Span enterCriticalSpan(String name) { 1453 if (IS_USER_BUILD) { 1454 return NO_OP_SPAN; 1455 } 1456 if (name == null || name.isEmpty()) { 1457 throw new IllegalArgumentException("name must be non-null and non-empty"); 1458 } 1459 ThreadSpanState state = sThisThreadSpanState.get(); 1460 Span span = null; 1461 synchronized (state) { 1462 if (state.mFreeListHead != null) { 1463 span = state.mFreeListHead; 1464 state.mFreeListHead = span.mNext; 1465 state.mFreeListSize--; 1466 } else { 1467 // Shouldn't have to do this often. 1468 span = new Span(state); 1469 } 1470 span.mName = name; 1471 span.mCreateMillis = SystemClock.uptimeMillis(); 1472 span.mNext = state.mActiveHead; 1473 span.mPrev = null; 1474 state.mActiveHead = span; 1475 state.mActiveSize++; 1476 if (span.mNext != null) { 1477 span.mNext.mPrev = span; 1478 } 1479 if (LOG_V) Log.d(TAG, "Span enter=" + name + "; size=" + state.mActiveSize); 1480 } 1481 return span; 1482 } 1483 1484 1485 /** 1486 * Parcelable that gets sent in Binder call headers back to callers 1487 * to report violations that happened during a cross-process call. 1488 * 1489 * @hide 1490 */ 1491 public static class ViolationInfo { 1492 /** 1493 * Stack and other stuff info. 1494 */ 1495 public final ApplicationErrorReport.CrashInfo crashInfo; 1496 1497 /** 1498 * The strict mode policy mask at the time of violation. 1499 */ 1500 public final int policy; 1501 1502 /** 1503 * The wall time duration of the violation, when known. -1 when 1504 * not known. 1505 */ 1506 public int durationMillis = -1; 1507 1508 /** 1509 * The number of animations currently running. 1510 */ 1511 public int numAnimationsRunning = 0; 1512 1513 /** 1514 * List of tags from active Span instances during this 1515 * violation, or null for none. 1516 */ 1517 public String[] tags; 1518 1519 /** 1520 * Which violation number this was (1-based) since the last Looper loop, 1521 * from the perspective of the root caller (if it crossed any processes 1522 * via Binder calls). The value is 0 if the root caller wasn't on a Looper 1523 * thread. 1524 */ 1525 public int violationNumThisLoop; 1526 1527 /** 1528 * The time (in terms of SystemClock.uptimeMillis()) that the 1529 * violation occurred. 1530 */ 1531 public long violationUptimeMillis; 1532 1533 /** 1534 * The action of the Intent being broadcast to somebody's onReceive 1535 * on this thread right now, or null. 1536 */ 1537 public String broadcastIntentAction; 1538 1539 /** 1540 * Create an uninitialized instance of ViolationInfo 1541 */ 1542 public ViolationInfo() { 1543 crashInfo = null; 1544 policy = 0; 1545 } 1546 1547 /** 1548 * Create an instance of ViolationInfo initialized from an exception. 1549 */ 1550 public ViolationInfo(Throwable tr, int policy) { 1551 crashInfo = new ApplicationErrorReport.CrashInfo(tr); 1552 violationUptimeMillis = SystemClock.uptimeMillis(); 1553 this.policy = policy; 1554 this.numAnimationsRunning = ValueAnimator.getCurrentAnimationsCount(); 1555 Intent broadcastIntent = ActivityThread.getIntentBeingBroadcast(); 1556 if (broadcastIntent != null) { 1557 broadcastIntentAction = broadcastIntent.getAction(); 1558 } 1559 ThreadSpanState state = sThisThreadSpanState.get(); 1560 synchronized (state) { 1561 int spanActiveCount = state.mActiveSize; 1562 if (spanActiveCount > MAX_SPAN_TAGS) { 1563 spanActiveCount = MAX_SPAN_TAGS; 1564 } 1565 if (spanActiveCount != 0) { 1566 this.tags = new String[spanActiveCount]; 1567 Span iter = state.mActiveHead; 1568 int index = 0; 1569 while (iter != null && index < spanActiveCount) { 1570 this.tags[index] = iter.mName; 1571 index++; 1572 iter = iter.mNext; 1573 } 1574 } 1575 } 1576 } 1577 1578 @Override 1579 public int hashCode() { 1580 int result = 17; 1581 result = 37 * result + crashInfo.stackTrace.hashCode(); 1582 if (numAnimationsRunning != 0) { 1583 result *= 37; 1584 } 1585 if (broadcastIntentAction != null) { 1586 result = 37 * result + broadcastIntentAction.hashCode(); 1587 } 1588 if (tags != null) { 1589 for (String tag : tags) { 1590 result = 37 * result + tag.hashCode(); 1591 } 1592 } 1593 return result; 1594 } 1595 1596 /** 1597 * Create an instance of ViolationInfo initialized from a Parcel. 1598 */ 1599 public ViolationInfo(Parcel in) { 1600 this(in, false); 1601 } 1602 1603 /** 1604 * Create an instance of ViolationInfo initialized from a Parcel. 1605 * 1606 * @param unsetGatheringBit if true, the caller is the root caller 1607 * and the gathering penalty should be removed. 1608 */ 1609 public ViolationInfo(Parcel in, boolean unsetGatheringBit) { 1610 crashInfo = new ApplicationErrorReport.CrashInfo(in); 1611 int rawPolicy = in.readInt(); 1612 if (unsetGatheringBit) { 1613 policy = rawPolicy & ~PENALTY_GATHER; 1614 } else { 1615 policy = rawPolicy; 1616 } 1617 durationMillis = in.readInt(); 1618 violationNumThisLoop = in.readInt(); 1619 numAnimationsRunning = in.readInt(); 1620 violationUptimeMillis = in.readLong(); 1621 broadcastIntentAction = in.readString(); 1622 tags = in.readStringArray(); 1623 } 1624 1625 /** 1626 * Save a ViolationInfo instance to a parcel. 1627 */ 1628 public void writeToParcel(Parcel dest, int flags) { 1629 crashInfo.writeToParcel(dest, flags); 1630 dest.writeInt(policy); 1631 dest.writeInt(durationMillis); 1632 dest.writeInt(violationNumThisLoop); 1633 dest.writeInt(numAnimationsRunning); 1634 dest.writeLong(violationUptimeMillis); 1635 dest.writeString(broadcastIntentAction); 1636 dest.writeStringArray(tags); 1637 } 1638 1639 1640 /** 1641 * Dump a ViolationInfo instance to a Printer. 1642 */ 1643 public void dump(Printer pw, String prefix) { 1644 crashInfo.dump(pw, prefix); 1645 pw.println(prefix + "policy: " + policy); 1646 if (durationMillis != -1) { 1647 pw.println(prefix + "durationMillis: " + durationMillis); 1648 } 1649 if (violationNumThisLoop != 0) { 1650 pw.println(prefix + "violationNumThisLoop: " + violationNumThisLoop); 1651 } 1652 if (numAnimationsRunning != 0) { 1653 pw.println(prefix + "numAnimationsRunning: " + numAnimationsRunning); 1654 } 1655 pw.println(prefix + "violationUptimeMillis: " + violationUptimeMillis); 1656 if (broadcastIntentAction != null) { 1657 pw.println(prefix + "broadcastIntentAction: " + broadcastIntentAction); 1658 } 1659 if (tags != null) { 1660 int index = 0; 1661 for (String tag : tags) { 1662 pw.println(prefix + "tag[" + (index++) + "]: " + tag); 1663 } 1664 } 1665 } 1666 1667 } 1668} 1669