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