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