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