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