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