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