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