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