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