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