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