1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package android.os; 17 18 import android.animation.ValueAnimator; 19 import android.app.ActivityManagerNative; 20 import android.app.ActivityThread; 21 import android.app.ApplicationErrorReport; 22 import android.app.IActivityManager; 23 import android.content.BroadcastReceiver; 24 import android.content.Context; 25 import android.content.Intent; 26 import android.content.ServiceConnection; 27 import android.util.ArrayMap; 28 import android.util.Log; 29 import android.util.Printer; 30 import android.util.Singleton; 31 import android.util.Slog; 32 import android.view.IWindowManager; 33 34 import com.android.internal.os.RuntimeInit; 35 36 import com.android.internal.util.FastPrintWriter; 37 import dalvik.system.BlockGuard; 38 import dalvik.system.CloseGuard; 39 import dalvik.system.VMDebug; 40 41 import java.io.PrintWriter; 42 import java.io.StringWriter; 43 import java.util.ArrayList; 44 import java.util.Arrays; 45 import java.util.HashMap; 46 import java.util.Map; 47 import 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 */ 118 public 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 StrictMode()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 ThreadPolicy(int mask)325 private ThreadPolicy(int mask) { 326 this.mask = mask; 327 } 328 329 @Override toString()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 */ Builder()362 public Builder() { 363 mMask = 0; 364 } 365 366 /** 367 * Initialize a Builder from an existing ThreadPolicy. 368 */ Builder(ThreadPolicy policy)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 */ detectAll()379 public Builder detectAll() { 380 return enable(ALL_THREAD_DETECT_BITS); 381 } 382 383 /** 384 * Disable the detection of everything. 385 */ permitAll()386 public Builder permitAll() { 387 return disable(ALL_THREAD_DETECT_BITS); 388 } 389 390 /** 391 * Enable detection of network operations. 392 */ detectNetwork()393 public Builder detectNetwork() { 394 return enable(DETECT_NETWORK); 395 } 396 397 /** 398 * Disable detection of network operations. 399 */ permitNetwork()400 public Builder permitNetwork() { 401 return disable(DETECT_NETWORK); 402 } 403 404 /** 405 * Enable detection of disk reads. 406 */ detectDiskReads()407 public Builder detectDiskReads() { 408 return enable(DETECT_DISK_READ); 409 } 410 411 /** 412 * Disable detection of disk reads. 413 */ permitDiskReads()414 public Builder permitDiskReads() { 415 return disable(DETECT_DISK_READ); 416 } 417 418 /** 419 * Enable detection of slow calls. 420 */ detectCustomSlowCalls()421 public Builder detectCustomSlowCalls() { 422 return enable(DETECT_CUSTOM); 423 } 424 425 /** 426 * Disable detection of slow calls. 427 */ permitCustomSlowCalls()428 public Builder permitCustomSlowCalls() { 429 return disable(DETECT_CUSTOM); 430 } 431 432 /** 433 * Enable detection of disk writes. 434 */ detectDiskWrites()435 public Builder detectDiskWrites() { 436 return enable(DETECT_DISK_WRITE); 437 } 438 439 /** 440 * Disable detection of disk writes. 441 */ permitDiskWrites()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 */ penaltyDialog()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 */ penaltyDeath()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 */ penaltyDeathOnNetwork()475 public Builder penaltyDeathOnNetwork() { 476 return enable(PENALTY_DEATH_ON_NETWORK); 477 } 478 479 /** 480 * Flash the screen during a violation. 481 */ penaltyFlashScreen()482 public Builder penaltyFlashScreen() { 483 return enable(PENALTY_FLASH); 484 } 485 486 /** 487 * Log detected violations to the system log. 488 */ penaltyLog()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 */ penaltyDropBox()499 public Builder penaltyDropBox() { 500 return enable(PENALTY_DROPBOX); 501 } 502 enable(int bit)503 private Builder enable(int bit) { 504 mMask |= bit; 505 return this; 506 } 507 disable(int bit)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 */ build()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 VmPolicy(int mask, HashMap<Class, Integer> classInstanceLimit)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 toString()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 Builder()587 public Builder() { 588 mMask = 0; 589 } 590 591 /** 592 * Build upon an existing VmPolicy. 593 */ Builder(VmPolicy base)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 */ setClassInstanceLimit(Class klass, int instanceLimit)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 */ detectActivityLeaks()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 */ detectAll()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 */ detectLeakedSqlLiteObjects()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 */ detectLeakedClosableObjects()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 */ detectLeakedRegistrationObjects()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 */ detectFileUriExposure()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 */ penaltyDeath()693 public Builder penaltyDeath() { 694 return enable(PENALTY_DEATH); 695 } 696 697 /** 698 * Log detected violations to the system log. 699 */ penaltyLog()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 */ penaltyDropBox()710 public Builder penaltyDropBox() { 711 return enable(PENALTY_DROPBOX); 712 } 713 enable(int bit)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 */ build()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 */ setThreadPolicy(final ThreadPolicy policy)767 public static void setThreadPolicy(final ThreadPolicy policy) { 768 setThreadPolicyMask(policy.mask); 769 } 770 setThreadPolicyMask(final int policyMask)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) setBlockGuardPolicy(final int policyMask)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 setCloseGuardEnabled(boolean enabled)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 { StrictModeViolation(int policyState, int policyViolated, String message)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 { StrictModeNetworkViolation(int policyMask)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 { StrictModeDiskReadViolation(int policyMask)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 { StrictModeDiskWriteViolation(int policyMask)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 { StrictModeCustomViolation(int policyMask, String name)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 */ getThreadPolicyMask()860 public static int getThreadPolicyMask() { 861 return BlockGuard.getThreadPolicy().getPolicyMask(); 862 } 863 864 /** 865 * Returns the current thread's policy. 866 */ getThreadPolicy()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 */ allowThreadDiskWrites()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 */ allowThreadDiskReads()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. amTheSystemServerProcess()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 */ conditionallyEnableDebugLogging()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 */ enableDeathOnNetwork()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 */ parsePolicyFromMessage(String message)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 */ parseViolationFromMessage(String message)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 tooManyViolationsThisLoop()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 AndroidBlockGuardPolicy(final int policyMask)1088 public AndroidBlockGuardPolicy(final int policyMask) { 1089 mPolicyMask = policyMask; 1090 } 1091 1092 @Override toString()1093 public String toString() { 1094 return "AndroidBlockGuardPolicy; mPolicyMask=" + mPolicyMask; 1095 } 1096 1097 // Part of BlockGuard.Policy interface: getPolicyMask()1098 public int getPolicyMask() { 1099 return mPolicyMask; 1100 } 1101 1102 // Part of BlockGuard.Policy interface: onWriteToDisk()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: onCustomSlowCall(String name)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: onReadFromDisk()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: onNetwork()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 setPolicyMask(int policyMask)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. startHandlingViolationException(BlockGuard.BlockGuardPolicyException e)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) handleViolationWithTimingAttempt(final ViolationInfo info)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. handleViolation(final ViolationInfo info)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 executeDeathPenalty(ViolationInfo info)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 */ dropboxViolationAsync( final int violationMaskSubset, final ViolationInfo info)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 { report(String message, Throwable allocationSite)1425 public void report (String message, Throwable allocationSite) { 1426 onVmPolicyViolation(message, allocationSite); 1427 } 1428 } 1429 1430 /** 1431 * Called from Parcel.writeNoException() 1432 */ hasGatheredViolations()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 */ clearGatheredViolations()1442 /* package */ static void clearGatheredViolations() { 1443 gatheredViolations.set(null); 1444 } 1445 1446 /** 1447 * @hide 1448 */ conditionallyCheckInstanceCounts()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 */ setVmPolicy(final VmPolicy policy)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 */ getVmPolicy()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 */ enableDefaults()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 */ vmSqliteObjectLeaksEnabled()1545 public static boolean vmSqliteObjectLeaksEnabled() { 1546 return (sVmPolicyMask & DETECT_VM_CURSOR_LEAKS) != 0; 1547 } 1548 1549 /** 1550 * @hide 1551 */ vmClosableObjectLeaksEnabled()1552 public static boolean vmClosableObjectLeaksEnabled() { 1553 return (sVmPolicyMask & DETECT_VM_CLOSABLE_LEAKS) != 0; 1554 } 1555 1556 /** 1557 * @hide 1558 */ vmRegistrationLeaksEnabled()1559 public static boolean vmRegistrationLeaksEnabled() { 1560 return (sVmPolicyMask & DETECT_VM_REGISTRATION_LEAKS) != 0; 1561 } 1562 1563 /** 1564 * @hide 1565 */ vmFileUriExposureEnabled()1566 public static boolean vmFileUriExposureEnabled() { 1567 return (sVmPolicyMask & DETECT_VM_FILE_URI_EXPOSURE) != 0; 1568 } 1569 1570 /** 1571 * @hide 1572 */ onSqliteObjectLeaked(String message, Throwable originStack)1573 public static void onSqliteObjectLeaked(String message, Throwable originStack) { 1574 onVmPolicyViolation(message, originStack); 1575 } 1576 1577 /** 1578 * @hide 1579 */ onWebViewMethodCalledOnWrongThread(Throwable originStack)1580 public static void onWebViewMethodCalledOnWrongThread(Throwable originStack) { 1581 onVmPolicyViolation(null, originStack); 1582 } 1583 1584 /** 1585 * @hide 1586 */ onIntentReceiverLeaked(Throwable originStack)1587 public static void onIntentReceiverLeaked(Throwable originStack) { 1588 onVmPolicyViolation(null, originStack); 1589 } 1590 1591 /** 1592 * @hide 1593 */ onServiceConnectionLeaked(Throwable originStack)1594 public static void onServiceConnectionLeaked(Throwable originStack) { 1595 onVmPolicyViolation(null, originStack); 1596 } 1597 1598 /** 1599 * @hide 1600 */ onFileUriExposed(String location)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 */ onVmPolicyViolation(String message, Throwable originStack)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 */ writeGatheredViolationsToParcel(Parcel p)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 */ readAndHandleBinderCallViolations(Parcel p)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 != null && info.crashInfo.stackTrace.length() > 10000) { 1729 String front = info.crashInfo.stackTrace.substring(256); 1730 // 10000 characters is way too large for this to be any sane kind of 1731 // strict mode collection of stacks. We've had a problem where we leave 1732 // strict mode violations associated with the thread, and it keeps tacking 1733 // more and more stacks on to the violations. Looks like we're in this casse, 1734 // so we'll report it and bail on all of the current strict mode violations 1735 // we currently are maintaining for this thread. 1736 // First, drain the remaining violations from the parcel. 1737 while (i < numViolations) { 1738 info = new ViolationInfo(p, !currentlyGathering); 1739 i++; 1740 } 1741 // Next clear out all gathered violations. 1742 clearGatheredViolations(); 1743 // Now report the problem. 1744 Slog.wtfStack(TAG, "Stack is too large: numViolations=" + numViolations 1745 + " policy=#" + Integer.toHexString(policyMask) 1746 + " front=" + front); 1747 return; 1748 } 1749 info.crashInfo.stackTrace += "# via Binder call with stack:\n" + ourStack; 1750 BlockGuard.Policy policy = BlockGuard.getThreadPolicy(); 1751 if (policy instanceof AndroidBlockGuardPolicy) { 1752 ((AndroidBlockGuardPolicy) policy).handleViolationWithTimingAttempt(info); 1753 } 1754 } 1755 } 1756 1757 /** 1758 * Called from android_util_Binder.cpp's 1759 * android_os_Parcel_enforceInterface when an incoming Binder call 1760 * requires changing the StrictMode policy mask. The role of this 1761 * function is to ask Binder for its current (native) thread-local 1762 * policy value and synchronize it to libcore's (Java) 1763 * thread-local policy value. 1764 */ onBinderStrictModePolicyChange(int newPolicy)1765 private static void onBinderStrictModePolicyChange(int newPolicy) { 1766 setBlockGuardPolicy(newPolicy); 1767 } 1768 1769 /** 1770 * A tracked, critical time span. (e.g. during an animation.) 1771 * 1772 * The object itself is a linked list node, to avoid any allocations 1773 * during rapid span entries and exits. 1774 * 1775 * @hide 1776 */ 1777 public static class Span { 1778 private String mName; 1779 private long mCreateMillis; 1780 private Span mNext; 1781 private Span mPrev; // not used when in freeList, only active 1782 private final ThreadSpanState mContainerState; 1783 Span(ThreadSpanState threadState)1784 Span(ThreadSpanState threadState) { 1785 mContainerState = threadState; 1786 } 1787 1788 // Empty constructor for the NO_OP_SPAN Span()1789 protected Span() { 1790 mContainerState = null; 1791 } 1792 1793 /** 1794 * To be called when the critical span is complete (i.e. the 1795 * animation is done animating). This can be called on any 1796 * thread (even a different one from where the animation was 1797 * taking place), but that's only a defensive implementation 1798 * measure. It really makes no sense for you to call this on 1799 * thread other than that where you created it. 1800 * 1801 * @hide 1802 */ finish()1803 public void finish() { 1804 ThreadSpanState state = mContainerState; 1805 synchronized (state) { 1806 if (mName == null) { 1807 // Duplicate finish call. Ignore. 1808 return; 1809 } 1810 1811 // Remove ourselves from the active list. 1812 if (mPrev != null) { 1813 mPrev.mNext = mNext; 1814 } 1815 if (mNext != null) { 1816 mNext.mPrev = mPrev; 1817 } 1818 if (state.mActiveHead == this) { 1819 state.mActiveHead = mNext; 1820 } 1821 1822 state.mActiveSize--; 1823 1824 if (LOG_V) Log.d(TAG, "Span finished=" + mName + "; size=" + state.mActiveSize); 1825 1826 this.mCreateMillis = -1; 1827 this.mName = null; 1828 this.mPrev = null; 1829 this.mNext = null; 1830 1831 // Add ourselves to the freeList, if it's not already 1832 // too big. 1833 if (state.mFreeListSize < 5) { 1834 this.mNext = state.mFreeListHead; 1835 state.mFreeListHead = this; 1836 state.mFreeListSize++; 1837 } 1838 } 1839 } 1840 } 1841 1842 // The no-op span that's used in user builds. 1843 private static final Span NO_OP_SPAN = new Span() { 1844 public void finish() { 1845 // Do nothing. 1846 } 1847 }; 1848 1849 /** 1850 * Linked lists of active spans and a freelist. 1851 * 1852 * Locking notes: there's one of these structures per thread and 1853 * all members of this structure (as well as the Span nodes under 1854 * it) are guarded by the ThreadSpanState object instance. While 1855 * in theory there'd be no locking required because it's all local 1856 * per-thread, the finish() method above is defensive against 1857 * people calling it on a different thread from where they created 1858 * the Span, hence the locking. 1859 */ 1860 private static class ThreadSpanState { 1861 public Span mActiveHead; // doubly-linked list. 1862 public int mActiveSize; 1863 public Span mFreeListHead; // singly-linked list. only changes at head. 1864 public int mFreeListSize; 1865 } 1866 1867 private static final ThreadLocal<ThreadSpanState> sThisThreadSpanState = 1868 new ThreadLocal<ThreadSpanState>() { 1869 @Override protected ThreadSpanState initialValue() { 1870 return new ThreadSpanState(); 1871 } 1872 }; 1873 1874 private static Singleton<IWindowManager> sWindowManager = new Singleton<IWindowManager>() { 1875 protected IWindowManager create() { 1876 return IWindowManager.Stub.asInterface(ServiceManager.getService("window")); 1877 } 1878 }; 1879 1880 /** 1881 * Enter a named critical span (e.g. an animation) 1882 * 1883 * <p>The name is an arbitary label (or tag) that will be applied 1884 * to any strictmode violation that happens while this span is 1885 * active. You must call finish() on the span when done. 1886 * 1887 * <p>This will never return null, but on devices without debugging 1888 * enabled, this may return a dummy object on which the finish() 1889 * method is a no-op. 1890 * 1891 * <p>TODO: add CloseGuard to this, verifying callers call finish. 1892 * 1893 * @hide 1894 */ enterCriticalSpan(String name)1895 public static Span enterCriticalSpan(String name) { 1896 if (IS_USER_BUILD) { 1897 return NO_OP_SPAN; 1898 } 1899 if (name == null || name.isEmpty()) { 1900 throw new IllegalArgumentException("name must be non-null and non-empty"); 1901 } 1902 ThreadSpanState state = sThisThreadSpanState.get(); 1903 Span span = null; 1904 synchronized (state) { 1905 if (state.mFreeListHead != null) { 1906 span = state.mFreeListHead; 1907 state.mFreeListHead = span.mNext; 1908 state.mFreeListSize--; 1909 } else { 1910 // Shouldn't have to do this often. 1911 span = new Span(state); 1912 } 1913 span.mName = name; 1914 span.mCreateMillis = SystemClock.uptimeMillis(); 1915 span.mNext = state.mActiveHead; 1916 span.mPrev = null; 1917 state.mActiveHead = span; 1918 state.mActiveSize++; 1919 if (span.mNext != null) { 1920 span.mNext.mPrev = span; 1921 } 1922 if (LOG_V) Log.d(TAG, "Span enter=" + name + "; size=" + state.mActiveSize); 1923 } 1924 return span; 1925 } 1926 1927 /** 1928 * For code to note that it's slow. This is a no-op unless the 1929 * current thread's {@link android.os.StrictMode.ThreadPolicy} has 1930 * {@link android.os.StrictMode.ThreadPolicy.Builder#detectCustomSlowCalls} 1931 * enabled. 1932 * 1933 * @param name a short string for the exception stack trace that's 1934 * built if when this fires. 1935 */ noteSlowCall(String name)1936 public static void noteSlowCall(String name) { 1937 BlockGuard.Policy policy = BlockGuard.getThreadPolicy(); 1938 if (!(policy instanceof AndroidBlockGuardPolicy)) { 1939 // StrictMode not enabled. 1940 return; 1941 } 1942 ((AndroidBlockGuardPolicy) policy).onCustomSlowCall(name); 1943 } 1944 1945 /** 1946 * @hide 1947 */ noteDiskRead()1948 public static void noteDiskRead() { 1949 BlockGuard.Policy policy = BlockGuard.getThreadPolicy(); 1950 if (!(policy instanceof AndroidBlockGuardPolicy)) { 1951 // StrictMode not enabled. 1952 return; 1953 } 1954 ((AndroidBlockGuardPolicy) policy).onReadFromDisk(); 1955 } 1956 1957 /** 1958 * @hide 1959 */ noteDiskWrite()1960 public static void noteDiskWrite() { 1961 BlockGuard.Policy policy = BlockGuard.getThreadPolicy(); 1962 if (!(policy instanceof AndroidBlockGuardPolicy)) { 1963 // StrictMode not enabled. 1964 return; 1965 } 1966 ((AndroidBlockGuardPolicy) policy).onWriteToDisk(); 1967 } 1968 1969 // Guarded by StrictMode.class 1970 private static final HashMap<Class, Integer> sExpectedActivityInstanceCount = 1971 new HashMap<Class, Integer>(); 1972 1973 /** 1974 * Returns an object that is used to track instances of activites. 1975 * The activity should store a reference to the tracker object in one of its fields. 1976 * @hide 1977 */ trackActivity(Object instance)1978 public static Object trackActivity(Object instance) { 1979 return new InstanceTracker(instance); 1980 } 1981 1982 /** 1983 * @hide 1984 */ incrementExpectedActivityCount(Class klass)1985 public static void incrementExpectedActivityCount(Class klass) { 1986 if (klass == null) { 1987 return; 1988 } 1989 1990 synchronized (StrictMode.class) { 1991 if ((sVmPolicy.mask & DETECT_VM_ACTIVITY_LEAKS) == 0) { 1992 return; 1993 } 1994 1995 Integer expected = sExpectedActivityInstanceCount.get(klass); 1996 Integer newExpected = expected == null ? 1 : expected + 1; 1997 sExpectedActivityInstanceCount.put(klass, newExpected); 1998 } 1999 } 2000 2001 /** 2002 * @hide 2003 */ decrementExpectedActivityCount(Class klass)2004 public static void decrementExpectedActivityCount(Class klass) { 2005 if (klass == null) { 2006 return; 2007 } 2008 2009 final int limit; 2010 synchronized (StrictMode.class) { 2011 if ((sVmPolicy.mask & DETECT_VM_ACTIVITY_LEAKS) == 0) { 2012 return; 2013 } 2014 2015 Integer expected = sExpectedActivityInstanceCount.get(klass); 2016 int newExpected = (expected == null || expected == 0) ? 0 : expected - 1; 2017 if (newExpected == 0) { 2018 sExpectedActivityInstanceCount.remove(klass); 2019 } else { 2020 sExpectedActivityInstanceCount.put(klass, newExpected); 2021 } 2022 2023 // Note: adding 1 here to give some breathing room during 2024 // orientation changes. (shouldn't be necessary, though?) 2025 limit = newExpected + 1; 2026 } 2027 2028 // Quick check. 2029 int actual = InstanceTracker.getInstanceCount(klass); 2030 if (actual <= limit) { 2031 return; 2032 } 2033 2034 // Do a GC and explicit count to double-check. 2035 // This is the work that we are trying to avoid by tracking the object instances 2036 // explicity. Running an explicit GC can be expensive (80ms) and so can walking 2037 // the heap to count instance (30ms). This extra work can make the system feel 2038 // noticeably less responsive during orientation changes when activities are 2039 // being restarted. Granted, it is only a problem when StrictMode is enabled 2040 // but it is annoying. 2041 2042 System.gc(); 2043 System.runFinalization(); 2044 System.gc(); 2045 2046 long instances = VMDebug.countInstancesOfClass(klass, false); 2047 if (instances > limit) { 2048 Throwable tr = new InstanceCountViolation(klass, instances, limit); 2049 onVmPolicyViolation(tr.getMessage(), tr); 2050 } 2051 } 2052 2053 /** 2054 * Parcelable that gets sent in Binder call headers back to callers 2055 * to report violations that happened during a cross-process call. 2056 * 2057 * @hide 2058 */ 2059 public static class ViolationInfo { 2060 /** 2061 * Stack and other stuff info. 2062 */ 2063 public final ApplicationErrorReport.CrashInfo crashInfo; 2064 2065 /** 2066 * The strict mode policy mask at the time of violation. 2067 */ 2068 public final int policy; 2069 2070 /** 2071 * The wall time duration of the violation, when known. -1 when 2072 * not known. 2073 */ 2074 public int durationMillis = -1; 2075 2076 /** 2077 * The number of animations currently running. 2078 */ 2079 public int numAnimationsRunning = 0; 2080 2081 /** 2082 * List of tags from active Span instances during this 2083 * violation, or null for none. 2084 */ 2085 public String[] tags; 2086 2087 /** 2088 * Which violation number this was (1-based) since the last Looper loop, 2089 * from the perspective of the root caller (if it crossed any processes 2090 * via Binder calls). The value is 0 if the root caller wasn't on a Looper 2091 * thread. 2092 */ 2093 public int violationNumThisLoop; 2094 2095 /** 2096 * The time (in terms of SystemClock.uptimeMillis()) that the 2097 * violation occurred. 2098 */ 2099 public long violationUptimeMillis; 2100 2101 /** 2102 * The action of the Intent being broadcast to somebody's onReceive 2103 * on this thread right now, or null. 2104 */ 2105 public String broadcastIntentAction; 2106 2107 /** 2108 * If this is a instance count violation, the number of instances in memory, 2109 * else -1. 2110 */ 2111 public long numInstances = -1; 2112 2113 /** 2114 * Create an uninitialized instance of ViolationInfo 2115 */ ViolationInfo()2116 public ViolationInfo() { 2117 crashInfo = null; 2118 policy = 0; 2119 } 2120 2121 /** 2122 * Create an instance of ViolationInfo initialized from an exception. 2123 */ ViolationInfo(Throwable tr, int policy)2124 public ViolationInfo(Throwable tr, int policy) { 2125 crashInfo = new ApplicationErrorReport.CrashInfo(tr); 2126 violationUptimeMillis = SystemClock.uptimeMillis(); 2127 this.policy = policy; 2128 this.numAnimationsRunning = ValueAnimator.getCurrentAnimationsCount(); 2129 Intent broadcastIntent = ActivityThread.getIntentBeingBroadcast(); 2130 if (broadcastIntent != null) { 2131 broadcastIntentAction = broadcastIntent.getAction(); 2132 } 2133 ThreadSpanState state = sThisThreadSpanState.get(); 2134 if (tr instanceof InstanceCountViolation) { 2135 this.numInstances = ((InstanceCountViolation) tr).mInstances; 2136 } 2137 synchronized (state) { 2138 int spanActiveCount = state.mActiveSize; 2139 if (spanActiveCount > MAX_SPAN_TAGS) { 2140 spanActiveCount = MAX_SPAN_TAGS; 2141 } 2142 if (spanActiveCount != 0) { 2143 this.tags = new String[spanActiveCount]; 2144 Span iter = state.mActiveHead; 2145 int index = 0; 2146 while (iter != null && index < spanActiveCount) { 2147 this.tags[index] = iter.mName; 2148 index++; 2149 iter = iter.mNext; 2150 } 2151 } 2152 } 2153 } 2154 2155 @Override hashCode()2156 public int hashCode() { 2157 int result = 17; 2158 result = 37 * result + crashInfo.stackTrace.hashCode(); 2159 if (numAnimationsRunning != 0) { 2160 result *= 37; 2161 } 2162 if (broadcastIntentAction != null) { 2163 result = 37 * result + broadcastIntentAction.hashCode(); 2164 } 2165 if (tags != null) { 2166 for (String tag : tags) { 2167 result = 37 * result + tag.hashCode(); 2168 } 2169 } 2170 return result; 2171 } 2172 2173 /** 2174 * Create an instance of ViolationInfo initialized from a Parcel. 2175 */ ViolationInfo(Parcel in)2176 public ViolationInfo(Parcel in) { 2177 this(in, false); 2178 } 2179 2180 /** 2181 * Create an instance of ViolationInfo initialized from a Parcel. 2182 * 2183 * @param unsetGatheringBit if true, the caller is the root caller 2184 * and the gathering penalty should be removed. 2185 */ ViolationInfo(Parcel in, boolean unsetGatheringBit)2186 public ViolationInfo(Parcel in, boolean unsetGatheringBit) { 2187 crashInfo = new ApplicationErrorReport.CrashInfo(in); 2188 int rawPolicy = in.readInt(); 2189 if (unsetGatheringBit) { 2190 policy = rawPolicy & ~PENALTY_GATHER; 2191 } else { 2192 policy = rawPolicy; 2193 } 2194 durationMillis = in.readInt(); 2195 violationNumThisLoop = in.readInt(); 2196 numAnimationsRunning = in.readInt(); 2197 violationUptimeMillis = in.readLong(); 2198 numInstances = in.readLong(); 2199 broadcastIntentAction = in.readString(); 2200 tags = in.readStringArray(); 2201 } 2202 2203 /** 2204 * Save a ViolationInfo instance to a parcel. 2205 */ writeToParcel(Parcel dest, int flags)2206 public void writeToParcel(Parcel dest, int flags) { 2207 crashInfo.writeToParcel(dest, flags); 2208 int start = dest.dataPosition(); 2209 dest.writeInt(policy); 2210 dest.writeInt(durationMillis); 2211 dest.writeInt(violationNumThisLoop); 2212 dest.writeInt(numAnimationsRunning); 2213 dest.writeLong(violationUptimeMillis); 2214 dest.writeLong(numInstances); 2215 dest.writeString(broadcastIntentAction); 2216 dest.writeStringArray(tags); 2217 int total = dest.dataPosition()-start; 2218 if (total > 10*1024) { 2219 Slog.d(TAG, "VIO: policy=" + policy + " dur=" + durationMillis 2220 + " numLoop=" + violationNumThisLoop 2221 + " anim=" + numAnimationsRunning 2222 + " uptime=" + violationUptimeMillis 2223 + " numInst=" + numInstances); 2224 Slog.d(TAG, "VIO: action=" + broadcastIntentAction); 2225 Slog.d(TAG, "VIO: tags=" + Arrays.toString(tags)); 2226 Slog.d(TAG, "VIO: TOTAL BYTES WRITTEN: " + (dest.dataPosition()-start)); 2227 } 2228 } 2229 2230 2231 /** 2232 * Dump a ViolationInfo instance to a Printer. 2233 */ dump(Printer pw, String prefix)2234 public void dump(Printer pw, String prefix) { 2235 crashInfo.dump(pw, prefix); 2236 pw.println(prefix + "policy: " + policy); 2237 if (durationMillis != -1) { 2238 pw.println(prefix + "durationMillis: " + durationMillis); 2239 } 2240 if (numInstances != -1) { 2241 pw.println(prefix + "numInstances: " + numInstances); 2242 } 2243 if (violationNumThisLoop != 0) { 2244 pw.println(prefix + "violationNumThisLoop: " + violationNumThisLoop); 2245 } 2246 if (numAnimationsRunning != 0) { 2247 pw.println(prefix + "numAnimationsRunning: " + numAnimationsRunning); 2248 } 2249 pw.println(prefix + "violationUptimeMillis: " + violationUptimeMillis); 2250 if (broadcastIntentAction != null) { 2251 pw.println(prefix + "broadcastIntentAction: " + broadcastIntentAction); 2252 } 2253 if (tags != null) { 2254 int index = 0; 2255 for (String tag : tags) { 2256 pw.println(prefix + "tag[" + (index++) + "]: " + tag); 2257 } 2258 } 2259 } 2260 2261 } 2262 2263 // Dummy throwable, for now, since we don't know when or where the 2264 // leaked instances came from. We might in the future, but for 2265 // now we suppress the stack trace because it's useless and/or 2266 // misleading. 2267 private static class InstanceCountViolation extends Throwable { 2268 final Class mClass; 2269 final long mInstances; 2270 final int mLimit; 2271 2272 private static final StackTraceElement[] FAKE_STACK = { 2273 new StackTraceElement("android.os.StrictMode", "setClassInstanceLimit", 2274 "StrictMode.java", 1) 2275 }; 2276 InstanceCountViolation(Class klass, long instances, int limit)2277 public InstanceCountViolation(Class klass, long instances, int limit) { 2278 super(klass.toString() + "; instances=" + instances + "; limit=" + limit); 2279 setStackTrace(FAKE_STACK); 2280 mClass = klass; 2281 mInstances = instances; 2282 mLimit = limit; 2283 } 2284 } 2285 2286 private static final class InstanceTracker { 2287 private static final HashMap<Class<?>, Integer> sInstanceCounts = 2288 new HashMap<Class<?>, Integer>(); 2289 2290 private final Class<?> mKlass; 2291 InstanceTracker(Object instance)2292 public InstanceTracker(Object instance) { 2293 mKlass = instance.getClass(); 2294 2295 synchronized (sInstanceCounts) { 2296 final Integer value = sInstanceCounts.get(mKlass); 2297 final int newValue = value != null ? value + 1 : 1; 2298 sInstanceCounts.put(mKlass, newValue); 2299 } 2300 } 2301 2302 @Override finalize()2303 protected void finalize() throws Throwable { 2304 try { 2305 synchronized (sInstanceCounts) { 2306 final Integer value = sInstanceCounts.get(mKlass); 2307 if (value != null) { 2308 final int newValue = value - 1; 2309 if (newValue > 0) { 2310 sInstanceCounts.put(mKlass, newValue); 2311 } else { 2312 sInstanceCounts.remove(mKlass); 2313 } 2314 } 2315 } 2316 } finally { 2317 super.finalize(); 2318 } 2319 } 2320 getInstanceCount(Class<?> klass)2321 public static int getInstanceCount(Class<?> klass) { 2322 synchronized (sInstanceCounts) { 2323 final Integer value = sInstanceCounts.get(klass); 2324 return value != null ? value : 0; 2325 } 2326 } 2327 } 2328 } 2329