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