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