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