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