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