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