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