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