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