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