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