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