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