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