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