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