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