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