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