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