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