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