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