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