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