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