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