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