StrictMode.java revision 5f8b5c191cae77f536ee64f0b625e4a7f8596787
1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16package android.os; 17 18import android.animation.ValueAnimator; 19import android.app.ActivityManagerNative; 20import android.app.ActivityThread; 21import android.app.ApplicationErrorReport; 22import android.app.IActivityManager; 23import android.content.Intent; 24import android.util.Log; 25import android.util.Printer; 26import android.util.Singleton; 27import android.view.IWindowManager; 28 29import com.android.internal.os.RuntimeInit; 30 31import dalvik.system.BlockGuard; 32import dalvik.system.CloseGuard; 33import dalvik.system.VMDebug; 34 35import java.io.PrintWriter; 36import java.io.StringWriter; 37import java.util.ArrayList; 38import java.util.Collections; 39import java.util.HashMap; 40import java.util.Map; 41import java.util.concurrent.atomic.AtomicInteger; 42 43/** 44 * <p>StrictMode is a developer tool which detects things you might be 45 * doing by accident and brings them to your attention so you can fix 46 * them. 47 * 48 * <p>StrictMode is most commonly used to catch accidental disk or 49 * network access on the application's main thread, where UI 50 * operations are received and animations take place. Keeping disk 51 * and network operations off the main thread makes for much smoother, 52 * more responsive applications. By keeping your application's main thread 53 * responsive, you also prevent 54 * <a href="{@docRoot}guide/practices/design/responsiveness.html">ANR dialogs</a> 55 * from being shown to users. 56 * 57 * <p class="note">Note that even though an Android device's disk is 58 * often on flash memory, many devices run a filesystem on top of that 59 * memory with very limited concurrency. It's often the case that 60 * almost all disk accesses are fast, but may in individual cases be 61 * dramatically slower when certain I/O is happening in the background 62 * from other processes. If possible, it's best to assume that such 63 * things are not fast.</p> 64 * 65 * <p>Example code to enable from early in your 66 * {@link android.app.Application}, {@link android.app.Activity}, or 67 * other application component's 68 * {@link android.app.Application#onCreate} method: 69 * 70 * <pre> 71 * public void onCreate() { 72 * if (DEVELOPER_MODE) { 73 * StrictMode.setThreadPolicy(new {@link ThreadPolicy.Builder StrictMode.ThreadPolicy.Builder}() 74 * .detectDiskReads() 75 * .detectDiskWrites() 76 * .detectNetwork() // or .detectAll() for all detectable problems 77 * .penaltyLog() 78 * .build()); 79 * StrictMode.setVmPolicy(new {@link VmPolicy.Builder StrictMode.VmPolicy.Builder}() 80 * .detectLeakedSqlLiteObjects() 81 * .detectLeakedClosableObjects() 82 * .penaltyLog() 83 * .penaltyDeath() 84 * .build()); 85 * } 86 * super.onCreate(); 87 * } 88 * </pre> 89 * 90 * <p>You can decide what should happen when a violation is detected. 91 * For example, using {@link ThreadPolicy.Builder#penaltyLog} you can 92 * watch the output of <code>adb logcat</code> while you use your 93 * application to see the violations as they happen. 94 * 95 * <p>If you find violations that you feel are problematic, there are 96 * a variety of tools to help solve them: threads, {@link android.os.Handler}, 97 * {@link android.os.AsyncTask}, {@link android.app.IntentService}, etc. 98 * But don't feel compelled to fix everything that StrictMode finds. In particular, 99 * many cases of disk access are often necessary during the normal activity lifecycle. Use 100 * StrictMode to find things you did by accident. Network requests on the UI thread 101 * are almost always a problem, though. 102 * 103 * <p class="note">StrictMode is not a security mechanism and is not 104 * guaranteed to find all disk or network accesses. While it does 105 * propagate its state across process boundaries when doing 106 * {@link android.os.Binder} calls, it's still ultimately a best 107 * effort mechanism. Notably, disk or network access from JNI calls 108 * won't necessarily trigger it. Future versions of Android may catch 109 * more (or fewer) operations, so you should never leave StrictMode 110 * enabled in shipping applications on the Android Market. 111 */ 112public final class StrictMode { 113 private static final String TAG = "StrictMode"; 114 private static final boolean LOG_V = Log.isLoggable(TAG, Log.VERBOSE); 115 116 private static final boolean IS_USER_BUILD = "user".equals(Build.TYPE); 117 private static final boolean IS_ENG_BUILD = "eng".equals(Build.TYPE); 118 119 /** 120 * The boolean system property to control screen flashes on violations. 121 * 122 * @hide 123 */ 124 public static final String VISUAL_PROPERTY = "persist.sys.strictmode.visual"; 125 126 // Only log a duplicate stack trace to the logs every second. 127 private static final long MIN_LOG_INTERVAL_MS = 1000; 128 129 // Only show an annoying dialog at most every 30 seconds 130 private static final long MIN_DIALOG_INTERVAL_MS = 30000; 131 132 // How many Span tags (e.g. animations) to report. 133 private static final int MAX_SPAN_TAGS = 20; 134 135 // How many offending stacks to keep track of (and time) per loop 136 // of the Looper. 137 private static final int MAX_OFFENSES_PER_LOOP = 10; 138 139 // Thread-policy: 140 141 /** 142 * @hide 143 */ 144 public static final int DETECT_DISK_WRITE = 0x01; // for ThreadPolicy 145 146 /** 147 * @hide 148 */ 149 public static final int DETECT_DISK_READ = 0x02; // for ThreadPolicy 150 151 /** 152 * @hide 153 */ 154 public static final int DETECT_NETWORK = 0x04; // for ThreadPolicy 155 156 /** 157 * For StrictMode.noteSlowCall() 158 * 159 * @hide 160 */ 161 public static final int DETECT_CUSTOM = 0x08; // for ThreadPolicy 162 163 private static final int ALL_THREAD_DETECT_BITS = 164 DETECT_DISK_WRITE | DETECT_DISK_READ | DETECT_NETWORK | DETECT_CUSTOM; 165 166 // Process-policy: 167 168 /** 169 * Note, a "VM_" bit, not thread. 170 * @hide 171 */ 172 public static final int DETECT_VM_CURSOR_LEAKS = 0x200; // for VmPolicy 173 174 /** 175 * Note, a "VM_" bit, not thread. 176 * @hide 177 */ 178 public static final int DETECT_VM_CLOSABLE_LEAKS = 0x400; // for VmPolicy 179 180 /** 181 * Note, a "VM_" bit, not thread. 182 * @hide 183 */ 184 public static final int DETECT_VM_ACTIVITY_LEAKS = 0x800; // for VmPolicy 185 186 /** 187 * @hide 188 */ 189 private static final int DETECT_VM_INSTANCE_LEAKS = 0x1000; // for VmPolicy 190 191 private static final int ALL_VM_DETECT_BITS = 192 DETECT_VM_CURSOR_LEAKS | DETECT_VM_CLOSABLE_LEAKS | 193 DETECT_VM_ACTIVITY_LEAKS | DETECT_VM_INSTANCE_LEAKS; 194 195 /** 196 * @hide 197 */ 198 public static final int PENALTY_LOG = 0x10; // normal android.util.Log 199 200 // Used for both process and thread policy: 201 202 /** 203 * @hide 204 */ 205 public static final int PENALTY_DIALOG = 0x20; 206 207 /** 208 * Death on any detected violation. 209 * 210 * @hide 211 */ 212 public static final int PENALTY_DEATH = 0x40; 213 214 /** 215 * Death just for detected network usage. 216 * 217 * @hide 218 */ 219 public static final int PENALTY_DEATH_ON_NETWORK = 0x200; 220 221 /** 222 * Flash the screen during violations. 223 * 224 * @hide 225 */ 226 public static final int PENALTY_FLASH = 0x800; 227 228 /** 229 * @hide 230 */ 231 public static final int PENALTY_DROPBOX = 0x80; 232 233 /** 234 * Non-public penalty mode which overrides all the other penalty 235 * bits and signals that we're in a Binder call and we should 236 * ignore the other penalty bits and instead serialize back all 237 * our offending stack traces to the caller to ultimately handle 238 * in the originating process. 239 * 240 * This must be kept in sync with the constant in libs/binder/Parcel.cpp 241 * 242 * @hide 243 */ 244 public static final int PENALTY_GATHER = 0x100; 245 246 /** 247 * Mask of all the penalty bits. 248 */ 249 private static final int PENALTY_MASK = 250 PENALTY_LOG | PENALTY_DIALOG | PENALTY_DEATH | PENALTY_DROPBOX | PENALTY_GATHER | 251 PENALTY_DEATH_ON_NETWORK | PENALTY_FLASH; 252 253 254 // TODO: wrap in some ImmutableHashMap thing. 255 // Note: must be before static initialization of sVmPolicy. 256 private static final HashMap<Class, Integer> EMPTY_CLASS_LIMIT_MAP = new HashMap<Class, Integer>(); 257 258 /** 259 * The current VmPolicy in effect. 260 * 261 * TODO: these are redundant (mask is in VmPolicy). Should remove sVmPolicyMask. 262 */ 263 private static volatile int sVmPolicyMask = 0; 264 private static volatile VmPolicy sVmPolicy = VmPolicy.LAX; 265 266 /** 267 * The number of threads trying to do an async dropbox write. 268 * Just to limit ourselves out of paranoia. 269 */ 270 private static final AtomicInteger sDropboxCallsInFlight = new AtomicInteger(0); 271 272 private StrictMode() {} 273 274 /** 275 * {@link StrictMode} policy applied to a certain thread. 276 * 277 * <p>The policy is enabled by {@link #setThreadPolicy}. The current policy 278 * can be retrieved with {@link #getThreadPolicy}. 279 * 280 * <p>Note that multiple penalties may be provided and they're run 281 * in order from least to most severe (logging before process 282 * death, for example). There's currently no mechanism to choose 283 * different penalties for different detected actions. 284 */ 285 public static final class ThreadPolicy { 286 /** 287 * The default, lax policy which doesn't catch anything. 288 */ 289 public static final ThreadPolicy LAX = new ThreadPolicy(0); 290 291 final int mask; 292 293 private ThreadPolicy(int mask) { 294 this.mask = mask; 295 } 296 297 @Override 298 public String toString() { 299 return "[StrictMode.ThreadPolicy; mask=" + mask + "]"; 300 } 301 302 /** 303 * Creates {@link ThreadPolicy} instances. Methods whose names start 304 * with {@code detect} specify what problems we should look 305 * for. Methods whose names start with {@code penalty} specify what 306 * we should do when we detect a problem. 307 * 308 * <p>You can call as many {@code detect} and {@code penalty} 309 * methods as you like. Currently order is insignificant: all 310 * penalties apply to all detected problems. 311 * 312 * <p>For example, detect everything and log anything that's found: 313 * <pre> 314 * StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder() 315 * .detectAll() 316 * .penaltyLog() 317 * .build(); 318 * StrictMode.setThreadPolicy(policy); 319 * </pre> 320 */ 321 public static final class Builder { 322 private int mMask = 0; 323 324 /** 325 * Create a Builder that detects nothing and has no 326 * violations. (but note that {@link #build} will default 327 * to enabling {@link #penaltyLog} if no other penalties 328 * are specified) 329 */ 330 public Builder() { 331 mMask = 0; 332 } 333 334 /** 335 * Initialize a Builder from an existing ThreadPolicy. 336 */ 337 public Builder(ThreadPolicy policy) { 338 mMask = policy.mask; 339 } 340 341 /** 342 * Detect everything that's potentially suspect. 343 * 344 * <p>As of the Gingerbread release this includes network and 345 * disk operations but will likely expand in future releases. 346 */ 347 public Builder detectAll() { 348 return enable(ALL_THREAD_DETECT_BITS); 349 } 350 351 /** 352 * Disable the detection of everything. 353 */ 354 public Builder permitAll() { 355 return disable(ALL_THREAD_DETECT_BITS); 356 } 357 358 /** 359 * Enable detection of network operations. 360 */ 361 public Builder detectNetwork() { 362 return enable(DETECT_NETWORK); 363 } 364 365 /** 366 * Disable detection of network operations. 367 */ 368 public Builder permitNetwork() { 369 return disable(DETECT_NETWORK); 370 } 371 372 /** 373 * Enable detection of disk reads. 374 */ 375 public Builder detectDiskReads() { 376 return enable(DETECT_DISK_READ); 377 } 378 379 /** 380 * Disable detection of disk reads. 381 */ 382 public Builder permitDiskReads() { 383 return disable(DETECT_DISK_READ); 384 } 385 386 /** 387 * Enable detection of disk reads. 388 */ 389 public Builder detectCustomSlowCalls() { 390 return enable(DETECT_CUSTOM); 391 } 392 393 /** 394 * Enable detection of disk reads. 395 */ 396 public Builder permitCustomSlowCalls() { 397 return enable(DETECT_CUSTOM); 398 } 399 400 /** 401 * Enable detection of disk writes. 402 */ 403 public Builder detectDiskWrites() { 404 return enable(DETECT_DISK_WRITE); 405 } 406 407 /** 408 * Disable detection of disk writes. 409 */ 410 public Builder permitDiskWrites() { 411 return disable(DETECT_DISK_WRITE); 412 } 413 414 /** 415 * Show an annoying dialog to the developer on detected 416 * violations, rate-limited to be only a little annoying. 417 */ 418 public Builder penaltyDialog() { 419 return enable(PENALTY_DIALOG); 420 } 421 422 /** 423 * Crash the whole process on violation. This penalty runs at 424 * the end of all enabled penalties so you'll still get 425 * see logging or other violations before the process dies. 426 * 427 * <p>Unlike {@link #penaltyDeathOnNetwork}, this applies 428 * to disk reads, disk writes, and network usage if their 429 * corresponding detect flags are set. 430 */ 431 public Builder penaltyDeath() { 432 return enable(PENALTY_DEATH); 433 } 434 435 /** 436 * Crash the whole process on any network usage. Unlike 437 * {@link #penaltyDeath}, this penalty runs 438 * <em>before</em> anything else. You must still have 439 * called {@link #detectNetwork} to enable this. 440 * 441 * <p>In the Honeycomb or later SDKs, this is on by default. 442 */ 443 public Builder penaltyDeathOnNetwork() { 444 return enable(PENALTY_DEATH_ON_NETWORK); 445 } 446 447 /** 448 * Flash the screen during a violation. 449 */ 450 public Builder penaltyFlashScreen() { 451 return enable(PENALTY_FLASH); 452 } 453 454 /** 455 * Log detected violations to the system log. 456 */ 457 public Builder penaltyLog() { 458 return enable(PENALTY_LOG); 459 } 460 461 /** 462 * Enable detected violations log a stacktrace and timing data 463 * to the {@link android.os.DropBoxManager DropBox} on policy 464 * violation. Intended mostly for platform integrators doing 465 * beta user field data collection. 466 */ 467 public Builder penaltyDropBox() { 468 return enable(PENALTY_DROPBOX); 469 } 470 471 private Builder enable(int bit) { 472 mMask |= bit; 473 return this; 474 } 475 476 private Builder disable(int bit) { 477 mMask &= ~bit; 478 return this; 479 } 480 481 /** 482 * Construct the ThreadPolicy instance. 483 * 484 * <p>Note: if no penalties are enabled before calling 485 * <code>build</code>, {@link #penaltyLog} is implicitly 486 * set. 487 */ 488 public ThreadPolicy build() { 489 // If there are detection bits set but no violation bits 490 // set, enable simple logging. 491 if (mMask != 0 && 492 (mMask & (PENALTY_DEATH | PENALTY_LOG | 493 PENALTY_DROPBOX | PENALTY_DIALOG)) == 0) { 494 penaltyLog(); 495 } 496 return new ThreadPolicy(mMask); 497 } 498 } 499 } 500 501 /** 502 * {@link StrictMode} policy applied to all threads in the virtual machine's process. 503 * 504 * <p>The policy is enabled by {@link #setVmPolicy}. 505 */ 506 public static final class VmPolicy { 507 /** 508 * The default, lax policy which doesn't catch anything. 509 */ 510 public static final VmPolicy LAX = new VmPolicy(0, EMPTY_CLASS_LIMIT_MAP); 511 512 final int mask; 513 514 // Map from class to max number of allowed instances in memory. 515 final HashMap<Class, Integer> classInstanceLimit; 516 517 private VmPolicy(int mask, HashMap<Class, Integer> classInstanceLimit) { 518 if (classInstanceLimit == null) { 519 throw new NullPointerException("classInstanceLimit == null"); 520 } 521 this.mask = mask; 522 this.classInstanceLimit = classInstanceLimit; 523 } 524 525 @Override 526 public String toString() { 527 return "[StrictMode.VmPolicy; mask=" + mask + "]"; 528 } 529 530 /** 531 * Creates {@link VmPolicy} instances. Methods whose names start 532 * with {@code detect} specify what problems we should look 533 * for. Methods whose names start with {@code penalty} specify what 534 * we should do when we detect a problem. 535 * 536 * <p>You can call as many {@code detect} and {@code penalty} 537 * methods as you like. Currently order is insignificant: all 538 * penalties apply to all detected problems. 539 * 540 * <p>For example, detect everything and log anything that's found: 541 * <pre> 542 * StrictMode.VmPolicy policy = new StrictMode.VmPolicy.Builder() 543 * .detectAll() 544 * .penaltyLog() 545 * .build(); 546 * StrictMode.setVmPolicy(policy); 547 * </pre> 548 */ 549 public static final class Builder { 550 private int mMask; 551 552 private HashMap<Class, Integer> mClassInstanceLimit; // null until needed 553 private boolean mClassInstanceLimitNeedCow = false; // need copy-on-write 554 555 public Builder() { 556 mMask = 0; 557 } 558 559 /** 560 * Build upon an existing VmPolicy. 561 */ 562 public Builder(VmPolicy base) { 563 mMask = base.mask; 564 mClassInstanceLimitNeedCow = true; 565 mClassInstanceLimit = base.classInstanceLimit; 566 } 567 568 /** 569 * Set an upper bound on how many instances of a class can be in memory 570 * at once. Helps to prevent object leaks. 571 */ 572 public Builder setClassInstanceLimit(Class klass, int instanceLimit) { 573 if (klass == null) { 574 throw new NullPointerException("klass == null"); 575 } 576 if (mClassInstanceLimitNeedCow) { 577 if (mClassInstanceLimit.containsKey(klass) && 578 mClassInstanceLimit.get(klass) == instanceLimit) { 579 // no-op; don't break COW 580 return this; 581 } 582 mClassInstanceLimitNeedCow = false; 583 mClassInstanceLimit = (HashMap<Class, Integer>) mClassInstanceLimit.clone(); 584 } else if (mClassInstanceLimit == null) { 585 mClassInstanceLimit = new HashMap<Class, Integer>(); 586 } 587 mMask |= DETECT_VM_INSTANCE_LEAKS; 588 mClassInstanceLimit.put(klass, instanceLimit); 589 return this; 590 } 591 592 /** 593 * Detect leaks of {@link android.app.Activity} subclasses. 594 */ 595 public Builder detectActivityLeaks() { 596 return enable(DETECT_VM_ACTIVITY_LEAKS); 597 } 598 599 /** 600 * Detect everything that's potentially suspect. 601 * 602 * <p>In the Honeycomb release this includes leaks of 603 * SQLite cursors, Activities, and other closable objects 604 * but will likely expand in future releases. 605 */ 606 public Builder detectAll() { 607 return enable(DETECT_VM_ACTIVITY_LEAKS | 608 DETECT_VM_CURSOR_LEAKS | DETECT_VM_CLOSABLE_LEAKS); 609 } 610 611 /** 612 * Detect when an 613 * {@link android.database.sqlite.SQLiteCursor} or other 614 * SQLite object is finalized without having been closed. 615 * 616 * <p>You always want to explicitly close your SQLite 617 * cursors to avoid unnecessary database contention and 618 * temporary memory leaks. 619 */ 620 public Builder detectLeakedSqlLiteObjects() { 621 return enable(DETECT_VM_CURSOR_LEAKS); 622 } 623 624 /** 625 * Detect when an {@link java.io.Closeable} or other 626 * object with a explict termination method is finalized 627 * without having been closed. 628 * 629 * <p>You always want to explicitly close such objects to 630 * avoid unnecessary resources leaks. 631 */ 632 public Builder detectLeakedClosableObjects() { 633 return enable(DETECT_VM_CLOSABLE_LEAKS); 634 } 635 636 /** 637 * Crashes the whole process on violation. This penalty runs at 638 * the end of all enabled penalties so yo you'll still get 639 * your logging or other violations before the process dies. 640 */ 641 public Builder penaltyDeath() { 642 return enable(PENALTY_DEATH); 643 } 644 645 /** 646 * Log detected violations to the system log. 647 */ 648 public Builder penaltyLog() { 649 return enable(PENALTY_LOG); 650 } 651 652 /** 653 * Enable detected violations log a stacktrace and timing data 654 * to the {@link android.os.DropBoxManager DropBox} on policy 655 * violation. Intended mostly for platform integrators doing 656 * beta user field data collection. 657 */ 658 public Builder penaltyDropBox() { 659 return enable(PENALTY_DROPBOX); 660 } 661 662 private Builder enable(int bit) { 663 mMask |= bit; 664 return this; 665 } 666 667 /** 668 * Construct the VmPolicy instance. 669 * 670 * <p>Note: if no penalties are enabled before calling 671 * <code>build</code>, {@link #penaltyLog} is implicitly 672 * set. 673 */ 674 public VmPolicy build() { 675 // If there are detection bits set but no violation bits 676 // set, enable simple logging. 677 if (mMask != 0 && 678 (mMask & (PENALTY_DEATH | PENALTY_LOG | 679 PENALTY_DROPBOX | PENALTY_DIALOG)) == 0) { 680 penaltyLog(); 681 } 682 return new VmPolicy(mMask, 683 mClassInstanceLimit != null ? mClassInstanceLimit : EMPTY_CLASS_LIMIT_MAP); 684 } 685 } 686 } 687 688 /** 689 * Log of strict mode violation stack traces that have occurred 690 * during a Binder call, to be serialized back later to the caller 691 * via Parcel.writeNoException() (amusingly) where the caller can 692 * choose how to react. 693 */ 694 private static final ThreadLocal<ArrayList<ViolationInfo>> gatheredViolations = 695 new ThreadLocal<ArrayList<ViolationInfo>>() { 696 @Override protected ArrayList<ViolationInfo> initialValue() { 697 // Starts null to avoid unnecessary allocations when 698 // checking whether there are any violations or not in 699 // hasGatheredViolations() below. 700 return null; 701 } 702 }; 703 704 /** 705 * Sets the policy for what actions on the current thread should 706 * be detected, as well as the penalty if such actions occur. 707 * 708 * <p>Internally this sets a thread-local variable which is 709 * propagated across cross-process IPC calls, meaning you can 710 * catch violations when a system service or another process 711 * accesses the disk or network on your behalf. 712 * 713 * @param policy the policy to put into place 714 */ 715 public static void setThreadPolicy(final ThreadPolicy policy) { 716 setThreadPolicyMask(policy.mask); 717 } 718 719 private static void setThreadPolicyMask(final int policyMask) { 720 // In addition to the Java-level thread-local in Dalvik's 721 // BlockGuard, we also need to keep a native thread-local in 722 // Binder in order to propagate the value across Binder calls, 723 // even across native-only processes. The two are kept in 724 // sync via the callback to onStrictModePolicyChange, below. 725 setBlockGuardPolicy(policyMask); 726 727 // And set the Android native version... 728 Binder.setThreadStrictModePolicy(policyMask); 729 } 730 731 // Sets the policy in Dalvik/libcore (BlockGuard) 732 private static void setBlockGuardPolicy(final int policyMask) { 733 if (policyMask == 0) { 734 BlockGuard.setThreadPolicy(BlockGuard.LAX_POLICY); 735 return; 736 } 737 BlockGuard.Policy policy = BlockGuard.getThreadPolicy(); 738 if (!(policy instanceof AndroidBlockGuardPolicy)) { 739 BlockGuard.setThreadPolicy(new AndroidBlockGuardPolicy(policyMask)); 740 } else { 741 AndroidBlockGuardPolicy androidPolicy = (AndroidBlockGuardPolicy) policy; 742 androidPolicy.setPolicyMask(policyMask); 743 } 744 } 745 746 // Sets up CloseGuard in Dalvik/libcore 747 private static void setCloseGuardEnabled(boolean enabled) { 748 if (!(CloseGuard.getReporter() instanceof AndroidCloseGuardReporter)) { 749 CloseGuard.setReporter(new AndroidCloseGuardReporter()); 750 } 751 CloseGuard.setEnabled(enabled); 752 } 753 754 /** 755 * @hide 756 */ 757 public static class StrictModeViolation extends BlockGuard.BlockGuardPolicyException { 758 public StrictModeViolation(int policyState, int policyViolated, String message) { 759 super(policyState, policyViolated, message); 760 } 761 } 762 763 /** 764 * @hide 765 */ 766 public static class StrictModeNetworkViolation extends StrictModeViolation { 767 public StrictModeNetworkViolation(int policyMask) { 768 super(policyMask, DETECT_NETWORK, null); 769 } 770 } 771 772 /** 773 * @hide 774 */ 775 private static class StrictModeDiskReadViolation extends StrictModeViolation { 776 public StrictModeDiskReadViolation(int policyMask) { 777 super(policyMask, DETECT_DISK_READ, null); 778 } 779 } 780 781 /** 782 * @hide 783 */ 784 private static class StrictModeDiskWriteViolation extends StrictModeViolation { 785 public StrictModeDiskWriteViolation(int policyMask) { 786 super(policyMask, DETECT_DISK_WRITE, null); 787 } 788 } 789 790 /** 791 * @hide 792 */ 793 private static class StrictModeCustomViolation extends StrictModeViolation { 794 public StrictModeCustomViolation(int policyMask, String name) { 795 super(policyMask, DETECT_CUSTOM, name); 796 } 797 } 798 799 /** 800 * Returns the bitmask of the current thread's policy. 801 * 802 * @return the bitmask of all the DETECT_* and PENALTY_* bits currently enabled 803 * 804 * @hide 805 */ 806 public static int getThreadPolicyMask() { 807 return BlockGuard.getThreadPolicy().getPolicyMask(); 808 } 809 810 /** 811 * Returns the current thread's policy. 812 */ 813 public static ThreadPolicy getThreadPolicy() { 814 // TODO: this was a last minute Gingerbread API change (to 815 // introduce VmPolicy cleanly) but this isn't particularly 816 // optimal for users who might call this method often. This 817 // should be in a thread-local and not allocate on each call. 818 return new ThreadPolicy(getThreadPolicyMask()); 819 } 820 821 /** 822 * A convenience wrapper that takes the current 823 * {@link ThreadPolicy} from {@link #getThreadPolicy}, modifies it 824 * to permit both disk reads & writes, and sets the new policy 825 * with {@link #setThreadPolicy}, returning the old policy so you 826 * can restore it at the end of a block. 827 * 828 * @return the old policy, to be passed to {@link #setThreadPolicy} to 829 * restore the policy at the end of a block 830 */ 831 public static ThreadPolicy allowThreadDiskWrites() { 832 int oldPolicyMask = getThreadPolicyMask(); 833 int newPolicyMask = oldPolicyMask & ~(DETECT_DISK_WRITE | DETECT_DISK_READ); 834 if (newPolicyMask != oldPolicyMask) { 835 setThreadPolicyMask(newPolicyMask); 836 } 837 return new ThreadPolicy(oldPolicyMask); 838 } 839 840 /** 841 * A convenience wrapper that takes the current 842 * {@link ThreadPolicy} from {@link #getThreadPolicy}, modifies it 843 * to permit disk reads, and sets the new policy 844 * with {@link #setThreadPolicy}, returning the old policy so you 845 * can restore it at the end of a block. 846 * 847 * @return the old policy, to be passed to setThreadPolicy to 848 * restore the policy. 849 */ 850 public static ThreadPolicy allowThreadDiskReads() { 851 int oldPolicyMask = getThreadPolicyMask(); 852 int newPolicyMask = oldPolicyMask & ~(DETECT_DISK_READ); 853 if (newPolicyMask != oldPolicyMask) { 854 setThreadPolicyMask(newPolicyMask); 855 } 856 return new ThreadPolicy(oldPolicyMask); 857 } 858 859 // We don't want to flash the screen red in the system server 860 // process, nor do we want to modify all the call sites of 861 // conditionallyEnableDebugLogging() in the system server, 862 // so instead we use this to determine if we are the system server. 863 private static boolean amTheSystemServerProcess() { 864 // Fast path. Most apps don't have the system server's UID. 865 if (Process.myUid() != Process.SYSTEM_UID) { 866 return false; 867 } 868 869 // The settings app, though, has the system server's UID so 870 // look up our stack to see if we came from the system server. 871 Throwable stack = new Throwable(); 872 stack.fillInStackTrace(); 873 for (StackTraceElement ste : stack.getStackTrace()) { 874 String clsName = ste.getClassName(); 875 if (clsName != null && clsName.startsWith("com.android.server.")) { 876 return true; 877 } 878 } 879 return false; 880 } 881 882 /** 883 * Enable DropBox logging for debug phone builds. 884 * 885 * @hide 886 */ 887 public static boolean conditionallyEnableDebugLogging() { 888 boolean doFlashes = !amTheSystemServerProcess() && 889 SystemProperties.getBoolean(VISUAL_PROPERTY, IS_ENG_BUILD); 890 891 // For debug builds, log event loop stalls to dropbox for analysis. 892 // Similar logic also appears in ActivityThread.java for system apps. 893 if (IS_USER_BUILD && !doFlashes) { 894 setCloseGuardEnabled(false); 895 return false; 896 } 897 898 int threadPolicyMask = StrictMode.DETECT_DISK_WRITE | 899 StrictMode.DETECT_DISK_READ | 900 StrictMode.DETECT_NETWORK; 901 902 if (!IS_USER_BUILD) { 903 threadPolicyMask |= StrictMode.PENALTY_DROPBOX; 904 } 905 if (doFlashes) { 906 threadPolicyMask |= StrictMode.PENALTY_FLASH; 907 } 908 909 StrictMode.setThreadPolicyMask(threadPolicyMask); 910 911 if (IS_USER_BUILD) { 912 setCloseGuardEnabled(false); 913 } else { 914 setVmPolicy(new VmPolicy.Builder().detectAll().penaltyDropBox().build()); 915 setCloseGuardEnabled(vmClosableObjectLeaksEnabled()); 916 } 917 return true; 918 } 919 920 /** 921 * Used by the framework to make network usage on the main 922 * thread a fatal error. 923 * 924 * @hide 925 */ 926 public static void enableDeathOnNetwork() { 927 int oldPolicy = getThreadPolicyMask(); 928 int newPolicy = oldPolicy | DETECT_NETWORK | PENALTY_DEATH_ON_NETWORK; 929 setThreadPolicyMask(newPolicy); 930 } 931 932 /** 933 * Parses the BlockGuard policy mask out from the Exception's 934 * getMessage() String value. Kinda gross, but least 935 * invasive. :/ 936 * 937 * Input is of the following forms: 938 * "policy=137 violation=64" 939 * "policy=137 violation=64 msg=Arbitrary text" 940 * 941 * Returns 0 on failure, which is a valid policy, but not a 942 * valid policy during a violation (else there must've been 943 * some policy in effect to violate). 944 */ 945 private static int parsePolicyFromMessage(String message) { 946 if (message == null || !message.startsWith("policy=")) { 947 return 0; 948 } 949 int spaceIndex = message.indexOf(' '); 950 if (spaceIndex == -1) { 951 return 0; 952 } 953 String policyString = message.substring(7, spaceIndex); 954 try { 955 return Integer.valueOf(policyString).intValue(); 956 } catch (NumberFormatException e) { 957 return 0; 958 } 959 } 960 961 /** 962 * Like parsePolicyFromMessage(), but returns the violation. 963 */ 964 private static int parseViolationFromMessage(String message) { 965 if (message == null) { 966 return 0; 967 } 968 int violationIndex = message.indexOf("violation="); 969 if (violationIndex == -1) { 970 return 0; 971 } 972 int numberStartIndex = violationIndex + "violation=".length(); 973 int numberEndIndex = message.indexOf(' ', numberStartIndex); 974 if (numberEndIndex == -1) { 975 numberEndIndex = message.length(); 976 } 977 String violationString = message.substring(numberStartIndex, numberEndIndex); 978 try { 979 return Integer.valueOf(violationString).intValue(); 980 } catch (NumberFormatException e) { 981 return 0; 982 } 983 } 984 985 private static final ThreadLocal<ArrayList<ViolationInfo>> violationsBeingTimed = 986 new ThreadLocal<ArrayList<ViolationInfo>>() { 987 @Override protected ArrayList<ViolationInfo> initialValue() { 988 return new ArrayList<ViolationInfo>(); 989 } 990 }; 991 992 // Note: only access this once verifying the thread has a Looper. 993 private static final ThreadLocal<Handler> threadHandler = new ThreadLocal<Handler>() { 994 @Override protected Handler initialValue() { 995 return new Handler(); 996 } 997 }; 998 999 private static boolean tooManyViolationsThisLoop() { 1000 return violationsBeingTimed.get().size() >= MAX_OFFENSES_PER_LOOP; 1001 } 1002 1003 private static class AndroidBlockGuardPolicy implements BlockGuard.Policy { 1004 private int mPolicyMask; 1005 1006 // Map from violation stacktrace hashcode -> uptimeMillis of 1007 // last violation. No locking needed, as this is only 1008 // accessed by the same thread. 1009 private final HashMap<Integer, Long> mLastViolationTime = new HashMap<Integer, Long>(); 1010 1011 public AndroidBlockGuardPolicy(final int policyMask) { 1012 mPolicyMask = policyMask; 1013 } 1014 1015 @Override 1016 public String toString() { 1017 return "AndroidBlockGuardPolicy; mPolicyMask=" + mPolicyMask; 1018 } 1019 1020 // Part of BlockGuard.Policy interface: 1021 public int getPolicyMask() { 1022 return mPolicyMask; 1023 } 1024 1025 // Part of BlockGuard.Policy interface: 1026 public void onWriteToDisk() { 1027 if ((mPolicyMask & DETECT_DISK_WRITE) == 0) { 1028 return; 1029 } 1030 if (tooManyViolationsThisLoop()) { 1031 return; 1032 } 1033 BlockGuard.BlockGuardPolicyException e = new StrictModeDiskWriteViolation(mPolicyMask); 1034 e.fillInStackTrace(); 1035 startHandlingViolationException(e); 1036 } 1037 1038 // Not part of BlockGuard.Policy; just part of StrictMode: 1039 void onCustomSlowCall(String name) { 1040 if ((mPolicyMask & DETECT_CUSTOM) == 0) { 1041 return; 1042 } 1043 if (tooManyViolationsThisLoop()) { 1044 return; 1045 } 1046 BlockGuard.BlockGuardPolicyException e = new StrictModeCustomViolation(mPolicyMask, name); 1047 e.fillInStackTrace(); 1048 startHandlingViolationException(e); 1049 } 1050 1051 // Part of BlockGuard.Policy interface: 1052 public void onReadFromDisk() { 1053 if ((mPolicyMask & DETECT_DISK_READ) == 0) { 1054 return; 1055 } 1056 if (tooManyViolationsThisLoop()) { 1057 return; 1058 } 1059 BlockGuard.BlockGuardPolicyException e = new StrictModeDiskReadViolation(mPolicyMask); 1060 e.fillInStackTrace(); 1061 startHandlingViolationException(e); 1062 } 1063 1064 // Part of BlockGuard.Policy interface: 1065 public void onNetwork() { 1066 if ((mPolicyMask & DETECT_NETWORK) == 0) { 1067 return; 1068 } 1069 if ((mPolicyMask & PENALTY_DEATH_ON_NETWORK) != 0) { 1070 throw new NetworkOnMainThreadException(); 1071 } 1072 if (tooManyViolationsThisLoop()) { 1073 return; 1074 } 1075 BlockGuard.BlockGuardPolicyException e = new StrictModeNetworkViolation(mPolicyMask); 1076 e.fillInStackTrace(); 1077 startHandlingViolationException(e); 1078 } 1079 1080 public void setPolicyMask(int policyMask) { 1081 mPolicyMask = policyMask; 1082 } 1083 1084 // Start handling a violation that just started and hasn't 1085 // actually run yet (e.g. no disk write or network operation 1086 // has yet occurred). This sees if we're in an event loop 1087 // thread and, if so, uses it to roughly measure how long the 1088 // violation took. 1089 void startHandlingViolationException(BlockGuard.BlockGuardPolicyException e) { 1090 final ViolationInfo info = new ViolationInfo(e, e.getPolicy()); 1091 info.violationUptimeMillis = SystemClock.uptimeMillis(); 1092 handleViolationWithTimingAttempt(info); 1093 } 1094 1095 // Attempts to fill in the provided ViolationInfo's 1096 // durationMillis field if this thread has a Looper we can use 1097 // to measure with. We measure from the time of violation 1098 // until the time the looper is idle again (right before 1099 // the next epoll_wait) 1100 void handleViolationWithTimingAttempt(final ViolationInfo info) { 1101 Looper looper = Looper.myLooper(); 1102 1103 // Without a Looper, we're unable to time how long the 1104 // violation takes place. This case should be rare, as 1105 // most users will care about timing violations that 1106 // happen on their main UI thread. Note that this case is 1107 // also hit when a violation takes place in a Binder 1108 // thread, in "gather" mode. In this case, the duration 1109 // of the violation is computed by the ultimate caller and 1110 // its Looper, if any. 1111 // 1112 // Also, as a special short-cut case when the only penalty 1113 // bit is death, we die immediately, rather than timing 1114 // the violation's duration. This makes it convenient to 1115 // use in unit tests too, rather than waiting on a Looper. 1116 // 1117 // TODO: if in gather mode, ignore Looper.myLooper() and always 1118 // go into this immediate mode? 1119 if (looper == null || 1120 (info.policy & PENALTY_MASK) == PENALTY_DEATH) { 1121 info.durationMillis = -1; // unknown (redundant, already set) 1122 handleViolation(info); 1123 return; 1124 } 1125 1126 final ArrayList<ViolationInfo> records = violationsBeingTimed.get(); 1127 if (records.size() >= MAX_OFFENSES_PER_LOOP) { 1128 // Not worth measuring. Too many offenses in one loop. 1129 return; 1130 } 1131 records.add(info); 1132 if (records.size() > 1) { 1133 // There's already been a violation this loop, so we've already 1134 // registered an idle handler to process the list of violations 1135 // at the end of this Looper's loop. 1136 return; 1137 } 1138 1139 final IWindowManager windowManager = (info.policy & PENALTY_FLASH) != 0 ? 1140 sWindowManager.get() : null; 1141 if (windowManager != null) { 1142 try { 1143 windowManager.showStrictModeViolation(true); 1144 } catch (RemoteException unused) { 1145 } 1146 } 1147 1148 // We post a runnable to a Handler (== delay 0 ms) for 1149 // measuring the end time of a violation instead of using 1150 // an IdleHandler (as was previously used) because an 1151 // IdleHandler may not run for quite a long period of time 1152 // if an ongoing animation is happening and continually 1153 // posting ASAP (0 ms) animation steps. Animations are 1154 // throttled back to 60fps via SurfaceFlinger/View 1155 // invalidates, _not_ by posting frame updates every 16 1156 // milliseconds. 1157 threadHandler.get().post(new Runnable() { 1158 public void run() { 1159 long loopFinishTime = SystemClock.uptimeMillis(); 1160 1161 // Note: we do this early, before handling the 1162 // violation below, as handling the violation 1163 // may include PENALTY_DEATH and we don't want 1164 // to keep the red border on. 1165 if (windowManager != null) { 1166 try { 1167 windowManager.showStrictModeViolation(false); 1168 } catch (RemoteException unused) { 1169 } 1170 } 1171 1172 for (int n = 0; n < records.size(); ++n) { 1173 ViolationInfo v = records.get(n); 1174 v.violationNumThisLoop = n + 1; 1175 v.durationMillis = 1176 (int) (loopFinishTime - v.violationUptimeMillis); 1177 handleViolation(v); 1178 } 1179 records.clear(); 1180 } 1181 }); 1182 } 1183 1184 // Note: It's possible (even quite likely) that the 1185 // thread-local policy mask has changed from the time the 1186 // violation fired and now (after the violating code ran) due 1187 // to people who push/pop temporary policy in regions of code, 1188 // hence the policy being passed around. 1189 void handleViolation(final ViolationInfo info) { 1190 if (info == null || info.crashInfo == null || info.crashInfo.stackTrace == null) { 1191 Log.wtf(TAG, "unexpected null stacktrace"); 1192 return; 1193 } 1194 1195 if (LOG_V) Log.d(TAG, "handleViolation; policy=" + info.policy); 1196 1197 if ((info.policy & PENALTY_GATHER) != 0) { 1198 ArrayList<ViolationInfo> violations = gatheredViolations.get(); 1199 if (violations == null) { 1200 violations = new ArrayList<ViolationInfo>(1); 1201 gatheredViolations.set(violations); 1202 } else if (violations.size() >= 5) { 1203 // Too many. In a loop or something? Don't gather them all. 1204 return; 1205 } 1206 for (ViolationInfo previous : violations) { 1207 if (info.crashInfo.stackTrace.equals(previous.crashInfo.stackTrace)) { 1208 // Duplicate. Don't log. 1209 return; 1210 } 1211 } 1212 violations.add(info); 1213 return; 1214 } 1215 1216 // Not perfect, but fast and good enough for dup suppression. 1217 Integer crashFingerprint = info.hashCode(); 1218 long lastViolationTime = 0; 1219 if (mLastViolationTime.containsKey(crashFingerprint)) { 1220 lastViolationTime = mLastViolationTime.get(crashFingerprint); 1221 } 1222 long now = SystemClock.uptimeMillis(); 1223 mLastViolationTime.put(crashFingerprint, now); 1224 long timeSinceLastViolationMillis = lastViolationTime == 0 ? 1225 Long.MAX_VALUE : (now - lastViolationTime); 1226 1227 if ((info.policy & PENALTY_LOG) != 0 && 1228 timeSinceLastViolationMillis > MIN_LOG_INTERVAL_MS) { 1229 if (info.durationMillis != -1) { 1230 Log.d(TAG, "StrictMode policy violation; ~duration=" + 1231 info.durationMillis + " ms: " + info.crashInfo.stackTrace); 1232 } else { 1233 Log.d(TAG, "StrictMode policy violation: " + info.crashInfo.stackTrace); 1234 } 1235 } 1236 1237 // The violationMaskSubset, passed to ActivityManager, is a 1238 // subset of the original StrictMode policy bitmask, with 1239 // only the bit violated and penalty bits to be executed 1240 // by the ActivityManagerService remaining set. 1241 int violationMaskSubset = 0; 1242 1243 if ((info.policy & PENALTY_DIALOG) != 0 && 1244 timeSinceLastViolationMillis > MIN_DIALOG_INTERVAL_MS) { 1245 violationMaskSubset |= PENALTY_DIALOG; 1246 } 1247 1248 if ((info.policy & PENALTY_DROPBOX) != 0 && lastViolationTime == 0) { 1249 violationMaskSubset |= PENALTY_DROPBOX; 1250 } 1251 1252 if (violationMaskSubset != 0) { 1253 int violationBit = parseViolationFromMessage(info.crashInfo.exceptionMessage); 1254 violationMaskSubset |= violationBit; 1255 final int savedPolicyMask = getThreadPolicyMask(); 1256 1257 final boolean justDropBox = (info.policy & PENALTY_MASK) == PENALTY_DROPBOX; 1258 if (justDropBox) { 1259 // If all we're going to ask the activity manager 1260 // to do is dropbox it (the common case during 1261 // platform development), we can avoid doing this 1262 // call synchronously which Binder data suggests 1263 // isn't always super fast, despite the implementation 1264 // in the ActivityManager trying to be mostly async. 1265 dropboxViolationAsync(violationMaskSubset, info); 1266 return; 1267 } 1268 1269 // Normal synchronous call to the ActivityManager. 1270 try { 1271 // First, remove any policy before we call into the Activity Manager, 1272 // otherwise we'll infinite recurse as we try to log policy violations 1273 // to disk, thus violating policy, thus requiring logging, etc... 1274 // We restore the current policy below, in the finally block. 1275 setThreadPolicyMask(0); 1276 1277 ActivityManagerNative.getDefault().handleApplicationStrictModeViolation( 1278 RuntimeInit.getApplicationObject(), 1279 violationMaskSubset, 1280 info); 1281 } catch (RemoteException e) { 1282 Log.e(TAG, "RemoteException trying to handle StrictMode violation", e); 1283 } finally { 1284 // Restore the policy. 1285 setThreadPolicyMask(savedPolicyMask); 1286 } 1287 } 1288 1289 if ((info.policy & PENALTY_DEATH) != 0) { 1290 executeDeathPenalty(info); 1291 } 1292 } 1293 } 1294 1295 private static void executeDeathPenalty(ViolationInfo info) { 1296 int violationBit = parseViolationFromMessage(info.crashInfo.exceptionMessage); 1297 throw new StrictModeViolation(info.policy, violationBit, null); 1298 } 1299 1300 /** 1301 * In the common case, as set by conditionallyEnableDebugLogging, 1302 * we're just dropboxing any violations but not showing a dialog, 1303 * not loggging, and not killing the process. In these cases we 1304 * don't need to do a synchronous call to the ActivityManager. 1305 * This is used by both per-thread and vm-wide violations when 1306 * applicable. 1307 */ 1308 private static void dropboxViolationAsync( 1309 final int violationMaskSubset, final ViolationInfo info) { 1310 int outstanding = sDropboxCallsInFlight.incrementAndGet(); 1311 if (outstanding > 20) { 1312 // What's going on? Let's not make make the situation 1313 // worse and just not log. 1314 sDropboxCallsInFlight.decrementAndGet(); 1315 return; 1316 } 1317 1318 if (LOG_V) Log.d(TAG, "Dropboxing async; in-flight=" + outstanding); 1319 1320 new Thread("callActivityManagerForStrictModeDropbox") { 1321 public void run() { 1322 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); 1323 try { 1324 IActivityManager am = ActivityManagerNative.getDefault(); 1325 if (am == null) { 1326 Log.d(TAG, "No activity manager; failed to Dropbox violation."); 1327 } else { 1328 am.handleApplicationStrictModeViolation( 1329 RuntimeInit.getApplicationObject(), 1330 violationMaskSubset, 1331 info); 1332 } 1333 } catch (RemoteException e) { 1334 Log.e(TAG, "RemoteException handling StrictMode violation", e); 1335 } 1336 int outstanding = sDropboxCallsInFlight.decrementAndGet(); 1337 if (LOG_V) Log.d(TAG, "Dropbox complete; in-flight=" + outstanding); 1338 } 1339 }.start(); 1340 } 1341 1342 private static class AndroidCloseGuardReporter implements CloseGuard.Reporter { 1343 public void report (String message, Throwable allocationSite) { 1344 onVmPolicyViolation(message, allocationSite); 1345 } 1346 } 1347 1348 /** 1349 * Called from Parcel.writeNoException() 1350 */ 1351 /* package */ static boolean hasGatheredViolations() { 1352 return gatheredViolations.get() != null; 1353 } 1354 1355 /** 1356 * Called from Parcel.writeException(), so we drop this memory and 1357 * don't incorrectly attribute it to the wrong caller on the next 1358 * Binder call on this thread. 1359 */ 1360 /* package */ static void clearGatheredViolations() { 1361 gatheredViolations.set(null); 1362 } 1363 1364 /** 1365 * @hide 1366 */ 1367 public static void conditionallyCheckInstanceCounts() { 1368 VmPolicy policy = getVmPolicy(); 1369 if (policy.classInstanceLimit.size() == 0) { 1370 return; 1371 } 1372 Runtime.getRuntime().gc(); 1373 // Note: classInstanceLimit is immutable, so this is lock-free 1374 for (Map.Entry<Class, Integer> entry : policy.classInstanceLimit.entrySet()) { 1375 Class klass = entry.getKey(); 1376 int limit = entry.getValue(); 1377 long instances = VMDebug.countInstancesOfClass(klass, false); 1378 if (instances <= limit) { 1379 continue; 1380 } 1381 Throwable tr = new InstanceCountViolation(klass, instances, limit); 1382 onVmPolicyViolation(tr.getMessage(), tr); 1383 } 1384 } 1385 1386 private static long sLastInstanceCountCheckMillis = 0; 1387 private static boolean sIsIdlerRegistered = false; // guarded by StrictMode.class 1388 private static final MessageQueue.IdleHandler sProcessIdleHandler = 1389 new MessageQueue.IdleHandler() { 1390 public boolean queueIdle() { 1391 long now = SystemClock.uptimeMillis(); 1392 if (now - sLastInstanceCountCheckMillis > 30 * 1000) { 1393 sLastInstanceCountCheckMillis = now; 1394 conditionallyCheckInstanceCounts(); 1395 } 1396 return true; 1397 } 1398 }; 1399 1400 /** 1401 * Sets the policy for what actions in the VM process (on any 1402 * thread) should be detected, as well as the penalty if such 1403 * actions occur. 1404 * 1405 * @param policy the policy to put into place 1406 */ 1407 public static void setVmPolicy(final VmPolicy policy) { 1408 synchronized (StrictMode.class) { 1409 sVmPolicy = policy; 1410 sVmPolicyMask = policy.mask; 1411 setCloseGuardEnabled(vmClosableObjectLeaksEnabled()); 1412 1413 Looper looper = Looper.getMainLooper(); 1414 if (looper != null) { 1415 MessageQueue mq = looper.mQueue; 1416 if (policy.classInstanceLimit.size() == 0) { 1417 mq.removeIdleHandler(sProcessIdleHandler); 1418 } else if (!sIsIdlerRegistered) { 1419 mq.addIdleHandler(sProcessIdleHandler); 1420 sIsIdlerRegistered = true; 1421 } 1422 } 1423 } 1424 } 1425 1426 /** 1427 * Gets the current VM policy. 1428 */ 1429 public static VmPolicy getVmPolicy() { 1430 synchronized (StrictMode.class) { 1431 return sVmPolicy; 1432 } 1433 } 1434 1435 /** 1436 * Enable the recommended StrictMode defaults, with violations just being logged. 1437 * 1438 * <p>This catches disk and network access on the main thread, as 1439 * well as leaked SQLite cursors and unclosed resources. This is 1440 * simply a wrapper around {@link #setVmPolicy} and {@link 1441 * #setThreadPolicy}. 1442 */ 1443 public static void enableDefaults() { 1444 StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() 1445 .detectAll() 1446 .penaltyLog() 1447 .build()); 1448 StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder() 1449 .detectAll() 1450 .penaltyLog() 1451 .build()); 1452 } 1453 1454 /** 1455 * @hide 1456 */ 1457 public static boolean vmSqliteObjectLeaksEnabled() { 1458 return (sVmPolicyMask & DETECT_VM_CURSOR_LEAKS) != 0; 1459 } 1460 1461 /** 1462 * @hide 1463 */ 1464 public static boolean vmClosableObjectLeaksEnabled() { 1465 return (sVmPolicyMask & DETECT_VM_CLOSABLE_LEAKS) != 0; 1466 } 1467 1468 /** 1469 * @hide 1470 */ 1471 public static void onSqliteObjectLeaked(String message, Throwable originStack) { 1472 onVmPolicyViolation(message, originStack); 1473 } 1474 1475 // Map from VM violation fingerprint to uptime millis. 1476 private static final HashMap<Integer, Long> sLastVmViolationTime = new HashMap<Integer, Long>(); 1477 1478 /** 1479 * @hide 1480 */ 1481 public static void onVmPolicyViolation(String message, Throwable originStack) { 1482 final boolean penaltyDropbox = (sVmPolicyMask & PENALTY_DROPBOX) != 0; 1483 final boolean penaltyDeath = (sVmPolicyMask & PENALTY_DEATH) != 0; 1484 final boolean penaltyLog = (sVmPolicyMask & PENALTY_LOG) != 0; 1485 final ViolationInfo info = new ViolationInfo(originStack, sVmPolicyMask); 1486 1487 // Erase stuff not relevant for process-wide violations 1488 info.numAnimationsRunning = 0; 1489 info.tags = null; 1490 info.broadcastIntentAction = null; 1491 1492 final Integer fingerprint = info.hashCode(); 1493 final long now = SystemClock.uptimeMillis(); 1494 long lastViolationTime = 0; 1495 long timeSinceLastViolationMillis = Long.MAX_VALUE; 1496 synchronized (sLastVmViolationTime) { 1497 if (sLastVmViolationTime.containsKey(fingerprint)) { 1498 lastViolationTime = sLastVmViolationTime.get(fingerprint); 1499 timeSinceLastViolationMillis = now - lastViolationTime; 1500 } 1501 if (timeSinceLastViolationMillis > MIN_LOG_INTERVAL_MS) { 1502 sLastVmViolationTime.put(fingerprint, now); 1503 } 1504 } 1505 1506 if (penaltyLog && timeSinceLastViolationMillis > MIN_LOG_INTERVAL_MS) { 1507 Log.e(TAG, message, originStack); 1508 } 1509 1510 int violationMaskSubset = PENALTY_DROPBOX | (ALL_VM_DETECT_BITS & sVmPolicyMask); 1511 1512 if (penaltyDropbox && !penaltyDeath) { 1513 // Common case for userdebug/eng builds. If no death and 1514 // just dropboxing, we can do the ActivityManager call 1515 // asynchronously. 1516 dropboxViolationAsync(violationMaskSubset, info); 1517 return; 1518 } 1519 1520 if (penaltyDropbox && lastViolationTime == 0) { 1521 // The violationMask, passed to ActivityManager, is a 1522 // subset of the original StrictMode policy bitmask, with 1523 // only the bit violated and penalty bits to be executed 1524 // by the ActivityManagerService remaining set. 1525 final int savedPolicyMask = getThreadPolicyMask(); 1526 try { 1527 // First, remove any policy before we call into the Activity Manager, 1528 // otherwise we'll infinite recurse as we try to log policy violations 1529 // to disk, thus violating policy, thus requiring logging, etc... 1530 // We restore the current policy below, in the finally block. 1531 setThreadPolicyMask(0); 1532 1533 ActivityManagerNative.getDefault().handleApplicationStrictModeViolation( 1534 RuntimeInit.getApplicationObject(), 1535 violationMaskSubset, 1536 info); 1537 } catch (RemoteException e) { 1538 Log.e(TAG, "RemoteException trying to handle StrictMode violation", e); 1539 } finally { 1540 // Restore the policy. 1541 setThreadPolicyMask(savedPolicyMask); 1542 } 1543 } 1544 1545 if (penaltyDeath) { 1546 System.err.println("StrictMode VmPolicy violation with POLICY_DEATH; shutting down."); 1547 Process.killProcess(Process.myPid()); 1548 System.exit(10); 1549 } 1550 } 1551 1552 /** 1553 * Called from Parcel.writeNoException() 1554 */ 1555 /* package */ static void writeGatheredViolationsToParcel(Parcel p) { 1556 ArrayList<ViolationInfo> violations = gatheredViolations.get(); 1557 if (violations == null) { 1558 p.writeInt(0); 1559 } else { 1560 p.writeInt(violations.size()); 1561 for (int i = 0; i < violations.size(); ++i) { 1562 violations.get(i).writeToParcel(p, 0 /* unused flags? */); 1563 } 1564 if (LOG_V) Log.d(TAG, "wrote violations to response parcel; num=" + violations.size()); 1565 violations.clear(); // somewhat redundant, as we're about to null the threadlocal 1566 } 1567 gatheredViolations.set(null); 1568 } 1569 1570 private static class LogStackTrace extends Exception {} 1571 1572 /** 1573 * Called from Parcel.readException() when the exception is EX_STRICT_MODE_VIOLATIONS, 1574 * we here read back all the encoded violations. 1575 */ 1576 /* package */ static void readAndHandleBinderCallViolations(Parcel p) { 1577 // Our own stack trace to append 1578 StringWriter sw = new StringWriter(); 1579 new LogStackTrace().printStackTrace(new PrintWriter(sw)); 1580 String ourStack = sw.toString(); 1581 1582 int policyMask = getThreadPolicyMask(); 1583 boolean currentlyGathering = (policyMask & PENALTY_GATHER) != 0; 1584 1585 int numViolations = p.readInt(); 1586 for (int i = 0; i < numViolations; ++i) { 1587 if (LOG_V) Log.d(TAG, "strict mode violation stacks read from binder call. i=" + i); 1588 ViolationInfo info = new ViolationInfo(p, !currentlyGathering); 1589 info.crashInfo.stackTrace += "# via Binder call with stack:\n" + ourStack; 1590 BlockGuard.Policy policy = BlockGuard.getThreadPolicy(); 1591 if (policy instanceof AndroidBlockGuardPolicy) { 1592 ((AndroidBlockGuardPolicy) policy).handleViolationWithTimingAttempt(info); 1593 } 1594 } 1595 } 1596 1597 /** 1598 * Called from android_util_Binder.cpp's 1599 * android_os_Parcel_enforceInterface when an incoming Binder call 1600 * requires changing the StrictMode policy mask. The role of this 1601 * function is to ask Binder for its current (native) thread-local 1602 * policy value and synchronize it to libcore's (Java) 1603 * thread-local policy value. 1604 */ 1605 private static void onBinderStrictModePolicyChange(int newPolicy) { 1606 setBlockGuardPolicy(newPolicy); 1607 } 1608 1609 /** 1610 * A tracked, critical time span. (e.g. during an animation.) 1611 * 1612 * The object itself is a linked list node, to avoid any allocations 1613 * during rapid span entries and exits. 1614 * 1615 * @hide 1616 */ 1617 public static class Span { 1618 private String mName; 1619 private long mCreateMillis; 1620 private Span mNext; 1621 private Span mPrev; // not used when in freeList, only active 1622 private final ThreadSpanState mContainerState; 1623 1624 Span(ThreadSpanState threadState) { 1625 mContainerState = threadState; 1626 } 1627 1628 // Empty constructor for the NO_OP_SPAN 1629 protected Span() { 1630 mContainerState = null; 1631 } 1632 1633 /** 1634 * To be called when the critical span is complete (i.e. the 1635 * animation is done animating). This can be called on any 1636 * thread (even a different one from where the animation was 1637 * taking place), but that's only a defensive implementation 1638 * measure. It really makes no sense for you to call this on 1639 * thread other than that where you created it. 1640 * 1641 * @hide 1642 */ 1643 public void finish() { 1644 ThreadSpanState state = mContainerState; 1645 synchronized (state) { 1646 if (mName == null) { 1647 // Duplicate finish call. Ignore. 1648 return; 1649 } 1650 1651 // Remove ourselves from the active list. 1652 if (mPrev != null) { 1653 mPrev.mNext = mNext; 1654 } 1655 if (mNext != null) { 1656 mNext.mPrev = mPrev; 1657 } 1658 if (state.mActiveHead == this) { 1659 state.mActiveHead = mNext; 1660 } 1661 1662 state.mActiveSize--; 1663 1664 if (LOG_V) Log.d(TAG, "Span finished=" + mName + "; size=" + state.mActiveSize); 1665 1666 this.mCreateMillis = -1; 1667 this.mName = null; 1668 this.mPrev = null; 1669 this.mNext = null; 1670 1671 // Add ourselves to the freeList, if it's not already 1672 // too big. 1673 if (state.mFreeListSize < 5) { 1674 this.mNext = state.mFreeListHead; 1675 state.mFreeListHead = this; 1676 state.mFreeListSize++; 1677 } 1678 } 1679 } 1680 } 1681 1682 // The no-op span that's used in user builds. 1683 private static final Span NO_OP_SPAN = new Span() { 1684 public void finish() { 1685 // Do nothing. 1686 } 1687 }; 1688 1689 /** 1690 * Linked lists of active spans and a freelist. 1691 * 1692 * Locking notes: there's one of these structures per thread and 1693 * all members of this structure (as well as the Span nodes under 1694 * it) are guarded by the ThreadSpanState object instance. While 1695 * in theory there'd be no locking required because it's all local 1696 * per-thread, the finish() method above is defensive against 1697 * people calling it on a different thread from where they created 1698 * the Span, hence the locking. 1699 */ 1700 private static class ThreadSpanState { 1701 public Span mActiveHead; // doubly-linked list. 1702 public int mActiveSize; 1703 public Span mFreeListHead; // singly-linked list. only changes at head. 1704 public int mFreeListSize; 1705 } 1706 1707 private static final ThreadLocal<ThreadSpanState> sThisThreadSpanState = 1708 new ThreadLocal<ThreadSpanState>() { 1709 @Override protected ThreadSpanState initialValue() { 1710 return new ThreadSpanState(); 1711 } 1712 }; 1713 1714 private static Singleton<IWindowManager> sWindowManager = new Singleton<IWindowManager>() { 1715 protected IWindowManager create() { 1716 return IWindowManager.Stub.asInterface(ServiceManager.getService("window")); 1717 } 1718 }; 1719 1720 /** 1721 * Enter a named critical span (e.g. an animation) 1722 * 1723 * <p>The name is an arbitary label (or tag) that will be applied 1724 * to any strictmode violation that happens while this span is 1725 * active. You must call finish() on the span when done. 1726 * 1727 * <p>This will never return null, but on devices without debugging 1728 * enabled, this may return a dummy object on which the finish() 1729 * method is a no-op. 1730 * 1731 * <p>TODO: add CloseGuard to this, verifying callers call finish. 1732 * 1733 * @hide 1734 */ 1735 public static Span enterCriticalSpan(String name) { 1736 if (IS_USER_BUILD) { 1737 return NO_OP_SPAN; 1738 } 1739 if (name == null || name.isEmpty()) { 1740 throw new IllegalArgumentException("name must be non-null and non-empty"); 1741 } 1742 ThreadSpanState state = sThisThreadSpanState.get(); 1743 Span span = null; 1744 synchronized (state) { 1745 if (state.mFreeListHead != null) { 1746 span = state.mFreeListHead; 1747 state.mFreeListHead = span.mNext; 1748 state.mFreeListSize--; 1749 } else { 1750 // Shouldn't have to do this often. 1751 span = new Span(state); 1752 } 1753 span.mName = name; 1754 span.mCreateMillis = SystemClock.uptimeMillis(); 1755 span.mNext = state.mActiveHead; 1756 span.mPrev = null; 1757 state.mActiveHead = span; 1758 state.mActiveSize++; 1759 if (span.mNext != null) { 1760 span.mNext.mPrev = span; 1761 } 1762 if (LOG_V) Log.d(TAG, "Span enter=" + name + "; size=" + state.mActiveSize); 1763 } 1764 return span; 1765 } 1766 1767 /** 1768 * For code to note that it's slow. This is a no-op unless the 1769 * current thread's {@link android.os.StrictMode.ThreadPolicy} has 1770 * {@link android.os.StrictMode.ThreadPolicy.Builder#detectCustomSlowCalls} 1771 * enabled. 1772 * 1773 * @param name a short string for the exception stack trace that's 1774 * built if when this fires. 1775 */ 1776 public static void noteSlowCall(String name) { 1777 BlockGuard.Policy policy = BlockGuard.getThreadPolicy(); 1778 if (!(policy instanceof AndroidBlockGuardPolicy)) { 1779 // StrictMode not enabled. 1780 return; 1781 } 1782 ((AndroidBlockGuardPolicy) policy).onCustomSlowCall(name); 1783 } 1784 1785 /** 1786 * @hide 1787 */ 1788 public static void noteDiskRead() { 1789 BlockGuard.Policy policy = BlockGuard.getThreadPolicy(); 1790 if (!(policy instanceof AndroidBlockGuardPolicy)) { 1791 // StrictMode not enabled. 1792 return; 1793 } 1794 ((AndroidBlockGuardPolicy) policy).onReadFromDisk(); 1795 } 1796 1797 /** 1798 * @hide 1799 */ 1800 public static void noteDiskWrite() { 1801 BlockGuard.Policy policy = BlockGuard.getThreadPolicy(); 1802 if (!(policy instanceof AndroidBlockGuardPolicy)) { 1803 // StrictMode not enabled. 1804 return; 1805 } 1806 ((AndroidBlockGuardPolicy) policy).onWriteToDisk(); 1807 } 1808 1809 // Guarded by StrictMode.class 1810 private static final HashMap<Class, Integer> sExpectedActivityInstanceCount = 1811 new HashMap<Class, Integer>(); 1812 1813 /** 1814 * @hide 1815 */ 1816 public static void incrementExpectedActivityCount(Class klass) { 1817 if (klass == null || (sVmPolicy.mask & DETECT_VM_ACTIVITY_LEAKS) == 0) { 1818 return; 1819 } 1820 synchronized (StrictMode.class) { 1821 Integer expected = sExpectedActivityInstanceCount.get(klass); 1822 Integer newExpected = expected == null ? 1 : expected + 1; 1823 sExpectedActivityInstanceCount.put(klass, newExpected); 1824 // Note: adding 1 here to give some breathing room during 1825 // orientation changes. (shouldn't be necessary, though?) 1826 setExpectedClassInstanceCount(klass, newExpected + 1); 1827 } 1828 } 1829 1830 /** 1831 * @hide 1832 */ 1833 public static void decrementExpectedActivityCount(Class klass) { 1834 if (klass == null || (sVmPolicy.mask & DETECT_VM_ACTIVITY_LEAKS) == 0) { 1835 return; 1836 } 1837 synchronized (StrictMode.class) { 1838 Integer expected = sExpectedActivityInstanceCount.get(klass); 1839 Integer newExpected = (expected == null || expected == 0) ? 0 : expected - 1; 1840 if (newExpected == 0) { 1841 sExpectedActivityInstanceCount.remove(klass); 1842 } else { 1843 sExpectedActivityInstanceCount.put(klass, newExpected); 1844 } 1845 // Note: adding 1 here to give some breathing room during 1846 // orientation changes. (shouldn't be necessary, though?) 1847 setExpectedClassInstanceCount(klass, newExpected + 1); 1848 } 1849 } 1850 1851 /** 1852 * @hide 1853 */ 1854 public static void setExpectedClassInstanceCount(Class klass, int count) { 1855 synchronized (StrictMode.class) { 1856 setVmPolicy(new VmPolicy.Builder(sVmPolicy) 1857 .setClassInstanceLimit(klass, count) 1858 .build()); 1859 } 1860 } 1861 1862 /** 1863 * Parcelable that gets sent in Binder call headers back to callers 1864 * to report violations that happened during a cross-process call. 1865 * 1866 * @hide 1867 */ 1868 public static class ViolationInfo { 1869 /** 1870 * Stack and other stuff info. 1871 */ 1872 public final ApplicationErrorReport.CrashInfo crashInfo; 1873 1874 /** 1875 * The strict mode policy mask at the time of violation. 1876 */ 1877 public final int policy; 1878 1879 /** 1880 * The wall time duration of the violation, when known. -1 when 1881 * not known. 1882 */ 1883 public int durationMillis = -1; 1884 1885 /** 1886 * The number of animations currently running. 1887 */ 1888 public int numAnimationsRunning = 0; 1889 1890 /** 1891 * List of tags from active Span instances during this 1892 * violation, or null for none. 1893 */ 1894 public String[] tags; 1895 1896 /** 1897 * Which violation number this was (1-based) since the last Looper loop, 1898 * from the perspective of the root caller (if it crossed any processes 1899 * via Binder calls). The value is 0 if the root caller wasn't on a Looper 1900 * thread. 1901 */ 1902 public int violationNumThisLoop; 1903 1904 /** 1905 * The time (in terms of SystemClock.uptimeMillis()) that the 1906 * violation occurred. 1907 */ 1908 public long violationUptimeMillis; 1909 1910 /** 1911 * The action of the Intent being broadcast to somebody's onReceive 1912 * on this thread right now, or null. 1913 */ 1914 public String broadcastIntentAction; 1915 1916 /** 1917 * If this is a instance count violation, the number of instances in memory, 1918 * else -1. 1919 */ 1920 public long numInstances = -1; 1921 1922 /** 1923 * Create an uninitialized instance of ViolationInfo 1924 */ 1925 public ViolationInfo() { 1926 crashInfo = null; 1927 policy = 0; 1928 } 1929 1930 /** 1931 * Create an instance of ViolationInfo initialized from an exception. 1932 */ 1933 public ViolationInfo(Throwable tr, int policy) { 1934 crashInfo = new ApplicationErrorReport.CrashInfo(tr); 1935 violationUptimeMillis = SystemClock.uptimeMillis(); 1936 this.policy = policy; 1937 this.numAnimationsRunning = ValueAnimator.getCurrentAnimationsCount(); 1938 Intent broadcastIntent = ActivityThread.getIntentBeingBroadcast(); 1939 if (broadcastIntent != null) { 1940 broadcastIntentAction = broadcastIntent.getAction(); 1941 } 1942 ThreadSpanState state = sThisThreadSpanState.get(); 1943 if (tr instanceof InstanceCountViolation) { 1944 this.numInstances = ((InstanceCountViolation) tr).mInstances; 1945 } 1946 synchronized (state) { 1947 int spanActiveCount = state.mActiveSize; 1948 if (spanActiveCount > MAX_SPAN_TAGS) { 1949 spanActiveCount = MAX_SPAN_TAGS; 1950 } 1951 if (spanActiveCount != 0) { 1952 this.tags = new String[spanActiveCount]; 1953 Span iter = state.mActiveHead; 1954 int index = 0; 1955 while (iter != null && index < spanActiveCount) { 1956 this.tags[index] = iter.mName; 1957 index++; 1958 iter = iter.mNext; 1959 } 1960 } 1961 } 1962 } 1963 1964 @Override 1965 public int hashCode() { 1966 int result = 17; 1967 result = 37 * result + crashInfo.stackTrace.hashCode(); 1968 if (numAnimationsRunning != 0) { 1969 result *= 37; 1970 } 1971 if (broadcastIntentAction != null) { 1972 result = 37 * result + broadcastIntentAction.hashCode(); 1973 } 1974 if (tags != null) { 1975 for (String tag : tags) { 1976 result = 37 * result + tag.hashCode(); 1977 } 1978 } 1979 return result; 1980 } 1981 1982 /** 1983 * Create an instance of ViolationInfo initialized from a Parcel. 1984 */ 1985 public ViolationInfo(Parcel in) { 1986 this(in, false); 1987 } 1988 1989 /** 1990 * Create an instance of ViolationInfo initialized from a Parcel. 1991 * 1992 * @param unsetGatheringBit if true, the caller is the root caller 1993 * and the gathering penalty should be removed. 1994 */ 1995 public ViolationInfo(Parcel in, boolean unsetGatheringBit) { 1996 crashInfo = new ApplicationErrorReport.CrashInfo(in); 1997 int rawPolicy = in.readInt(); 1998 if (unsetGatheringBit) { 1999 policy = rawPolicy & ~PENALTY_GATHER; 2000 } else { 2001 policy = rawPolicy; 2002 } 2003 durationMillis = in.readInt(); 2004 violationNumThisLoop = in.readInt(); 2005 numAnimationsRunning = in.readInt(); 2006 violationUptimeMillis = in.readLong(); 2007 numInstances = in.readLong(); 2008 broadcastIntentAction = in.readString(); 2009 tags = in.readStringArray(); 2010 } 2011 2012 /** 2013 * Save a ViolationInfo instance to a parcel. 2014 */ 2015 public void writeToParcel(Parcel dest, int flags) { 2016 crashInfo.writeToParcel(dest, flags); 2017 dest.writeInt(policy); 2018 dest.writeInt(durationMillis); 2019 dest.writeInt(violationNumThisLoop); 2020 dest.writeInt(numAnimationsRunning); 2021 dest.writeLong(violationUptimeMillis); 2022 dest.writeLong(numInstances); 2023 dest.writeString(broadcastIntentAction); 2024 dest.writeStringArray(tags); 2025 } 2026 2027 2028 /** 2029 * Dump a ViolationInfo instance to a Printer. 2030 */ 2031 public void dump(Printer pw, String prefix) { 2032 crashInfo.dump(pw, prefix); 2033 pw.println(prefix + "policy: " + policy); 2034 if (durationMillis != -1) { 2035 pw.println(prefix + "durationMillis: " + durationMillis); 2036 } 2037 if (numInstances != -1) { 2038 pw.println(prefix + "numInstances: " + numInstances); 2039 } 2040 if (violationNumThisLoop != 0) { 2041 pw.println(prefix + "violationNumThisLoop: " + violationNumThisLoop); 2042 } 2043 if (numAnimationsRunning != 0) { 2044 pw.println(prefix + "numAnimationsRunning: " + numAnimationsRunning); 2045 } 2046 pw.println(prefix + "violationUptimeMillis: " + violationUptimeMillis); 2047 if (broadcastIntentAction != null) { 2048 pw.println(prefix + "broadcastIntentAction: " + broadcastIntentAction); 2049 } 2050 if (tags != null) { 2051 int index = 0; 2052 for (String tag : tags) { 2053 pw.println(prefix + "tag[" + (index++) + "]: " + tag); 2054 } 2055 } 2056 } 2057 2058 } 2059 2060 // Dummy throwable, for now, since we don't know when or where the 2061 // leaked instances came from. We might in the future, but for 2062 // now we suppress the stack trace because it's useless and/or 2063 // misleading. 2064 private static class InstanceCountViolation extends Throwable { 2065 final Class mClass; 2066 final long mInstances; 2067 final int mLimit; 2068 2069 private static final StackTraceElement[] FAKE_STACK = { 2070 new StackTraceElement("android.os.StrictMode", "setClassInstanceLimit", 2071 "StrictMode.java", 1) 2072 }; 2073 2074 public InstanceCountViolation(Class klass, long instances, int limit) { 2075 super(klass.toString() + "; instances=" + instances + "; limit=" + limit); 2076 setStackTrace(FAKE_STACK); 2077 mClass = klass; 2078 mInstances = instances; 2079 mLimit = limit; 2080 } 2081 } 2082} 2083