• 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.app.ActivityManagerNative;
20 import android.app.ActivityThread;
21 import android.app.ApplicationErrorReport;
22 import android.app.IActivityManager;
23 import android.content.BroadcastReceiver;
24 import android.content.Context;
25 import android.content.Intent;
26 import android.content.ServiceConnection;
27 import android.util.ArrayMap;
28 import android.util.Log;
29 import android.util.Printer;
30 import android.util.Singleton;
31 import android.view.IWindowManager;
32 
33 import com.android.internal.os.RuntimeInit;
34 
35 import com.android.internal.util.FastPrintWriter;
36 import dalvik.system.BlockGuard;
37 import dalvik.system.CloseGuard;
38 import dalvik.system.VMDebug;
39 
40 import java.io.PrintWriter;
41 import java.io.StringWriter;
42 import java.util.ArrayList;
43 import java.util.HashMap;
44 import java.util.Map;
45 import java.util.concurrent.atomic.AtomicInteger;
46 
47 /**
48  * <p>StrictMode is a developer tool which detects things you might be
49  * doing by accident and brings them to your attention so you can fix
50  * them.
51  *
52  * <p>StrictMode is most commonly used to catch accidental disk or
53  * network access on the application's main thread, where UI
54  * operations are received and animations take place.  Keeping disk
55  * and network operations off the main thread makes for much smoother,
56  * more responsive applications.  By keeping your application's main thread
57  * responsive, you also prevent
58  * <a href="{@docRoot}guide/practices/design/responsiveness.html">ANR dialogs</a>
59  * from being shown to users.
60  *
61  * <p class="note">Note that even though an Android device's disk is
62  * often on flash memory, many devices run a filesystem on top of that
63  * memory with very limited concurrency.  It's often the case that
64  * almost all disk accesses are fast, but may in individual cases be
65  * dramatically slower when certain I/O is happening in the background
66  * from other processes.  If possible, it's best to assume that such
67  * things are not fast.</p>
68  *
69  * <p>Example code to enable from early in your
70  * {@link android.app.Application}, {@link android.app.Activity}, or
71  * other application component's
72  * {@link android.app.Application#onCreate} method:
73  *
74  * <pre>
75  * public void onCreate() {
76  *     if (DEVELOPER_MODE) {
77  *         StrictMode.setThreadPolicy(new {@link ThreadPolicy.Builder StrictMode.ThreadPolicy.Builder}()
78  *                 .detectDiskReads()
79  *                 .detectDiskWrites()
80  *                 .detectNetwork()   // or .detectAll() for all detectable problems
81  *                 .penaltyLog()
82  *                 .build());
83  *         StrictMode.setVmPolicy(new {@link VmPolicy.Builder StrictMode.VmPolicy.Builder}()
84  *                 .detectLeakedSqlLiteObjects()
85  *                 .detectLeakedClosableObjects()
86  *                 .penaltyLog()
87  *                 .penaltyDeath()
88  *                 .build());
89  *     }
90  *     super.onCreate();
91  * }
92  * </pre>
93  *
94  * <p>You can decide what should happen when a violation is detected.
95  * For example, using {@link ThreadPolicy.Builder#penaltyLog} you can
96  * watch the output of <code>adb logcat</code> while you use your
97  * application to see the violations as they happen.
98  *
99  * <p>If you find violations that you feel are problematic, there are
100  * a variety of tools to help solve them: threads, {@link android.os.Handler},
101  * {@link android.os.AsyncTask}, {@link android.app.IntentService}, etc.
102  * But don't feel compelled to fix everything that StrictMode finds.  In particular,
103  * many cases of disk access are often necessary during the normal activity lifecycle.  Use
104  * StrictMode to find things you did by accident.  Network requests on the UI thread
105  * are almost always a problem, though.
106  *
107  * <p class="note">StrictMode is not a security mechanism and is not
108  * guaranteed to find all disk or network accesses.  While it does
109  * propagate its state across process boundaries when doing
110  * {@link android.os.Binder} calls, it's still ultimately a best
111  * effort mechanism.  Notably, disk or network access from JNI calls
112  * won't necessarily trigger it.  Future versions of Android may catch
113  * more (or fewer) operations, so you should never leave StrictMode
114  * enabled in applications distributed on Google Play.
115  */
116 public final class StrictMode {
117     private static final String TAG = "StrictMode";
118     private static final boolean LOG_V = Log.isLoggable(TAG, Log.VERBOSE);
119 
120     private static final boolean IS_USER_BUILD = "user".equals(Build.TYPE);
121     private static final boolean IS_ENG_BUILD = "eng".equals(Build.TYPE);
122 
123     /**
124      * Boolean system property to disable strict mode checks outright.
125      * Set this to 'true' to force disable; 'false' has no effect on other
126      * enable/disable policy.
127      * @hide
128      */
129     public static final String DISABLE_PROPERTY = "persist.sys.strictmode.disable";
130 
131     /**
132      * The boolean system property to control screen flashes on violations.
133      *
134      * @hide
135      */
136     public static final String VISUAL_PROPERTY = "persist.sys.strictmode.visual";
137 
138     // Only log a duplicate stack trace to the logs every second.
139     private static final long MIN_LOG_INTERVAL_MS = 1000;
140 
141     // Only show an annoying dialog at most every 30 seconds
142     private static final long MIN_DIALOG_INTERVAL_MS = 30000;
143 
144     // How many Span tags (e.g. animations) to report.
145     private static final int MAX_SPAN_TAGS = 20;
146 
147     // How many offending stacks to keep track of (and time) per loop
148     // of the Looper.
149     private static final int MAX_OFFENSES_PER_LOOP = 10;
150 
151     // Thread-policy:
152 
153     /**
154      * @hide
155      */
156     public static final int DETECT_DISK_WRITE = 0x01;  // for ThreadPolicy
157 
158     /**
159       * @hide
160      */
161     public static final int DETECT_DISK_READ = 0x02;  // for ThreadPolicy
162 
163     /**
164      * @hide
165      */
166     public static final int DETECT_NETWORK = 0x04;  // for ThreadPolicy
167 
168     /**
169      * For StrictMode.noteSlowCall()
170      *
171      * @hide
172      */
173     public static final int DETECT_CUSTOM = 0x08;  // for ThreadPolicy
174 
175     private static final int ALL_THREAD_DETECT_BITS =
176             DETECT_DISK_WRITE | DETECT_DISK_READ | DETECT_NETWORK | DETECT_CUSTOM;
177 
178     // Process-policy:
179 
180     /**
181      * Note, a "VM_" bit, not thread.
182      * @hide
183      */
184     public static final int DETECT_VM_CURSOR_LEAKS = 0x200;  // for VmPolicy
185 
186     /**
187      * Note, a "VM_" bit, not thread.
188      * @hide
189      */
190     public static final int DETECT_VM_CLOSABLE_LEAKS = 0x400;  // for VmPolicy
191 
192     /**
193      * Note, a "VM_" bit, not thread.
194      * @hide
195      */
196     public static final int DETECT_VM_ACTIVITY_LEAKS = 0x800;  // for VmPolicy
197 
198     /**
199      * @hide
200      */
201     private static final int DETECT_VM_INSTANCE_LEAKS = 0x1000;  // for VmPolicy
202 
203     /**
204      * @hide
205      */
206     public static final int DETECT_VM_REGISTRATION_LEAKS = 0x2000;  // for VmPolicy
207 
208     /**
209      * @hide
210      */
211     private static final int DETECT_VM_FILE_URI_EXPOSURE = 0x4000;  // for VmPolicy
212 
213     private static final int ALL_VM_DETECT_BITS =
214             DETECT_VM_CURSOR_LEAKS | DETECT_VM_CLOSABLE_LEAKS |
215             DETECT_VM_ACTIVITY_LEAKS | DETECT_VM_INSTANCE_LEAKS |
216             DETECT_VM_REGISTRATION_LEAKS | DETECT_VM_FILE_URI_EXPOSURE;
217 
218     /**
219      * @hide
220      */
221     public static final int PENALTY_LOG = 0x10;  // normal android.util.Log
222 
223     // Used for both process and thread policy:
224 
225     /**
226      * @hide
227      */
228     public static final int PENALTY_DIALOG = 0x20;
229 
230     /**
231      * Death on any detected violation.
232      *
233      * @hide
234      */
235     public static final int PENALTY_DEATH = 0x40;
236 
237     /**
238      * Death just for detected network usage.
239      *
240      * @hide
241      */
242     public static final int PENALTY_DEATH_ON_NETWORK = 0x200;
243 
244     /**
245      * Flash the screen during violations.
246      *
247      * @hide
248      */
249     public static final int PENALTY_FLASH = 0x800;
250 
251     /**
252      * @hide
253      */
254     public static final int PENALTY_DROPBOX = 0x80;
255 
256     /**
257      * Non-public penalty mode which overrides all the other penalty
258      * bits and signals that we're in a Binder call and we should
259      * ignore the other penalty bits and instead serialize back all
260      * our offending stack traces to the caller to ultimately handle
261      * in the originating process.
262      *
263      * This must be kept in sync with the constant in libs/binder/Parcel.cpp
264      *
265      * @hide
266      */
267     public static final int PENALTY_GATHER = 0x100;
268 
269     /**
270      * Mask of all the penalty bits valid for thread policies.
271      */
272     private static final int THREAD_PENALTY_MASK =
273             PENALTY_LOG | PENALTY_DIALOG | PENALTY_DEATH | PENALTY_DROPBOX | PENALTY_GATHER |
274             PENALTY_DEATH_ON_NETWORK | PENALTY_FLASH;
275 
276 
277     /**
278      * Mask of all the penalty bits valid for VM policies.
279      */
280     private static final int VM_PENALTY_MASK =
281             PENALTY_LOG | PENALTY_DEATH | PENALTY_DROPBOX;
282 
283 
284     // TODO: wrap in some ImmutableHashMap thing.
285     // Note: must be before static initialization of sVmPolicy.
286     private static final HashMap<Class, Integer> EMPTY_CLASS_LIMIT_MAP = new HashMap<Class, Integer>();
287 
288     /**
289      * The current VmPolicy in effect.
290      *
291      * TODO: these are redundant (mask is in VmPolicy).  Should remove sVmPolicyMask.
292      */
293     private static volatile int sVmPolicyMask = 0;
294     private static volatile VmPolicy sVmPolicy = VmPolicy.LAX;
295 
296     /**
297      * The number of threads trying to do an async dropbox write.
298      * Just to limit ourselves out of paranoia.
299      */
300     private static final AtomicInteger sDropboxCallsInFlight = new AtomicInteger(0);
301 
StrictMode()302     private StrictMode() {}
303 
304     /**
305      * {@link StrictMode} policy applied to a certain thread.
306      *
307      * <p>The policy is enabled by {@link #setThreadPolicy}.  The current policy
308      * can be retrieved with {@link #getThreadPolicy}.
309      *
310      * <p>Note that multiple penalties may be provided and they're run
311      * in order from least to most severe (logging before process
312      * death, for example).  There's currently no mechanism to choose
313      * different penalties for different detected actions.
314      */
315     public static final class ThreadPolicy {
316         /**
317          * The default, lax policy which doesn't catch anything.
318          */
319         public static final ThreadPolicy LAX = new ThreadPolicy(0);
320 
321         final int mask;
322 
ThreadPolicy(int mask)323         private ThreadPolicy(int mask) {
324             this.mask = mask;
325         }
326 
327         @Override
toString()328         public String toString() {
329             return "[StrictMode.ThreadPolicy; mask=" + mask + "]";
330         }
331 
332         /**
333          * Creates {@link ThreadPolicy} instances.  Methods whose names start
334          * with {@code detect} specify what problems we should look
335          * for.  Methods whose names start with {@code penalty} specify what
336          * we should do when we detect a problem.
337          *
338          * <p>You can call as many {@code detect} and {@code penalty}
339          * methods as you like. Currently order is insignificant: all
340          * penalties apply to all detected problems.
341          *
342          * <p>For example, detect everything and log anything that's found:
343          * <pre>
344          * StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder()
345          *     .detectAll()
346          *     .penaltyLog()
347          *     .build();
348          * StrictMode.setThreadPolicy(policy);
349          * </pre>
350          */
351         public static final class Builder {
352             private int mMask = 0;
353 
354             /**
355              * Create a Builder that detects nothing and has no
356              * violations.  (but note that {@link #build} will default
357              * to enabling {@link #penaltyLog} if no other penalties
358              * are specified)
359              */
Builder()360             public Builder() {
361                 mMask = 0;
362             }
363 
364             /**
365              * Initialize a Builder from an existing ThreadPolicy.
366              */
Builder(ThreadPolicy policy)367             public Builder(ThreadPolicy policy) {
368                 mMask = policy.mask;
369             }
370 
371             /**
372              * Detect everything that's potentially suspect.
373              *
374              * <p>As of the Gingerbread release this includes network and
375              * disk operations but will likely expand in future releases.
376              */
detectAll()377             public Builder detectAll() {
378                 return enable(ALL_THREAD_DETECT_BITS);
379             }
380 
381             /**
382              * Disable the detection of everything.
383              */
permitAll()384             public Builder permitAll() {
385                 return disable(ALL_THREAD_DETECT_BITS);
386             }
387 
388             /**
389              * Enable detection of network operations.
390              */
detectNetwork()391             public Builder detectNetwork() {
392                 return enable(DETECT_NETWORK);
393             }
394 
395             /**
396              * Disable detection of network operations.
397              */
permitNetwork()398             public Builder permitNetwork() {
399                 return disable(DETECT_NETWORK);
400             }
401 
402             /**
403              * Enable detection of disk reads.
404              */
detectDiskReads()405             public Builder detectDiskReads() {
406                 return enable(DETECT_DISK_READ);
407             }
408 
409             /**
410              * Disable detection of disk reads.
411              */
permitDiskReads()412             public Builder permitDiskReads() {
413                 return disable(DETECT_DISK_READ);
414             }
415 
416             /**
417              * Enable detection of slow calls.
418              */
detectCustomSlowCalls()419             public Builder detectCustomSlowCalls() {
420                 return enable(DETECT_CUSTOM);
421             }
422 
423             /**
424              * Disable detection of slow calls.
425              */
permitCustomSlowCalls()426             public Builder permitCustomSlowCalls() {
427                 return disable(DETECT_CUSTOM);
428             }
429 
430             /**
431              * Enable detection of disk writes.
432              */
detectDiskWrites()433             public Builder detectDiskWrites() {
434                 return enable(DETECT_DISK_WRITE);
435             }
436 
437             /**
438              * Disable detection of disk writes.
439              */
permitDiskWrites()440             public Builder permitDiskWrites() {
441                 return disable(DETECT_DISK_WRITE);
442             }
443 
444             /**
445              * Show an annoying dialog to the developer on detected
446              * violations, rate-limited to be only a little annoying.
447              */
penaltyDialog()448             public Builder penaltyDialog() {
449                 return enable(PENALTY_DIALOG);
450             }
451 
452             /**
453              * Crash the whole process on violation.  This penalty runs at
454              * the end of all enabled penalties so you'll still get
455              * see logging or other violations before the process dies.
456              *
457              * <p>Unlike {@link #penaltyDeathOnNetwork}, this applies
458              * to disk reads, disk writes, and network usage if their
459              * corresponding detect flags are set.
460              */
penaltyDeath()461             public Builder penaltyDeath() {
462                 return enable(PENALTY_DEATH);
463             }
464 
465             /**
466              * Crash the whole process on any network usage.  Unlike
467              * {@link #penaltyDeath}, this penalty runs
468              * <em>before</em> anything else.  You must still have
469              * called {@link #detectNetwork} to enable this.
470              *
471              * <p>In the Honeycomb or later SDKs, this is on by default.
472              */
penaltyDeathOnNetwork()473             public Builder penaltyDeathOnNetwork() {
474                 return enable(PENALTY_DEATH_ON_NETWORK);
475             }
476 
477             /**
478              * Flash the screen during a violation.
479              */
penaltyFlashScreen()480             public Builder penaltyFlashScreen() {
481                 return enable(PENALTY_FLASH);
482             }
483 
484             /**
485              * Log detected violations to the system log.
486              */
penaltyLog()487             public Builder penaltyLog() {
488                 return enable(PENALTY_LOG);
489             }
490 
491             /**
492              * Enable detected violations log a stacktrace and timing data
493              * to the {@link android.os.DropBoxManager DropBox} on policy
494              * violation.  Intended mostly for platform integrators doing
495              * beta user field data collection.
496              */
penaltyDropBox()497             public Builder penaltyDropBox() {
498                 return enable(PENALTY_DROPBOX);
499             }
500 
enable(int bit)501             private Builder enable(int bit) {
502                 mMask |= bit;
503                 return this;
504             }
505 
disable(int bit)506             private Builder disable(int bit) {
507                 mMask &= ~bit;
508                 return this;
509             }
510 
511             /**
512              * Construct the ThreadPolicy instance.
513              *
514              * <p>Note: if no penalties are enabled before calling
515              * <code>build</code>, {@link #penaltyLog} is implicitly
516              * set.
517              */
build()518             public ThreadPolicy build() {
519                 // If there are detection bits set but no violation bits
520                 // set, enable simple logging.
521                 if (mMask != 0 &&
522                     (mMask & (PENALTY_DEATH | PENALTY_LOG |
523                               PENALTY_DROPBOX | PENALTY_DIALOG)) == 0) {
524                     penaltyLog();
525                 }
526                 return new ThreadPolicy(mMask);
527             }
528         }
529     }
530 
531     /**
532      * {@link StrictMode} policy applied to all threads in the virtual machine's process.
533      *
534      * <p>The policy is enabled by {@link #setVmPolicy}.
535      */
536     public static final class VmPolicy {
537         /**
538          * The default, lax policy which doesn't catch anything.
539          */
540         public static final VmPolicy LAX = new VmPolicy(0, EMPTY_CLASS_LIMIT_MAP);
541 
542         final int mask;
543 
544         // Map from class to max number of allowed instances in memory.
545         final HashMap<Class, Integer> classInstanceLimit;
546 
VmPolicy(int mask, HashMap<Class, Integer> classInstanceLimit)547         private VmPolicy(int mask, HashMap<Class, Integer> classInstanceLimit) {
548             if (classInstanceLimit == null) {
549                 throw new NullPointerException("classInstanceLimit == null");
550             }
551             this.mask = mask;
552             this.classInstanceLimit = classInstanceLimit;
553         }
554 
555         @Override
toString()556         public String toString() {
557             return "[StrictMode.VmPolicy; mask=" + mask + "]";
558         }
559 
560         /**
561          * Creates {@link VmPolicy} instances.  Methods whose names start
562          * with {@code detect} specify what problems we should look
563          * for.  Methods whose names start with {@code penalty} specify what
564          * we should do when we detect a problem.
565          *
566          * <p>You can call as many {@code detect} and {@code penalty}
567          * methods as you like. Currently order is insignificant: all
568          * penalties apply to all detected problems.
569          *
570          * <p>For example, detect everything and log anything that's found:
571          * <pre>
572          * StrictMode.VmPolicy policy = new StrictMode.VmPolicy.Builder()
573          *     .detectAll()
574          *     .penaltyLog()
575          *     .build();
576          * StrictMode.setVmPolicy(policy);
577          * </pre>
578          */
579         public static final class Builder {
580             private int mMask;
581 
582             private HashMap<Class, Integer> mClassInstanceLimit;  // null until needed
583             private boolean mClassInstanceLimitNeedCow = false;  // need copy-on-write
584 
Builder()585             public Builder() {
586                 mMask = 0;
587             }
588 
589             /**
590              * Build upon an existing VmPolicy.
591              */
Builder(VmPolicy base)592             public Builder(VmPolicy base) {
593                 mMask = base.mask;
594                 mClassInstanceLimitNeedCow = true;
595                 mClassInstanceLimit = base.classInstanceLimit;
596             }
597 
598             /**
599              * Set an upper bound on how many instances of a class can be in memory
600              * at once.  Helps to prevent object leaks.
601              */
setClassInstanceLimit(Class klass, int instanceLimit)602             public Builder setClassInstanceLimit(Class klass, int instanceLimit) {
603                 if (klass == null) {
604                     throw new NullPointerException("klass == null");
605                 }
606                 if (mClassInstanceLimitNeedCow) {
607                     if (mClassInstanceLimit.containsKey(klass) &&
608                         mClassInstanceLimit.get(klass) == instanceLimit) {
609                         // no-op; don't break COW
610                         return this;
611                     }
612                     mClassInstanceLimitNeedCow = false;
613                     mClassInstanceLimit = (HashMap<Class, Integer>) mClassInstanceLimit.clone();
614                 } else if (mClassInstanceLimit == null) {
615                     mClassInstanceLimit = new HashMap<Class, Integer>();
616                 }
617                 mMask |= DETECT_VM_INSTANCE_LEAKS;
618                 mClassInstanceLimit.put(klass, instanceLimit);
619                 return this;
620             }
621 
622             /**
623              * Detect leaks of {@link android.app.Activity} subclasses.
624              */
detectActivityLeaks()625             public Builder detectActivityLeaks() {
626                 return enable(DETECT_VM_ACTIVITY_LEAKS);
627             }
628 
629             /**
630              * Detect everything that's potentially suspect.
631              *
632              * <p>In the Honeycomb release this includes leaks of
633              * SQLite cursors, Activities, and other closable objects
634              * but will likely expand in future releases.
635              */
detectAll()636             public Builder detectAll() {
637                 return enable(DETECT_VM_ACTIVITY_LEAKS | DETECT_VM_CURSOR_LEAKS
638                         | DETECT_VM_CLOSABLE_LEAKS | DETECT_VM_REGISTRATION_LEAKS
639                         | DETECT_VM_FILE_URI_EXPOSURE);
640             }
641 
642             /**
643              * Detect when an
644              * {@link android.database.sqlite.SQLiteCursor} or other
645              * SQLite object is finalized without having been closed.
646              *
647              * <p>You always want to explicitly close your SQLite
648              * cursors to avoid unnecessary database contention and
649              * temporary memory leaks.
650              */
detectLeakedSqlLiteObjects()651             public Builder detectLeakedSqlLiteObjects() {
652                 return enable(DETECT_VM_CURSOR_LEAKS);
653             }
654 
655             /**
656              * Detect when an {@link java.io.Closeable} or other
657              * object with a explict termination method is finalized
658              * without having been closed.
659              *
660              * <p>You always want to explicitly close such objects to
661              * avoid unnecessary resources leaks.
662              */
detectLeakedClosableObjects()663             public Builder detectLeakedClosableObjects() {
664                 return enable(DETECT_VM_CLOSABLE_LEAKS);
665             }
666 
667             /**
668              * Detect when a {@link BroadcastReceiver} or
669              * {@link ServiceConnection} is leaked during {@link Context}
670              * teardown.
671              */
detectLeakedRegistrationObjects()672             public Builder detectLeakedRegistrationObjects() {
673                 return enable(DETECT_VM_REGISTRATION_LEAKS);
674             }
675 
676             /**
677              * Detect when a {@code file://} {@link android.net.Uri} is exposed beyond this
678              * app. The receiving app may not have access to the sent path.
679              * Instead, when sharing files between apps, {@code content://}
680              * should be used with permission grants.
681              */
detectFileUriExposure()682             public Builder detectFileUriExposure() {
683                 return enable(DETECT_VM_FILE_URI_EXPOSURE);
684             }
685 
686             /**
687              * Crashes the whole process on violation.  This penalty runs at
688              * the end of all enabled penalties so yo you'll still get
689              * your logging or other violations before the process dies.
690              */
penaltyDeath()691             public Builder penaltyDeath() {
692                 return enable(PENALTY_DEATH);
693             }
694 
695             /**
696              * Log detected violations to the system log.
697              */
penaltyLog()698             public Builder penaltyLog() {
699                 return enable(PENALTY_LOG);
700             }
701 
702             /**
703              * Enable detected violations log a stacktrace and timing data
704              * to the {@link android.os.DropBoxManager DropBox} on policy
705              * violation.  Intended mostly for platform integrators doing
706              * beta user field data collection.
707              */
penaltyDropBox()708             public Builder penaltyDropBox() {
709                 return enable(PENALTY_DROPBOX);
710             }
711 
enable(int bit)712             private Builder enable(int bit) {
713                 mMask |= bit;
714                 return this;
715             }
716 
717             /**
718              * Construct the VmPolicy instance.
719              *
720              * <p>Note: if no penalties are enabled before calling
721              * <code>build</code>, {@link #penaltyLog} is implicitly
722              * set.
723              */
build()724             public VmPolicy build() {
725                 // If there are detection bits set but no violation bits
726                 // set, enable simple logging.
727                 if (mMask != 0 &&
728                     (mMask & (PENALTY_DEATH | PENALTY_LOG |
729                               PENALTY_DROPBOX | PENALTY_DIALOG)) == 0) {
730                     penaltyLog();
731                 }
732                 return new VmPolicy(mMask,
733                         mClassInstanceLimit != null ? mClassInstanceLimit : EMPTY_CLASS_LIMIT_MAP);
734             }
735         }
736     }
737 
738     /**
739      * Log of strict mode violation stack traces that have occurred
740      * during a Binder call, to be serialized back later to the caller
741      * via Parcel.writeNoException() (amusingly) where the caller can
742      * choose how to react.
743      */
744     private static final ThreadLocal<ArrayList<ViolationInfo>> gatheredViolations =
745             new ThreadLocal<ArrayList<ViolationInfo>>() {
746         @Override protected ArrayList<ViolationInfo> initialValue() {
747             // Starts null to avoid unnecessary allocations when
748             // checking whether there are any violations or not in
749             // hasGatheredViolations() below.
750             return null;
751         }
752     };
753 
754     /**
755      * Sets the policy for what actions on the current thread should
756      * be detected, as well as the penalty if such actions occur.
757      *
758      * <p>Internally this sets a thread-local variable which is
759      * propagated across cross-process IPC calls, meaning you can
760      * catch violations when a system service or another process
761      * accesses the disk or network on your behalf.
762      *
763      * @param policy the policy to put into place
764      */
setThreadPolicy(final ThreadPolicy policy)765     public static void setThreadPolicy(final ThreadPolicy policy) {
766         setThreadPolicyMask(policy.mask);
767     }
768 
setThreadPolicyMask(final int policyMask)769     private static void setThreadPolicyMask(final int policyMask) {
770         // In addition to the Java-level thread-local in Dalvik's
771         // BlockGuard, we also need to keep a native thread-local in
772         // Binder in order to propagate the value across Binder calls,
773         // even across native-only processes.  The two are kept in
774         // sync via the callback to onStrictModePolicyChange, below.
775         setBlockGuardPolicy(policyMask);
776 
777         // And set the Android native version...
778         Binder.setThreadStrictModePolicy(policyMask);
779     }
780 
781     // Sets the policy in Dalvik/libcore (BlockGuard)
setBlockGuardPolicy(final int policyMask)782     private static void setBlockGuardPolicy(final int policyMask) {
783         if (policyMask == 0) {
784             BlockGuard.setThreadPolicy(BlockGuard.LAX_POLICY);
785             return;
786         }
787         final BlockGuard.Policy policy = BlockGuard.getThreadPolicy();
788         final AndroidBlockGuardPolicy androidPolicy;
789         if (policy instanceof AndroidBlockGuardPolicy) {
790             androidPolicy = (AndroidBlockGuardPolicy) policy;
791         } else {
792             androidPolicy = threadAndroidPolicy.get();
793             BlockGuard.setThreadPolicy(androidPolicy);
794         }
795         androidPolicy.setPolicyMask(policyMask);
796     }
797 
798     // Sets up CloseGuard in Dalvik/libcore
setCloseGuardEnabled(boolean enabled)799     private static void setCloseGuardEnabled(boolean enabled) {
800         if (!(CloseGuard.getReporter() instanceof AndroidCloseGuardReporter)) {
801             CloseGuard.setReporter(new AndroidCloseGuardReporter());
802         }
803         CloseGuard.setEnabled(enabled);
804     }
805 
806     /**
807      * @hide
808      */
809     public static class StrictModeViolation extends BlockGuard.BlockGuardPolicyException {
StrictModeViolation(int policyState, int policyViolated, String message)810         public StrictModeViolation(int policyState, int policyViolated, String message) {
811             super(policyState, policyViolated, message);
812         }
813     }
814 
815     /**
816      * @hide
817      */
818     public static class StrictModeNetworkViolation extends StrictModeViolation {
StrictModeNetworkViolation(int policyMask)819         public StrictModeNetworkViolation(int policyMask) {
820             super(policyMask, DETECT_NETWORK, null);
821         }
822     }
823 
824     /**
825      * @hide
826      */
827     private static class StrictModeDiskReadViolation extends StrictModeViolation {
StrictModeDiskReadViolation(int policyMask)828         public StrictModeDiskReadViolation(int policyMask) {
829             super(policyMask, DETECT_DISK_READ, null);
830         }
831     }
832 
833      /**
834      * @hide
835      */
836    private static class StrictModeDiskWriteViolation extends StrictModeViolation {
StrictModeDiskWriteViolation(int policyMask)837         public StrictModeDiskWriteViolation(int policyMask) {
838             super(policyMask, DETECT_DISK_WRITE, null);
839         }
840     }
841 
842     /**
843      * @hide
844      */
845     private static class StrictModeCustomViolation extends StrictModeViolation {
StrictModeCustomViolation(int policyMask, String name)846         public StrictModeCustomViolation(int policyMask, String name) {
847             super(policyMask, DETECT_CUSTOM, name);
848         }
849     }
850 
851     /**
852      * Returns the bitmask of the current thread's policy.
853      *
854      * @return the bitmask of all the DETECT_* and PENALTY_* bits currently enabled
855      *
856      * @hide
857      */
getThreadPolicyMask()858     public static int getThreadPolicyMask() {
859         return BlockGuard.getThreadPolicy().getPolicyMask();
860     }
861 
862     /**
863      * Returns the current thread's policy.
864      */
getThreadPolicy()865     public static ThreadPolicy getThreadPolicy() {
866         // TODO: this was a last minute Gingerbread API change (to
867         // introduce VmPolicy cleanly) but this isn't particularly
868         // optimal for users who might call this method often.  This
869         // should be in a thread-local and not allocate on each call.
870         return new ThreadPolicy(getThreadPolicyMask());
871     }
872 
873     /**
874      * A convenience wrapper that takes the current
875      * {@link ThreadPolicy} from {@link #getThreadPolicy}, modifies it
876      * to permit both disk reads &amp; writes, and sets the new policy
877      * with {@link #setThreadPolicy}, returning the old policy so you
878      * can restore it at the end of a block.
879      *
880      * @return the old policy, to be passed to {@link #setThreadPolicy} to
881      *         restore the policy at the end of a block
882      */
allowThreadDiskWrites()883     public static ThreadPolicy allowThreadDiskWrites() {
884         int oldPolicyMask = getThreadPolicyMask();
885         int newPolicyMask = oldPolicyMask & ~(DETECT_DISK_WRITE | DETECT_DISK_READ);
886         if (newPolicyMask != oldPolicyMask) {
887             setThreadPolicyMask(newPolicyMask);
888         }
889         return new ThreadPolicy(oldPolicyMask);
890     }
891 
892     /**
893      * A convenience wrapper that takes the current
894      * {@link ThreadPolicy} from {@link #getThreadPolicy}, modifies it
895      * to permit disk reads, and sets the new policy
896      * with {@link #setThreadPolicy}, returning the old policy so you
897      * can restore it at the end of a block.
898      *
899      * @return the old policy, to be passed to setThreadPolicy to
900      *         restore the policy.
901      */
allowThreadDiskReads()902     public static ThreadPolicy allowThreadDiskReads() {
903         int oldPolicyMask = getThreadPolicyMask();
904         int newPolicyMask = oldPolicyMask & ~(DETECT_DISK_READ);
905         if (newPolicyMask != oldPolicyMask) {
906             setThreadPolicyMask(newPolicyMask);
907         }
908         return new ThreadPolicy(oldPolicyMask);
909     }
910 
911     // We don't want to flash the screen red in the system server
912     // process, nor do we want to modify all the call sites of
913     // conditionallyEnableDebugLogging() in the system server,
914     // so instead we use this to determine if we are the system server.
amTheSystemServerProcess()915     private static boolean amTheSystemServerProcess() {
916         // Fast path.  Most apps don't have the system server's UID.
917         if (Process.myUid() != Process.SYSTEM_UID) {
918             return false;
919         }
920 
921         // The settings app, though, has the system server's UID so
922         // look up our stack to see if we came from the system server.
923         Throwable stack = new Throwable();
924         stack.fillInStackTrace();
925         for (StackTraceElement ste : stack.getStackTrace()) {
926             String clsName = ste.getClassName();
927             if (clsName != null && clsName.startsWith("com.android.server.")) {
928                 return true;
929             }
930         }
931         return false;
932     }
933 
934     /**
935      * Enable DropBox logging for debug phone builds.
936      *
937      * @hide
938      */
conditionallyEnableDebugLogging()939     public static boolean conditionallyEnableDebugLogging() {
940         boolean doFlashes = SystemProperties.getBoolean(VISUAL_PROPERTY, false)
941                 && !amTheSystemServerProcess();
942         final boolean suppress = SystemProperties.getBoolean(DISABLE_PROPERTY, false);
943 
944         // For debug builds, log event loop stalls to dropbox for analysis.
945         // Similar logic also appears in ActivityThread.java for system apps.
946         if (!doFlashes && (IS_USER_BUILD || suppress)) {
947             setCloseGuardEnabled(false);
948             return false;
949         }
950 
951         // Eng builds have flashes on all the time.  The suppression property
952         // overrides this, so we force the behavior only after the short-circuit
953         // check above.
954         if (IS_ENG_BUILD) {
955             doFlashes = true;
956         }
957 
958         // Thread policy controls BlockGuard.
959         int threadPolicyMask = StrictMode.DETECT_DISK_WRITE |
960                 StrictMode.DETECT_DISK_READ |
961                 StrictMode.DETECT_NETWORK;
962 
963         if (!IS_USER_BUILD) {
964             threadPolicyMask |= StrictMode.PENALTY_DROPBOX;
965         }
966         if (doFlashes) {
967             threadPolicyMask |= StrictMode.PENALTY_FLASH;
968         }
969 
970         StrictMode.setThreadPolicyMask(threadPolicyMask);
971 
972         // VM Policy controls CloseGuard, detection of Activity leaks,
973         // and instance counting.
974         if (IS_USER_BUILD) {
975             setCloseGuardEnabled(false);
976         } else {
977             VmPolicy.Builder policyBuilder = new VmPolicy.Builder().detectAll().penaltyDropBox();
978             if (IS_ENG_BUILD) {
979                 policyBuilder.penaltyLog();
980             }
981             setVmPolicy(policyBuilder.build());
982             setCloseGuardEnabled(vmClosableObjectLeaksEnabled());
983         }
984         return true;
985     }
986 
987     /**
988      * Used by the framework to make network usage on the main
989      * thread a fatal error.
990      *
991      * @hide
992      */
enableDeathOnNetwork()993     public static void enableDeathOnNetwork() {
994         int oldPolicy = getThreadPolicyMask();
995         int newPolicy = oldPolicy | DETECT_NETWORK | PENALTY_DEATH_ON_NETWORK;
996         setThreadPolicyMask(newPolicy);
997     }
998 
999     /**
1000      * Parses the BlockGuard policy mask out from the Exception's
1001      * getMessage() String value.  Kinda gross, but least
1002      * invasive.  :/
1003      *
1004      * Input is of the following forms:
1005      *     "policy=137 violation=64"
1006      *     "policy=137 violation=64 msg=Arbitrary text"
1007      *
1008      * Returns 0 on failure, which is a valid policy, but not a
1009      * valid policy during a violation (else there must've been
1010      * some policy in effect to violate).
1011      */
parsePolicyFromMessage(String message)1012     private static int parsePolicyFromMessage(String message) {
1013         if (message == null || !message.startsWith("policy=")) {
1014             return 0;
1015         }
1016         int spaceIndex = message.indexOf(' ');
1017         if (spaceIndex == -1) {
1018             return 0;
1019         }
1020         String policyString = message.substring(7, spaceIndex);
1021         try {
1022             return Integer.valueOf(policyString).intValue();
1023         } catch (NumberFormatException e) {
1024             return 0;
1025         }
1026     }
1027 
1028     /**
1029      * Like parsePolicyFromMessage(), but returns the violation.
1030      */
parseViolationFromMessage(String message)1031     private static int parseViolationFromMessage(String message) {
1032         if (message == null) {
1033             return 0;
1034         }
1035         int violationIndex = message.indexOf("violation=");
1036         if (violationIndex == -1) {
1037             return 0;
1038         }
1039         int numberStartIndex = violationIndex + "violation=".length();
1040         int numberEndIndex = message.indexOf(' ', numberStartIndex);
1041         if (numberEndIndex == -1) {
1042             numberEndIndex = message.length();
1043         }
1044         String violationString = message.substring(numberStartIndex, numberEndIndex);
1045         try {
1046             return Integer.valueOf(violationString).intValue();
1047         } catch (NumberFormatException e) {
1048             return 0;
1049         }
1050     }
1051 
1052     private static final ThreadLocal<ArrayList<ViolationInfo>> violationsBeingTimed =
1053             new ThreadLocal<ArrayList<ViolationInfo>>() {
1054         @Override protected ArrayList<ViolationInfo> initialValue() {
1055             return new ArrayList<ViolationInfo>();
1056         }
1057     };
1058 
1059     // Note: only access this once verifying the thread has a Looper.
1060     private static final ThreadLocal<Handler> threadHandler = new ThreadLocal<Handler>() {
1061         @Override protected Handler initialValue() {
1062             return new Handler();
1063         }
1064     };
1065 
1066     private static final ThreadLocal<AndroidBlockGuardPolicy>
1067             threadAndroidPolicy = new ThreadLocal<AndroidBlockGuardPolicy>() {
1068         @Override
1069         protected AndroidBlockGuardPolicy initialValue() {
1070             return new AndroidBlockGuardPolicy(0);
1071         }
1072     };
1073 
tooManyViolationsThisLoop()1074     private static boolean tooManyViolationsThisLoop() {
1075         return violationsBeingTimed.get().size() >= MAX_OFFENSES_PER_LOOP;
1076     }
1077 
1078     private static class AndroidBlockGuardPolicy implements BlockGuard.Policy {
1079         private int mPolicyMask;
1080 
1081         // Map from violation stacktrace hashcode -> uptimeMillis of
1082         // last violation.  No locking needed, as this is only
1083         // accessed by the same thread.
1084         private ArrayMap<Integer, Long> mLastViolationTime;
1085 
AndroidBlockGuardPolicy(final int policyMask)1086         public AndroidBlockGuardPolicy(final int policyMask) {
1087             mPolicyMask = policyMask;
1088         }
1089 
1090         @Override
toString()1091         public String toString() {
1092             return "AndroidBlockGuardPolicy; mPolicyMask=" + mPolicyMask;
1093         }
1094 
1095         // Part of BlockGuard.Policy interface:
getPolicyMask()1096         public int getPolicyMask() {
1097             return mPolicyMask;
1098         }
1099 
1100         // Part of BlockGuard.Policy interface:
onWriteToDisk()1101         public void onWriteToDisk() {
1102             if ((mPolicyMask & DETECT_DISK_WRITE) == 0) {
1103                 return;
1104             }
1105             if (tooManyViolationsThisLoop()) {
1106                 return;
1107             }
1108             BlockGuard.BlockGuardPolicyException e = new StrictModeDiskWriteViolation(mPolicyMask);
1109             e.fillInStackTrace();
1110             startHandlingViolationException(e);
1111         }
1112 
1113         // Not part of BlockGuard.Policy; just part of StrictMode:
onCustomSlowCall(String name)1114         void onCustomSlowCall(String name) {
1115             if ((mPolicyMask & DETECT_CUSTOM) == 0) {
1116                 return;
1117             }
1118             if (tooManyViolationsThisLoop()) {
1119                 return;
1120             }
1121             BlockGuard.BlockGuardPolicyException e = new StrictModeCustomViolation(mPolicyMask, name);
1122             e.fillInStackTrace();
1123             startHandlingViolationException(e);
1124         }
1125 
1126         // Part of BlockGuard.Policy interface:
onReadFromDisk()1127         public void onReadFromDisk() {
1128             if ((mPolicyMask & DETECT_DISK_READ) == 0) {
1129                 return;
1130             }
1131             if (tooManyViolationsThisLoop()) {
1132                 return;
1133             }
1134             BlockGuard.BlockGuardPolicyException e = new StrictModeDiskReadViolation(mPolicyMask);
1135             e.fillInStackTrace();
1136             startHandlingViolationException(e);
1137         }
1138 
1139         // Part of BlockGuard.Policy interface:
onNetwork()1140         public void onNetwork() {
1141             if ((mPolicyMask & DETECT_NETWORK) == 0) {
1142                 return;
1143             }
1144             if ((mPolicyMask & PENALTY_DEATH_ON_NETWORK) != 0) {
1145                 throw new NetworkOnMainThreadException();
1146             }
1147             if (tooManyViolationsThisLoop()) {
1148                 return;
1149             }
1150             BlockGuard.BlockGuardPolicyException e = new StrictModeNetworkViolation(mPolicyMask);
1151             e.fillInStackTrace();
1152             startHandlingViolationException(e);
1153         }
1154 
setPolicyMask(int policyMask)1155         public void setPolicyMask(int policyMask) {
1156             mPolicyMask = policyMask;
1157         }
1158 
1159         // Start handling a violation that just started and hasn't
1160         // actually run yet (e.g. no disk write or network operation
1161         // has yet occurred).  This sees if we're in an event loop
1162         // thread and, if so, uses it to roughly measure how long the
1163         // violation took.
startHandlingViolationException(BlockGuard.BlockGuardPolicyException e)1164         void startHandlingViolationException(BlockGuard.BlockGuardPolicyException e) {
1165             final ViolationInfo info = new ViolationInfo(e, e.getPolicy());
1166             info.violationUptimeMillis = SystemClock.uptimeMillis();
1167             handleViolationWithTimingAttempt(info);
1168         }
1169 
1170         // Attempts to fill in the provided ViolationInfo's
1171         // durationMillis field if this thread has a Looper we can use
1172         // to measure with.  We measure from the time of violation
1173         // until the time the looper is idle again (right before
1174         // the next epoll_wait)
handleViolationWithTimingAttempt(final ViolationInfo info)1175         void handleViolationWithTimingAttempt(final ViolationInfo info) {
1176             Looper looper = Looper.myLooper();
1177 
1178             // Without a Looper, we're unable to time how long the
1179             // violation takes place.  This case should be rare, as
1180             // most users will care about timing violations that
1181             // happen on their main UI thread.  Note that this case is
1182             // also hit when a violation takes place in a Binder
1183             // thread, in "gather" mode.  In this case, the duration
1184             // of the violation is computed by the ultimate caller and
1185             // its Looper, if any.
1186             //
1187             // Also, as a special short-cut case when the only penalty
1188             // bit is death, we die immediately, rather than timing
1189             // the violation's duration.  This makes it convenient to
1190             // use in unit tests too, rather than waiting on a Looper.
1191             //
1192             // TODO: if in gather mode, ignore Looper.myLooper() and always
1193             //       go into this immediate mode?
1194             if (looper == null ||
1195                 (info.policy & THREAD_PENALTY_MASK) == PENALTY_DEATH) {
1196                 info.durationMillis = -1;  // unknown (redundant, already set)
1197                 handleViolation(info);
1198                 return;
1199             }
1200 
1201             final ArrayList<ViolationInfo> records = violationsBeingTimed.get();
1202             if (records.size() >= MAX_OFFENSES_PER_LOOP) {
1203                 // Not worth measuring.  Too many offenses in one loop.
1204                 return;
1205             }
1206             records.add(info);
1207             if (records.size() > 1) {
1208                 // There's already been a violation this loop, so we've already
1209                 // registered an idle handler to process the list of violations
1210                 // at the end of this Looper's loop.
1211                 return;
1212             }
1213 
1214             final IWindowManager windowManager = (info.policy & PENALTY_FLASH) != 0 ?
1215                     sWindowManager.get() : null;
1216             if (windowManager != null) {
1217                 try {
1218                     windowManager.showStrictModeViolation(true);
1219                 } catch (RemoteException unused) {
1220                 }
1221             }
1222 
1223             // We post a runnable to a Handler (== delay 0 ms) for
1224             // measuring the end time of a violation instead of using
1225             // an IdleHandler (as was previously used) because an
1226             // IdleHandler may not run for quite a long period of time
1227             // if an ongoing animation is happening and continually
1228             // posting ASAP (0 ms) animation steps.  Animations are
1229             // throttled back to 60fps via SurfaceFlinger/View
1230             // invalidates, _not_ by posting frame updates every 16
1231             // milliseconds.
1232             threadHandler.get().postAtFrontOfQueue(new Runnable() {
1233                     public void run() {
1234                         long loopFinishTime = SystemClock.uptimeMillis();
1235 
1236                         // Note: we do this early, before handling the
1237                         // violation below, as handling the violation
1238                         // may include PENALTY_DEATH and we don't want
1239                         // to keep the red border on.
1240                         if (windowManager != null) {
1241                             try {
1242                                 windowManager.showStrictModeViolation(false);
1243                             } catch (RemoteException unused) {
1244                             }
1245                         }
1246 
1247                         for (int n = 0; n < records.size(); ++n) {
1248                             ViolationInfo v = records.get(n);
1249                             v.violationNumThisLoop = n + 1;
1250                             v.durationMillis =
1251                                     (int) (loopFinishTime - v.violationUptimeMillis);
1252                             handleViolation(v);
1253                         }
1254                         records.clear();
1255                     }
1256                 });
1257         }
1258 
1259         // Note: It's possible (even quite likely) that the
1260         // thread-local policy mask has changed from the time the
1261         // violation fired and now (after the violating code ran) due
1262         // to people who push/pop temporary policy in regions of code,
1263         // hence the policy being passed around.
handleViolation(final ViolationInfo info)1264         void handleViolation(final ViolationInfo info) {
1265             if (info == null || info.crashInfo == null || info.crashInfo.stackTrace == null) {
1266                 Log.wtf(TAG, "unexpected null stacktrace");
1267                 return;
1268             }
1269 
1270             if (LOG_V) Log.d(TAG, "handleViolation; policy=" + info.policy);
1271 
1272             if ((info.policy & PENALTY_GATHER) != 0) {
1273                 ArrayList<ViolationInfo> violations = gatheredViolations.get();
1274                 if (violations == null) {
1275                     violations = new ArrayList<ViolationInfo>(1);
1276                     gatheredViolations.set(violations);
1277                 } else if (violations.size() >= 5) {
1278                     // Too many.  In a loop or something?  Don't gather them all.
1279                     return;
1280                 }
1281                 for (ViolationInfo previous : violations) {
1282                     if (info.crashInfo.stackTrace.equals(previous.crashInfo.stackTrace)) {
1283                         // Duplicate. Don't log.
1284                         return;
1285                     }
1286                 }
1287                 violations.add(info);
1288                 return;
1289             }
1290 
1291             // Not perfect, but fast and good enough for dup suppression.
1292             Integer crashFingerprint = info.hashCode();
1293             long lastViolationTime = 0;
1294             if (mLastViolationTime != null) {
1295                 Long vtime = mLastViolationTime.get(crashFingerprint);
1296                 if (vtime != null) {
1297                     lastViolationTime = vtime;
1298                 }
1299             } else {
1300                 mLastViolationTime = new ArrayMap<Integer, Long>(1);
1301             }
1302             long now = SystemClock.uptimeMillis();
1303             mLastViolationTime.put(crashFingerprint, now);
1304             long timeSinceLastViolationMillis = lastViolationTime == 0 ?
1305                     Long.MAX_VALUE : (now - lastViolationTime);
1306 
1307             if ((info.policy & PENALTY_LOG) != 0 &&
1308                 timeSinceLastViolationMillis > MIN_LOG_INTERVAL_MS) {
1309                 if (info.durationMillis != -1) {
1310                     Log.d(TAG, "StrictMode policy violation; ~duration=" +
1311                           info.durationMillis + " ms: " + info.crashInfo.stackTrace);
1312                 } else {
1313                     Log.d(TAG, "StrictMode policy violation: " + info.crashInfo.stackTrace);
1314                 }
1315             }
1316 
1317             // The violationMaskSubset, passed to ActivityManager, is a
1318             // subset of the original StrictMode policy bitmask, with
1319             // only the bit violated and penalty bits to be executed
1320             // by the ActivityManagerService remaining set.
1321             int violationMaskSubset = 0;
1322 
1323             if ((info.policy & PENALTY_DIALOG) != 0 &&
1324                 timeSinceLastViolationMillis > MIN_DIALOG_INTERVAL_MS) {
1325                 violationMaskSubset |= PENALTY_DIALOG;
1326             }
1327 
1328             if ((info.policy & PENALTY_DROPBOX) != 0 && lastViolationTime == 0) {
1329                 violationMaskSubset |= PENALTY_DROPBOX;
1330             }
1331 
1332             if (violationMaskSubset != 0) {
1333                 int violationBit = parseViolationFromMessage(info.crashInfo.exceptionMessage);
1334                 violationMaskSubset |= violationBit;
1335                 final int savedPolicyMask = getThreadPolicyMask();
1336 
1337                 final boolean justDropBox = (info.policy & THREAD_PENALTY_MASK) == PENALTY_DROPBOX;
1338                 if (justDropBox) {
1339                     // If all we're going to ask the activity manager
1340                     // to do is dropbox it (the common case during
1341                     // platform development), we can avoid doing this
1342                     // call synchronously which Binder data suggests
1343                     // isn't always super fast, despite the implementation
1344                     // in the ActivityManager trying to be mostly async.
1345                     dropboxViolationAsync(violationMaskSubset, info);
1346                     return;
1347                 }
1348 
1349                 // Normal synchronous call to the ActivityManager.
1350                 try {
1351                     // First, remove any policy before we call into the Activity Manager,
1352                     // otherwise we'll infinite recurse as we try to log policy violations
1353                     // to disk, thus violating policy, thus requiring logging, etc...
1354                     // We restore the current policy below, in the finally block.
1355                     setThreadPolicyMask(0);
1356 
1357                     ActivityManagerNative.getDefault().handleApplicationStrictModeViolation(
1358                         RuntimeInit.getApplicationObject(),
1359                         violationMaskSubset,
1360                         info);
1361                 } catch (RemoteException e) {
1362                     Log.e(TAG, "RemoteException trying to handle StrictMode violation", e);
1363                 } finally {
1364                     // Restore the policy.
1365                     setThreadPolicyMask(savedPolicyMask);
1366                 }
1367             }
1368 
1369             if ((info.policy & PENALTY_DEATH) != 0) {
1370                 executeDeathPenalty(info);
1371             }
1372         }
1373     }
1374 
executeDeathPenalty(ViolationInfo info)1375     private static void executeDeathPenalty(ViolationInfo info) {
1376         int violationBit = parseViolationFromMessage(info.crashInfo.exceptionMessage);
1377         throw new StrictModeViolation(info.policy, violationBit, null);
1378     }
1379 
1380     /**
1381      * In the common case, as set by conditionallyEnableDebugLogging,
1382      * we're just dropboxing any violations but not showing a dialog,
1383      * not loggging, and not killing the process.  In these cases we
1384      * don't need to do a synchronous call to the ActivityManager.
1385      * This is used by both per-thread and vm-wide violations when
1386      * applicable.
1387      */
dropboxViolationAsync( final int violationMaskSubset, final ViolationInfo info)1388     private static void dropboxViolationAsync(
1389             final int violationMaskSubset, final ViolationInfo info) {
1390         int outstanding = sDropboxCallsInFlight.incrementAndGet();
1391         if (outstanding > 20) {
1392             // What's going on?  Let's not make make the situation
1393             // worse and just not log.
1394             sDropboxCallsInFlight.decrementAndGet();
1395             return;
1396         }
1397 
1398         if (LOG_V) Log.d(TAG, "Dropboxing async; in-flight=" + outstanding);
1399 
1400         new Thread("callActivityManagerForStrictModeDropbox") {
1401             public void run() {
1402                 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
1403                 try {
1404                     IActivityManager am = ActivityManagerNative.getDefault();
1405                     if (am == null) {
1406                         Log.d(TAG, "No activity manager; failed to Dropbox violation.");
1407                     } else {
1408                         am.handleApplicationStrictModeViolation(
1409                             RuntimeInit.getApplicationObject(),
1410                             violationMaskSubset,
1411                             info);
1412                     }
1413                 } catch (RemoteException e) {
1414                     Log.e(TAG, "RemoteException handling StrictMode violation", e);
1415                 }
1416                 int outstanding = sDropboxCallsInFlight.decrementAndGet();
1417                 if (LOG_V) Log.d(TAG, "Dropbox complete; in-flight=" + outstanding);
1418             }
1419         }.start();
1420     }
1421 
1422     private static class AndroidCloseGuardReporter implements CloseGuard.Reporter {
report(String message, Throwable allocationSite)1423         public void report (String message, Throwable allocationSite) {
1424             onVmPolicyViolation(message, allocationSite);
1425         }
1426     }
1427 
1428     /**
1429      * Called from Parcel.writeNoException()
1430      */
hasGatheredViolations()1431     /* package */ static boolean hasGatheredViolations() {
1432         return gatheredViolations.get() != null;
1433     }
1434 
1435     /**
1436      * Called from Parcel.writeException(), so we drop this memory and
1437      * don't incorrectly attribute it to the wrong caller on the next
1438      * Binder call on this thread.
1439      */
clearGatheredViolations()1440     /* package */ static void clearGatheredViolations() {
1441         gatheredViolations.set(null);
1442     }
1443 
1444     /**
1445      * @hide
1446      */
conditionallyCheckInstanceCounts()1447     public static void conditionallyCheckInstanceCounts() {
1448         VmPolicy policy = getVmPolicy();
1449         if (policy.classInstanceLimit.size() == 0) {
1450             return;
1451         }
1452         Runtime.getRuntime().gc();
1453         // Note: classInstanceLimit is immutable, so this is lock-free
1454         for (Map.Entry<Class, Integer> entry : policy.classInstanceLimit.entrySet()) {
1455             Class klass = entry.getKey();
1456             int limit = entry.getValue();
1457             long instances = VMDebug.countInstancesOfClass(klass, false);
1458             if (instances <= limit) {
1459                 continue;
1460             }
1461             Throwable tr = new InstanceCountViolation(klass, instances, limit);
1462             onVmPolicyViolation(tr.getMessage(), tr);
1463         }
1464     }
1465 
1466     private static long sLastInstanceCountCheckMillis = 0;
1467     private static boolean sIsIdlerRegistered = false;  // guarded by StrictMode.class
1468     private static final MessageQueue.IdleHandler sProcessIdleHandler =
1469             new MessageQueue.IdleHandler() {
1470                 public boolean queueIdle() {
1471                     long now = SystemClock.uptimeMillis();
1472                     if (now - sLastInstanceCountCheckMillis > 30 * 1000) {
1473                         sLastInstanceCountCheckMillis = now;
1474                         conditionallyCheckInstanceCounts();
1475                     }
1476                     return true;
1477                 }
1478             };
1479 
1480     /**
1481      * Sets the policy for what actions in the VM process (on any
1482      * thread) should be detected, as well as the penalty if such
1483      * actions occur.
1484      *
1485      * @param policy the policy to put into place
1486      */
setVmPolicy(final VmPolicy policy)1487     public static void setVmPolicy(final VmPolicy policy) {
1488         synchronized (StrictMode.class) {
1489             sVmPolicy = policy;
1490             sVmPolicyMask = policy.mask;
1491             setCloseGuardEnabled(vmClosableObjectLeaksEnabled());
1492 
1493             Looper looper = Looper.getMainLooper();
1494             if (looper != null) {
1495                 MessageQueue mq = looper.mQueue;
1496                 if (policy.classInstanceLimit.size() == 0 ||
1497                     (sVmPolicyMask & VM_PENALTY_MASK) == 0) {
1498                     mq.removeIdleHandler(sProcessIdleHandler);
1499                     sIsIdlerRegistered = false;
1500                 } else if (!sIsIdlerRegistered) {
1501                     mq.addIdleHandler(sProcessIdleHandler);
1502                     sIsIdlerRegistered = true;
1503                 }
1504             }
1505         }
1506     }
1507 
1508     /**
1509      * Gets the current VM policy.
1510      */
getVmPolicy()1511     public static VmPolicy getVmPolicy() {
1512         synchronized (StrictMode.class) {
1513             return sVmPolicy;
1514         }
1515     }
1516 
1517     /**
1518      * Enable the recommended StrictMode defaults, with violations just being logged.
1519      *
1520      * <p>This catches disk and network access on the main thread, as
1521      * well as leaked SQLite cursors and unclosed resources.  This is
1522      * simply a wrapper around {@link #setVmPolicy} and {@link
1523      * #setThreadPolicy}.
1524      */
enableDefaults()1525     public static void enableDefaults() {
1526         StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
1527                                    .detectAll()
1528                                    .penaltyLog()
1529                                    .build());
1530         StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
1531                                .detectAll()
1532                                .penaltyLog()
1533                                .build());
1534     }
1535 
1536     /**
1537      * @hide
1538      */
vmSqliteObjectLeaksEnabled()1539     public static boolean vmSqliteObjectLeaksEnabled() {
1540         return (sVmPolicyMask & DETECT_VM_CURSOR_LEAKS) != 0;
1541     }
1542 
1543     /**
1544      * @hide
1545      */
vmClosableObjectLeaksEnabled()1546     public static boolean vmClosableObjectLeaksEnabled() {
1547         return (sVmPolicyMask & DETECT_VM_CLOSABLE_LEAKS) != 0;
1548     }
1549 
1550     /**
1551      * @hide
1552      */
vmRegistrationLeaksEnabled()1553     public static boolean vmRegistrationLeaksEnabled() {
1554         return (sVmPolicyMask & DETECT_VM_REGISTRATION_LEAKS) != 0;
1555     }
1556 
1557     /**
1558      * @hide
1559      */
vmFileUriExposureEnabled()1560     public static boolean vmFileUriExposureEnabled() {
1561         return (sVmPolicyMask & DETECT_VM_FILE_URI_EXPOSURE) != 0;
1562     }
1563 
1564     /**
1565      * @hide
1566      */
onSqliteObjectLeaked(String message, Throwable originStack)1567     public static void onSqliteObjectLeaked(String message, Throwable originStack) {
1568         onVmPolicyViolation(message, originStack);
1569     }
1570 
1571     /**
1572      * @hide
1573      */
onWebViewMethodCalledOnWrongThread(Throwable originStack)1574     public static void onWebViewMethodCalledOnWrongThread(Throwable originStack) {
1575         onVmPolicyViolation(null, originStack);
1576     }
1577 
1578     /**
1579      * @hide
1580      */
onIntentReceiverLeaked(Throwable originStack)1581     public static void onIntentReceiverLeaked(Throwable originStack) {
1582         onVmPolicyViolation(null, originStack);
1583     }
1584 
1585     /**
1586      * @hide
1587      */
onServiceConnectionLeaked(Throwable originStack)1588     public static void onServiceConnectionLeaked(Throwable originStack) {
1589         onVmPolicyViolation(null, originStack);
1590     }
1591 
1592     /**
1593      * @hide
1594      */
onFileUriExposed(String location)1595     public static void onFileUriExposed(String location) {
1596         final String message = "file:// Uri exposed through " + location;
1597         onVmPolicyViolation(message, new Throwable(message));
1598     }
1599 
1600     // Map from VM violation fingerprint to uptime millis.
1601     private static final HashMap<Integer, Long> sLastVmViolationTime = new HashMap<Integer, Long>();
1602 
1603     /**
1604      * @hide
1605      */
onVmPolicyViolation(String message, Throwable originStack)1606     public static void onVmPolicyViolation(String message, Throwable originStack) {
1607         final boolean penaltyDropbox = (sVmPolicyMask & PENALTY_DROPBOX) != 0;
1608         final boolean penaltyDeath = (sVmPolicyMask & PENALTY_DEATH) != 0;
1609         final boolean penaltyLog = (sVmPolicyMask & PENALTY_LOG) != 0;
1610         final ViolationInfo info = new ViolationInfo(originStack, sVmPolicyMask);
1611 
1612         // Erase stuff not relevant for process-wide violations
1613         info.numAnimationsRunning = 0;
1614         info.tags = null;
1615         info.broadcastIntentAction = null;
1616 
1617         final Integer fingerprint = info.hashCode();
1618         final long now = SystemClock.uptimeMillis();
1619         long lastViolationTime = 0;
1620         long timeSinceLastViolationMillis = Long.MAX_VALUE;
1621         synchronized (sLastVmViolationTime) {
1622             if (sLastVmViolationTime.containsKey(fingerprint)) {
1623                 lastViolationTime = sLastVmViolationTime.get(fingerprint);
1624                 timeSinceLastViolationMillis = now - lastViolationTime;
1625             }
1626             if (timeSinceLastViolationMillis > MIN_LOG_INTERVAL_MS) {
1627                 sLastVmViolationTime.put(fingerprint, now);
1628             }
1629         }
1630 
1631         if (penaltyLog && timeSinceLastViolationMillis > MIN_LOG_INTERVAL_MS) {
1632             Log.e(TAG, message, originStack);
1633         }
1634 
1635         int violationMaskSubset = PENALTY_DROPBOX | (ALL_VM_DETECT_BITS & sVmPolicyMask);
1636 
1637         if (penaltyDropbox && !penaltyDeath) {
1638             // Common case for userdebug/eng builds.  If no death and
1639             // just dropboxing, we can do the ActivityManager call
1640             // asynchronously.
1641             dropboxViolationAsync(violationMaskSubset, info);
1642             return;
1643         }
1644 
1645         if (penaltyDropbox && lastViolationTime == 0) {
1646             // The violationMask, passed to ActivityManager, is a
1647             // subset of the original StrictMode policy bitmask, with
1648             // only the bit violated and penalty bits to be executed
1649             // by the ActivityManagerService remaining set.
1650             final int savedPolicyMask = getThreadPolicyMask();
1651             try {
1652                 // First, remove any policy before we call into the Activity Manager,
1653                 // otherwise we'll infinite recurse as we try to log policy violations
1654                 // to disk, thus violating policy, thus requiring logging, etc...
1655                 // We restore the current policy below, in the finally block.
1656                 setThreadPolicyMask(0);
1657 
1658                 ActivityManagerNative.getDefault().handleApplicationStrictModeViolation(
1659                     RuntimeInit.getApplicationObject(),
1660                     violationMaskSubset,
1661                     info);
1662             } catch (RemoteException e) {
1663                 Log.e(TAG, "RemoteException trying to handle StrictMode violation", e);
1664             } finally {
1665                 // Restore the policy.
1666                 setThreadPolicyMask(savedPolicyMask);
1667             }
1668         }
1669 
1670         if (penaltyDeath) {
1671             System.err.println("StrictMode VmPolicy violation with POLICY_DEATH; shutting down.");
1672             Process.killProcess(Process.myPid());
1673             System.exit(10);
1674         }
1675     }
1676 
1677     /**
1678      * Called from Parcel.writeNoException()
1679      */
writeGatheredViolationsToParcel(Parcel p)1680     /* package */ static void writeGatheredViolationsToParcel(Parcel p) {
1681         ArrayList<ViolationInfo> violations = gatheredViolations.get();
1682         if (violations == null) {
1683             p.writeInt(0);
1684         } else {
1685             p.writeInt(violations.size());
1686             for (int i = 0; i < violations.size(); ++i) {
1687                 violations.get(i).writeToParcel(p, 0 /* unused flags? */);
1688             }
1689             if (LOG_V) Log.d(TAG, "wrote violations to response parcel; num=" + violations.size());
1690             violations.clear(); // somewhat redundant, as we're about to null the threadlocal
1691         }
1692         gatheredViolations.set(null);
1693     }
1694 
1695     private static class LogStackTrace extends Exception {}
1696 
1697     /**
1698      * Called from Parcel.readException() when the exception is EX_STRICT_MODE_VIOLATIONS,
1699      * we here read back all the encoded violations.
1700      */
readAndHandleBinderCallViolations(Parcel p)1701     /* package */ static void readAndHandleBinderCallViolations(Parcel p) {
1702         // Our own stack trace to append
1703         StringWriter sw = new StringWriter();
1704         PrintWriter pw = new FastPrintWriter(sw, false, 256);
1705         new LogStackTrace().printStackTrace(pw);
1706         pw.flush();
1707         String ourStack = sw.toString();
1708 
1709         int policyMask = getThreadPolicyMask();
1710         boolean currentlyGathering = (policyMask & PENALTY_GATHER) != 0;
1711 
1712         int numViolations = p.readInt();
1713         for (int i = 0; i < numViolations; ++i) {
1714             if (LOG_V) Log.d(TAG, "strict mode violation stacks read from binder call.  i=" + i);
1715             ViolationInfo info = new ViolationInfo(p, !currentlyGathering);
1716             info.crashInfo.stackTrace += "# via Binder call with stack:\n" + ourStack;
1717             BlockGuard.Policy policy = BlockGuard.getThreadPolicy();
1718             if (policy instanceof AndroidBlockGuardPolicy) {
1719                 ((AndroidBlockGuardPolicy) policy).handleViolationWithTimingAttempt(info);
1720             }
1721         }
1722     }
1723 
1724     /**
1725      * Called from android_util_Binder.cpp's
1726      * android_os_Parcel_enforceInterface when an incoming Binder call
1727      * requires changing the StrictMode policy mask.  The role of this
1728      * function is to ask Binder for its current (native) thread-local
1729      * policy value and synchronize it to libcore's (Java)
1730      * thread-local policy value.
1731      */
onBinderStrictModePolicyChange(int newPolicy)1732     private static void onBinderStrictModePolicyChange(int newPolicy) {
1733         setBlockGuardPolicy(newPolicy);
1734     }
1735 
1736     /**
1737      * A tracked, critical time span.  (e.g. during an animation.)
1738      *
1739      * The object itself is a linked list node, to avoid any allocations
1740      * during rapid span entries and exits.
1741      *
1742      * @hide
1743      */
1744     public static class Span {
1745         private String mName;
1746         private long mCreateMillis;
1747         private Span mNext;
1748         private Span mPrev;  // not used when in freeList, only active
1749         private final ThreadSpanState mContainerState;
1750 
Span(ThreadSpanState threadState)1751         Span(ThreadSpanState threadState) {
1752             mContainerState = threadState;
1753         }
1754 
1755         // Empty constructor for the NO_OP_SPAN
Span()1756         protected Span() {
1757             mContainerState = null;
1758         }
1759 
1760         /**
1761          * To be called when the critical span is complete (i.e. the
1762          * animation is done animating).  This can be called on any
1763          * thread (even a different one from where the animation was
1764          * taking place), but that's only a defensive implementation
1765          * measure.  It really makes no sense for you to call this on
1766          * thread other than that where you created it.
1767          *
1768          * @hide
1769          */
finish()1770         public void finish() {
1771             ThreadSpanState state = mContainerState;
1772             synchronized (state) {
1773                 if (mName == null) {
1774                     // Duplicate finish call.  Ignore.
1775                     return;
1776                 }
1777 
1778                 // Remove ourselves from the active list.
1779                 if (mPrev != null) {
1780                     mPrev.mNext = mNext;
1781                 }
1782                 if (mNext != null) {
1783                     mNext.mPrev = mPrev;
1784                 }
1785                 if (state.mActiveHead == this) {
1786                     state.mActiveHead = mNext;
1787                 }
1788 
1789                 state.mActiveSize--;
1790 
1791                 if (LOG_V) Log.d(TAG, "Span finished=" + mName + "; size=" + state.mActiveSize);
1792 
1793                 this.mCreateMillis = -1;
1794                 this.mName = null;
1795                 this.mPrev = null;
1796                 this.mNext = null;
1797 
1798                 // Add ourselves to the freeList, if it's not already
1799                 // too big.
1800                 if (state.mFreeListSize < 5) {
1801                     this.mNext = state.mFreeListHead;
1802                     state.mFreeListHead = this;
1803                     state.mFreeListSize++;
1804                 }
1805             }
1806         }
1807     }
1808 
1809     // The no-op span that's used in user builds.
1810     private static final Span NO_OP_SPAN = new Span() {
1811             public void finish() {
1812                 // Do nothing.
1813             }
1814         };
1815 
1816     /**
1817      * Linked lists of active spans and a freelist.
1818      *
1819      * Locking notes: there's one of these structures per thread and
1820      * all members of this structure (as well as the Span nodes under
1821      * it) are guarded by the ThreadSpanState object instance.  While
1822      * in theory there'd be no locking required because it's all local
1823      * per-thread, the finish() method above is defensive against
1824      * people calling it on a different thread from where they created
1825      * the Span, hence the locking.
1826      */
1827     private static class ThreadSpanState {
1828         public Span mActiveHead;    // doubly-linked list.
1829         public int mActiveSize;
1830         public Span mFreeListHead;  // singly-linked list.  only changes at head.
1831         public int mFreeListSize;
1832     }
1833 
1834     private static final ThreadLocal<ThreadSpanState> sThisThreadSpanState =
1835             new ThreadLocal<ThreadSpanState>() {
1836         @Override protected ThreadSpanState initialValue() {
1837             return new ThreadSpanState();
1838         }
1839     };
1840 
1841     private static Singleton<IWindowManager> sWindowManager = new Singleton<IWindowManager>() {
1842         protected IWindowManager create() {
1843             return IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
1844         }
1845     };
1846 
1847     /**
1848      * Enter a named critical span (e.g. an animation)
1849      *
1850      * <p>The name is an arbitary label (or tag) that will be applied
1851      * to any strictmode violation that happens while this span is
1852      * active.  You must call finish() on the span when done.
1853      *
1854      * <p>This will never return null, but on devices without debugging
1855      * enabled, this may return a dummy object on which the finish()
1856      * method is a no-op.
1857      *
1858      * <p>TODO: add CloseGuard to this, verifying callers call finish.
1859      *
1860      * @hide
1861      */
enterCriticalSpan(String name)1862     public static Span enterCriticalSpan(String name) {
1863         if (IS_USER_BUILD) {
1864             return NO_OP_SPAN;
1865         }
1866         if (name == null || name.isEmpty()) {
1867             throw new IllegalArgumentException("name must be non-null and non-empty");
1868         }
1869         ThreadSpanState state = sThisThreadSpanState.get();
1870         Span span = null;
1871         synchronized (state) {
1872             if (state.mFreeListHead != null) {
1873                 span = state.mFreeListHead;
1874                 state.mFreeListHead = span.mNext;
1875                 state.mFreeListSize--;
1876             } else {
1877                 // Shouldn't have to do this often.
1878                 span = new Span(state);
1879             }
1880             span.mName = name;
1881             span.mCreateMillis = SystemClock.uptimeMillis();
1882             span.mNext = state.mActiveHead;
1883             span.mPrev = null;
1884             state.mActiveHead = span;
1885             state.mActiveSize++;
1886             if (span.mNext != null) {
1887                 span.mNext.mPrev = span;
1888             }
1889             if (LOG_V) Log.d(TAG, "Span enter=" + name + "; size=" + state.mActiveSize);
1890         }
1891         return span;
1892     }
1893 
1894     /**
1895      * For code to note that it's slow.  This is a no-op unless the
1896      * current thread's {@link android.os.StrictMode.ThreadPolicy} has
1897      * {@link android.os.StrictMode.ThreadPolicy.Builder#detectCustomSlowCalls}
1898      * enabled.
1899      *
1900      * @param name a short string for the exception stack trace that's
1901      *             built if when this fires.
1902      */
noteSlowCall(String name)1903     public static void noteSlowCall(String name) {
1904         BlockGuard.Policy policy = BlockGuard.getThreadPolicy();
1905         if (!(policy instanceof AndroidBlockGuardPolicy)) {
1906             // StrictMode not enabled.
1907             return;
1908         }
1909         ((AndroidBlockGuardPolicy) policy).onCustomSlowCall(name);
1910     }
1911 
1912     /**
1913      * @hide
1914      */
noteDiskRead()1915     public static void noteDiskRead() {
1916         BlockGuard.Policy policy = BlockGuard.getThreadPolicy();
1917         if (!(policy instanceof AndroidBlockGuardPolicy)) {
1918             // StrictMode not enabled.
1919             return;
1920         }
1921         ((AndroidBlockGuardPolicy) policy).onReadFromDisk();
1922     }
1923 
1924     /**
1925      * @hide
1926      */
noteDiskWrite()1927     public static void noteDiskWrite() {
1928         BlockGuard.Policy policy = BlockGuard.getThreadPolicy();
1929         if (!(policy instanceof AndroidBlockGuardPolicy)) {
1930             // StrictMode not enabled.
1931             return;
1932         }
1933         ((AndroidBlockGuardPolicy) policy).onWriteToDisk();
1934     }
1935 
1936     // Guarded by StrictMode.class
1937     private static final HashMap<Class, Integer> sExpectedActivityInstanceCount =
1938             new HashMap<Class, Integer>();
1939 
1940     /**
1941      * Returns an object that is used to track instances of activites.
1942      * The activity should store a reference to the tracker object in one of its fields.
1943      * @hide
1944      */
trackActivity(Object instance)1945     public static Object trackActivity(Object instance) {
1946         return new InstanceTracker(instance);
1947     }
1948 
1949     /**
1950      * @hide
1951      */
incrementExpectedActivityCount(Class klass)1952     public static void incrementExpectedActivityCount(Class klass) {
1953         if (klass == null) {
1954             return;
1955         }
1956 
1957         synchronized (StrictMode.class) {
1958             if ((sVmPolicy.mask & DETECT_VM_ACTIVITY_LEAKS) == 0) {
1959                 return;
1960             }
1961 
1962             Integer expected = sExpectedActivityInstanceCount.get(klass);
1963             Integer newExpected = expected == null ? 1 : expected + 1;
1964             sExpectedActivityInstanceCount.put(klass, newExpected);
1965         }
1966     }
1967 
1968     /**
1969      * @hide
1970      */
decrementExpectedActivityCount(Class klass)1971     public static void decrementExpectedActivityCount(Class klass) {
1972         if (klass == null) {
1973             return;
1974         }
1975 
1976         final int limit;
1977         synchronized (StrictMode.class) {
1978             if ((sVmPolicy.mask & DETECT_VM_ACTIVITY_LEAKS) == 0) {
1979                 return;
1980             }
1981 
1982             Integer expected = sExpectedActivityInstanceCount.get(klass);
1983             int newExpected = (expected == null || expected == 0) ? 0 : expected - 1;
1984             if (newExpected == 0) {
1985                 sExpectedActivityInstanceCount.remove(klass);
1986             } else {
1987                 sExpectedActivityInstanceCount.put(klass, newExpected);
1988             }
1989 
1990             // Note: adding 1 here to give some breathing room during
1991             // orientation changes.  (shouldn't be necessary, though?)
1992             limit = newExpected + 1;
1993         }
1994 
1995         // Quick check.
1996         int actual = InstanceTracker.getInstanceCount(klass);
1997         if (actual <= limit) {
1998             return;
1999         }
2000 
2001         // Do a GC and explicit count to double-check.
2002         // This is the work that we are trying to avoid by tracking the object instances
2003         // explicity.  Running an explicit GC can be expensive (80ms) and so can walking
2004         // the heap to count instance (30ms).  This extra work can make the system feel
2005         // noticeably less responsive during orientation changes when activities are
2006         // being restarted.  Granted, it is only a problem when StrictMode is enabled
2007         // but it is annoying.
2008         Runtime.getRuntime().gc();
2009 
2010         long instances = VMDebug.countInstancesOfClass(klass, false);
2011         if (instances > limit) {
2012             Throwable tr = new InstanceCountViolation(klass, instances, limit);
2013             onVmPolicyViolation(tr.getMessage(), tr);
2014         }
2015     }
2016 
2017     /**
2018      * Parcelable that gets sent in Binder call headers back to callers
2019      * to report violations that happened during a cross-process call.
2020      *
2021      * @hide
2022      */
2023     public static class ViolationInfo {
2024         /**
2025          * Stack and other stuff info.
2026          */
2027         public final ApplicationErrorReport.CrashInfo crashInfo;
2028 
2029         /**
2030          * The strict mode policy mask at the time of violation.
2031          */
2032         public final int policy;
2033 
2034         /**
2035          * The wall time duration of the violation, when known.  -1 when
2036          * not known.
2037          */
2038         public int durationMillis = -1;
2039 
2040         /**
2041          * The number of animations currently running.
2042          */
2043         public int numAnimationsRunning = 0;
2044 
2045         /**
2046          * List of tags from active Span instances during this
2047          * violation, or null for none.
2048          */
2049         public String[] tags;
2050 
2051         /**
2052          * Which violation number this was (1-based) since the last Looper loop,
2053          * from the perspective of the root caller (if it crossed any processes
2054          * via Binder calls).  The value is 0 if the root caller wasn't on a Looper
2055          * thread.
2056          */
2057         public int violationNumThisLoop;
2058 
2059         /**
2060          * The time (in terms of SystemClock.uptimeMillis()) that the
2061          * violation occurred.
2062          */
2063         public long violationUptimeMillis;
2064 
2065         /**
2066          * The action of the Intent being broadcast to somebody's onReceive
2067          * on this thread right now, or null.
2068          */
2069         public String broadcastIntentAction;
2070 
2071         /**
2072          * If this is a instance count violation, the number of instances in memory,
2073          * else -1.
2074          */
2075         public long numInstances = -1;
2076 
2077         /**
2078          * Create an uninitialized instance of ViolationInfo
2079          */
ViolationInfo()2080         public ViolationInfo() {
2081             crashInfo = null;
2082             policy = 0;
2083         }
2084 
2085         /**
2086          * Create an instance of ViolationInfo initialized from an exception.
2087          */
ViolationInfo(Throwable tr, int policy)2088         public ViolationInfo(Throwable tr, int policy) {
2089             crashInfo = new ApplicationErrorReport.CrashInfo(tr);
2090             violationUptimeMillis = SystemClock.uptimeMillis();
2091             this.policy = policy;
2092             this.numAnimationsRunning = ValueAnimator.getCurrentAnimationsCount();
2093             Intent broadcastIntent = ActivityThread.getIntentBeingBroadcast();
2094             if (broadcastIntent != null) {
2095                 broadcastIntentAction = broadcastIntent.getAction();
2096             }
2097             ThreadSpanState state = sThisThreadSpanState.get();
2098             if (tr instanceof InstanceCountViolation) {
2099                 this.numInstances = ((InstanceCountViolation) tr).mInstances;
2100             }
2101             synchronized (state) {
2102                 int spanActiveCount = state.mActiveSize;
2103                 if (spanActiveCount > MAX_SPAN_TAGS) {
2104                     spanActiveCount = MAX_SPAN_TAGS;
2105                 }
2106                 if (spanActiveCount != 0) {
2107                     this.tags = new String[spanActiveCount];
2108                     Span iter = state.mActiveHead;
2109                     int index = 0;
2110                     while (iter != null && index < spanActiveCount) {
2111                         this.tags[index] = iter.mName;
2112                         index++;
2113                         iter = iter.mNext;
2114                     }
2115                 }
2116             }
2117         }
2118 
2119         @Override
hashCode()2120         public int hashCode() {
2121             int result = 17;
2122             result = 37 * result + crashInfo.stackTrace.hashCode();
2123             if (numAnimationsRunning != 0) {
2124                 result *= 37;
2125             }
2126             if (broadcastIntentAction != null) {
2127                 result = 37 * result + broadcastIntentAction.hashCode();
2128             }
2129             if (tags != null) {
2130                 for (String tag : tags) {
2131                     result = 37 * result + tag.hashCode();
2132                 }
2133             }
2134             return result;
2135         }
2136 
2137         /**
2138          * Create an instance of ViolationInfo initialized from a Parcel.
2139          */
ViolationInfo(Parcel in)2140         public ViolationInfo(Parcel in) {
2141             this(in, false);
2142         }
2143 
2144         /**
2145          * Create an instance of ViolationInfo initialized from a Parcel.
2146          *
2147          * @param unsetGatheringBit if true, the caller is the root caller
2148          *   and the gathering penalty should be removed.
2149          */
ViolationInfo(Parcel in, boolean unsetGatheringBit)2150         public ViolationInfo(Parcel in, boolean unsetGatheringBit) {
2151             crashInfo = new ApplicationErrorReport.CrashInfo(in);
2152             int rawPolicy = in.readInt();
2153             if (unsetGatheringBit) {
2154                 policy = rawPolicy & ~PENALTY_GATHER;
2155             } else {
2156                 policy = rawPolicy;
2157             }
2158             durationMillis = in.readInt();
2159             violationNumThisLoop = in.readInt();
2160             numAnimationsRunning = in.readInt();
2161             violationUptimeMillis = in.readLong();
2162             numInstances = in.readLong();
2163             broadcastIntentAction = in.readString();
2164             tags = in.readStringArray();
2165         }
2166 
2167         /**
2168          * Save a ViolationInfo instance to a parcel.
2169          */
writeToParcel(Parcel dest, int flags)2170         public void writeToParcel(Parcel dest, int flags) {
2171             crashInfo.writeToParcel(dest, flags);
2172             dest.writeInt(policy);
2173             dest.writeInt(durationMillis);
2174             dest.writeInt(violationNumThisLoop);
2175             dest.writeInt(numAnimationsRunning);
2176             dest.writeLong(violationUptimeMillis);
2177             dest.writeLong(numInstances);
2178             dest.writeString(broadcastIntentAction);
2179             dest.writeStringArray(tags);
2180         }
2181 
2182 
2183         /**
2184          * Dump a ViolationInfo instance to a Printer.
2185          */
dump(Printer pw, String prefix)2186         public void dump(Printer pw, String prefix) {
2187             crashInfo.dump(pw, prefix);
2188             pw.println(prefix + "policy: " + policy);
2189             if (durationMillis != -1) {
2190                 pw.println(prefix + "durationMillis: " + durationMillis);
2191             }
2192             if (numInstances != -1) {
2193                 pw.println(prefix + "numInstances: " + numInstances);
2194             }
2195             if (violationNumThisLoop != 0) {
2196                 pw.println(prefix + "violationNumThisLoop: " + violationNumThisLoop);
2197             }
2198             if (numAnimationsRunning != 0) {
2199                 pw.println(prefix + "numAnimationsRunning: " + numAnimationsRunning);
2200             }
2201             pw.println(prefix + "violationUptimeMillis: " + violationUptimeMillis);
2202             if (broadcastIntentAction != null) {
2203                 pw.println(prefix + "broadcastIntentAction: " + broadcastIntentAction);
2204             }
2205             if (tags != null) {
2206                 int index = 0;
2207                 for (String tag : tags) {
2208                     pw.println(prefix + "tag[" + (index++) + "]: " + tag);
2209                 }
2210             }
2211         }
2212 
2213     }
2214 
2215     // Dummy throwable, for now, since we don't know when or where the
2216     // leaked instances came from.  We might in the future, but for
2217     // now we suppress the stack trace because it's useless and/or
2218     // misleading.
2219     private static class InstanceCountViolation extends Throwable {
2220         final Class mClass;
2221         final long mInstances;
2222         final int mLimit;
2223 
2224         private static final StackTraceElement[] FAKE_STACK = {
2225             new StackTraceElement("android.os.StrictMode", "setClassInstanceLimit",
2226                                   "StrictMode.java", 1)
2227         };
2228 
InstanceCountViolation(Class klass, long instances, int limit)2229         public InstanceCountViolation(Class klass, long instances, int limit) {
2230             super(klass.toString() + "; instances=" + instances + "; limit=" + limit);
2231             setStackTrace(FAKE_STACK);
2232             mClass = klass;
2233             mInstances = instances;
2234             mLimit = limit;
2235         }
2236     }
2237 
2238     private static final class InstanceTracker {
2239         private static final HashMap<Class<?>, Integer> sInstanceCounts =
2240                 new HashMap<Class<?>, Integer>();
2241 
2242         private final Class<?> mKlass;
2243 
InstanceTracker(Object instance)2244         public InstanceTracker(Object instance) {
2245             mKlass = instance.getClass();
2246 
2247             synchronized (sInstanceCounts) {
2248                 final Integer value = sInstanceCounts.get(mKlass);
2249                 final int newValue = value != null ? value + 1 : 1;
2250                 sInstanceCounts.put(mKlass, newValue);
2251             }
2252         }
2253 
2254         @Override
finalize()2255         protected void finalize() throws Throwable {
2256             try {
2257                 synchronized (sInstanceCounts) {
2258                     final Integer value = sInstanceCounts.get(mKlass);
2259                     if (value != null) {
2260                         final int newValue = value - 1;
2261                         if (newValue > 0) {
2262                             sInstanceCounts.put(mKlass, newValue);
2263                         } else {
2264                             sInstanceCounts.remove(mKlass);
2265                         }
2266                     }
2267                 }
2268             } finally {
2269                 super.finalize();
2270             }
2271         }
2272 
getInstanceCount(Class<?> klass)2273         public static int getInstanceCount(Class<?> klass) {
2274             synchronized (sInstanceCounts) {
2275                 final Integer value = sInstanceCounts.get(klass);
2276                 return value != null ? value : 0;
2277             }
2278         }
2279     }
2280 }
2281