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