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