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