StrictMode.java revision 32e60c7942eeba920ec5c27b372ec0899fd75a20
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.app.ActivityManagerNative;
19import android.app.ApplicationErrorReport;
20import android.util.Log;
21import android.util.Printer;
22
23import com.android.internal.os.RuntimeInit;
24
25import dalvik.system.BlockGuard;
26
27import java.io.PrintWriter;
28import java.io.StringWriter;
29import java.util.ArrayList;
30import java.util.HashMap;
31
32/**
33 * <p>StrictMode is a developer tool which detects things you might be
34 * doing by accident and brings them to your attention so you can fix
35 * them.
36 *
37 * <p>StrictMode is most commonly used to catch accidental disk or
38 * network access on the application's main thread, where UI
39 * operations are received and animations take place.  Keeping disk
40 * and network operations off the main thread makes for much smoother,
41 * more responsive applications.
42 *
43 * <p class="note">Note that even though an Android device's disk is
44 * often on flash memory, many devices run a filesystem on top of that
45 * memory with very limited concurrency.  It's often the case that
46 * almost all disk accesses are fast, but may in individual cases be
47 * dramatically slower when certain I/O is happening in the background
48 * from other processes.  If possible, it's best to assume that such
49 * things are not fast.</p>
50 *
51 * <p>Example code to enable from early in your
52 * {@link android.app.Application}, {@link android.app.Activity}, or
53 * other application component's
54 * {@link android.app.Application#onCreate} method:
55 *
56 * <pre>
57 * public void onCreate() {
58 *     if (DEVELOPER_MODE) {
59 *         StrictMode.setThreadPolicy(new {@link ThreadPolicy.Builder StrictMode.ThreadPolicy.Builder}()
60 *                 .detectDiskReads()
61 *                 .detectDiskWrites()
62 *                 .detectNetwork()   // or .detectAll() for all detectable problems
63 *                 .penaltyLog()
64 *                 .build());
65 *         StrictMode.setVmPolicy(new {@link VmPolicy.Builder StrictMode.VmPolicy.Builder}()
66 *                 .detectLeakedSqlLiteCursors()
67 *                 .penaltyLog()
68 *                 .penaltyDeath()
69 *                 .build());
70 *     }
71 *     super.onCreate();
72 * }
73 * </pre>
74 *
75 * <p>You can decide what should happen when a violation is detected.
76 * For example, using {@link ThreadPolicy.Builder#penaltyLog} you can
77 * watch the output of <code>adb logcat</code> while you use your
78 * application to see the violations as they happen.
79 *
80 * <p>If you find violations that you feel are problematic, there are
81 * a variety of tools to help solve them: threads, {@link android.os.Handler},
82 * {@link android.os.AsyncTask}, {@link android.app.IntentService}, etc.
83 * But don't feel compelled to fix everything that StrictMode finds.  In particular,
84 * many cases of disk access are often necessary during the normal activity lifecycle.  Use
85 * StrictMode to find things you did by accident.  Network requests on the UI thread
86 * are almost always a problem, though.
87 *
88 * <p class="note">StrictMode is not a security mechanism and is not
89 * guaranteed to find all disk or network accesses.  While it does
90 * propagate its state across process boundaries when doing
91 * {@link android.os.Binder} calls, it's still ultimately a best
92 * effort mechanism.  Notably, disk or network access from JNI calls
93 * won't necessarily trigger it.  Future versions of Android may catch
94 * more (or fewer) operations, so you should never leave StrictMode
95 * enabled in shipping applications on the Android Market.
96 */
97public final class StrictMode {
98    private static final String TAG = "StrictMode";
99    private static final boolean LOG_V = false;
100
101    // Only log a duplicate stack trace to the logs every second.
102    private static final long MIN_LOG_INTERVAL_MS = 1000;
103
104    // Only show an annoying dialog at most every 30 seconds
105    private static final long MIN_DIALOG_INTERVAL_MS = 30000;
106
107    // Thread-policy:
108
109    /**
110     * @hide
111     */
112    public static final int DETECT_DISK_WRITE = 0x01;  // for ThreadPolicy
113
114    /**
115      * @hide
116     */
117    public static final int DETECT_DISK_READ = 0x02;  // for ThreadPolicy
118
119    /**
120     * @hide
121     */
122    public static final int DETECT_NETWORK = 0x04;  // for ThreadPolicy
123
124    // Process-policy:
125
126    /**
127     * Note, a "VM_" bit, not thread.
128     * @hide
129     */
130    public static final int DETECT_VM_CURSOR_LEAKS = 0x200;  // for ProcessPolicy
131
132    /**
133     * @hide
134     */
135    public static final int PENALTY_LOG = 0x10;  // normal android.util.Log
136
137    // Used for both process and thread policy:
138
139    /**
140     * @hide
141     */
142    public static final int PENALTY_DIALOG = 0x20;
143
144    /**
145     * @hide
146     */
147    public static final int PENALTY_DEATH = 0x40;
148
149    /**
150     * @hide
151     */
152    public static final int PENALTY_DROPBOX = 0x80;
153
154    /**
155     * Non-public penalty mode which overrides all the other penalty
156     * bits and signals that we're in a Binder call and we should
157     * ignore the other penalty bits and instead serialize back all
158     * our offending stack traces to the caller to ultimately handle
159     * in the originating process.
160     *
161     * This must be kept in sync with the constant in libs/binder/Parcel.cpp
162     *
163     * @hide
164     */
165    public static final int PENALTY_GATHER = 0x100;
166
167    /**
168     * The current VmPolicy in effect.
169     */
170    private static volatile int sVmPolicyMask = 0;
171
172    private StrictMode() {}
173
174    /**
175     * {@link StrictMode} policy applied to a certain thread.
176     *
177     * <p>The policy is enabled by {@link #setThreadPolicy}.  The current policy
178     * can be retrieved with {@link #getThreadPolicy}.
179     *
180     * <p>Note that multiple penalties may be provided and they're run
181     * in order from least to most severe (logging before process
182     * death, for example).  There's currently no mechanism to choose
183     * different penalties for different detected actions.
184     */
185    public static final class ThreadPolicy {
186        /**
187         * The default, lax policy which doesn't catch anything.
188         */
189        public static final ThreadPolicy LAX = new ThreadPolicy(0);
190
191        final int mask;
192
193        private ThreadPolicy(int mask) {
194            this.mask = mask;
195        }
196
197        @Override
198        public String toString() {
199            return "[StrictMode.ThreadPolicy; mask=" + mask + "]";
200        }
201
202        /**
203         * Creates ThreadPolicy instances.  Methods whose names start
204         * with {@code detect} specify what problems we should look
205         * for.  Methods whose names start with {@code penalty} specify what
206         * we should do when we detect a problem.
207         *
208         * <p>You can call as many {@code detect} and {@code penalty}
209         * methods as you like. Currently order is insignificant: all
210         * penalties apply to all detected problems.
211         *
212         * <p>For example, detect everything and log anything that's found:
213         * <pre>
214         * StrictMode.VmPolicy policy = new StrictMode.VmPolicy.Builder()
215         *     .detectAll()
216         *     .penaltyLog()
217         *     .build();
218         * StrictMode.setVmPolicy(policy);
219         * </pre>
220         */
221        public static final class Builder {
222            private int mMask = 0;
223
224            /**
225             * Create a Builder that detects nothing and has no
226             * violations.  (but note that {@link #build} will default
227             * to enabling {@link #penaltyLog} if no other penalties
228             * are specified)
229             */
230            public Builder() {
231                mMask = 0;
232            }
233
234            /**
235             * Initialize a Builder from an existing ThreadPolicy.
236             */
237            public Builder(ThreadPolicy policy) {
238                mMask = policy.mask;
239            }
240
241            /**
242             * Detect everything that's potentially suspect.
243             *
244             * <p>As of the Gingerbread release this includes network and
245             * disk operations but will likely expand in future releases.
246             */
247            public Builder detectAll() {
248                return enable(DETECT_DISK_WRITE | DETECT_DISK_READ | DETECT_NETWORK);
249            }
250
251            /**
252             * Disable the detection of everything.
253             */
254            public Builder permitAll() {
255                return disable(DETECT_DISK_WRITE | DETECT_DISK_READ | DETECT_NETWORK);
256            }
257
258            /**
259             * Enable detection of network operations.
260             */
261            public Builder detectNetwork() {
262                return enable(DETECT_NETWORK);
263            }
264
265            /**
266             * Disable detection of network operations.
267             */
268            public Builder permitNetwork() {
269                return disable(DETECT_NETWORK);
270            }
271
272            /**
273             * Enable detection of disk reads.
274             */
275            public Builder detectDiskReads() {
276                return enable(DETECT_DISK_READ);
277            }
278
279            /**
280             * Disable detection of disk reads.
281             */
282            public Builder permitDiskReads() {
283                return disable(DETECT_DISK_READ);
284            }
285
286            /**
287             * Enable detection of disk writes.
288             */
289            public Builder detectDiskWrites() {
290                return enable(DETECT_DISK_WRITE);
291            }
292
293            /**
294             * Disable detection of disk writes.
295             */
296            public Builder permitDiskWrites() {
297                return disable(DETECT_DISK_WRITE);
298            }
299
300            /**
301             * Show an annoying dialog to the developer on detected
302             * violations, rate-limited to be only a little annoying.
303             */
304            public Builder penaltyDialog() {
305                return enable(PENALTY_DIALOG);
306            }
307
308            /**
309             * Crash the whole process on violation.  This penalty runs at
310             * the end of all enabled penalties so you'll still get
311             * see logging or other violations before the process dies.
312             */
313            public Builder penaltyDeath() {
314                return enable(PENALTY_DEATH);
315            }
316
317            /**
318             * Log detected violations to the system log.
319             */
320            public Builder penaltyLog() {
321                return enable(PENALTY_LOG);
322            }
323
324            /**
325             * Enable detected violations log a stacktrace and timing data
326             * to the {@link android.os.DropBoxManager DropBox} on policy
327             * violation.  Intended mostly for platform integrators doing
328             * beta user field data collection.
329             */
330            public Builder penaltyDropBox() {
331                return enable(PENALTY_DROPBOX);
332            }
333
334            private Builder enable(int bit) {
335                mMask |= bit;
336                return this;
337            }
338
339            private Builder disable(int bit) {
340                mMask &= ~bit;
341                return this;
342            }
343
344            /**
345             * Construct the ThreadPolicy instance.
346             *
347             * <p>Note: if no penalties are enabled before calling
348             * <code>build</code>, {@link #penaltyLog} is implicitly
349             * set.
350             */
351            public ThreadPolicy build() {
352                // If there are detection bits set but no violation bits
353                // set, enable simple logging.
354                if (mMask != 0 &&
355                    (mMask & (PENALTY_DEATH | PENALTY_LOG |
356                              PENALTY_DROPBOX | PENALTY_DIALOG)) == 0) {
357                    penaltyLog();
358                }
359                return new ThreadPolicy(mMask);
360            }
361        }
362    }
363
364    /**
365     * {@link StrictMode} policy applied to all threads in the virtual machine's process.
366     *
367     * <p>The policy is enabled by {@link #setVmPolicy}.
368     */
369    public static final class VmPolicy {
370        /**
371         * The default, lax policy which doesn't catch anything.
372         */
373        public static final VmPolicy LAX = new VmPolicy(0);
374
375        final int mask;
376
377        private VmPolicy(int mask) {
378            this.mask = mask;
379        }
380
381        @Override
382        public String toString() {
383            return "[StrictMode.VmPolicy; mask=" + mask + "]";
384        }
385
386        /**
387         * Creates {@link VmPolicy} instances.  Methods whose names start
388         * with {@code detect} specify what problems we should look
389         * for.  Methods whose names start with {@code penalty} specify what
390         * we should do when we detect a problem.
391         *
392         * <p>You can call as many {@code detect} and {@code penalty}
393         * methods as you like. Currently order is insignificant: all
394         * penalties apply to all detected problems.
395         *
396         * <p>For example, detect everything and log anything that's found:
397         * <pre>
398         * StrictMode.VmPolicy policy = new StrictMode.VmPolicy.Builder()
399         *     .detectAll()
400         *     .penaltyLog()
401         *     .build();
402         * StrictMode.setVmPolicy(policy);
403         * </pre>
404         */
405        public static final class Builder {
406            private int mMask;
407
408            /**
409             * Detect everything that's potentially suspect.
410             *
411             * <p>As of the Gingerbread release this only includes
412             * SQLite cursor leaks but will likely expand in future
413             * releases.
414             */
415            public Builder detectAll() {
416                return enable(DETECT_VM_CURSOR_LEAKS);
417            }
418
419            /**
420             * Detect when an
421             * {@link android.database.sqlite.SQLiteCursor} or other
422             * SQLite object is finalized without having been closed.
423             *
424             * <p>You always want to explicitly close your SQLite
425             * cursors to avoid unnecessary database contention and
426             * temporary memory leaks.
427             */
428            public Builder detectLeakedSqlLiteObjects() {
429                return enable(DETECT_VM_CURSOR_LEAKS);
430            }
431
432            /**
433             * Crashes the whole process on violation.  This penalty runs at
434             * the end of all enabled penalties so yo you'll still get
435             * your logging or other violations before the process dies.
436             */
437            public Builder penaltyDeath() {
438                return enable(PENALTY_DEATH);
439            }
440
441            /**
442             * Log detected violations to the system log.
443             */
444            public Builder penaltyLog() {
445                return enable(PENALTY_LOG);
446            }
447
448            /**
449             * Enable detected violations log a stacktrace and timing data
450             * to the {@link android.os.DropBoxManager DropBox} on policy
451             * violation.  Intended mostly for platform integrators doing
452             * beta user field data collection.
453             */
454            public Builder penaltyDropBox() {
455                return enable(PENALTY_DROPBOX);
456            }
457
458            private Builder enable(int bit) {
459                mMask |= bit;
460                return this;
461            }
462
463            /**
464             * Construct the VmPolicy instance.
465             *
466             * <p>Note: if no penalties are enabled before calling
467             * <code>build</code>, {@link #penaltyLog} is implicitly
468             * set.
469             */
470            public VmPolicy build() {
471                // If there are detection bits set but no violation bits
472                // set, enable simple logging.
473                if (mMask != 0 &&
474                    (mMask & (PENALTY_DEATH | PENALTY_LOG |
475                              PENALTY_DROPBOX | PENALTY_DIALOG)) == 0) {
476                    penaltyLog();
477                }
478                return new VmPolicy(mMask);
479            }
480        }
481    }
482
483    /**
484     * Log of strict mode violation stack traces that have occurred
485     * during a Binder call, to be serialized back later to the caller
486     * via Parcel.writeNoException() (amusingly) where the caller can
487     * choose how to react.
488     */
489    private static final ThreadLocal<ArrayList<ViolationInfo>> gatheredViolations =
490            new ThreadLocal<ArrayList<ViolationInfo>>() {
491        @Override protected ArrayList<ViolationInfo> initialValue() {
492            // Starts null to avoid unnecessary allocations when
493            // checking whether there are any violations or not in
494            // hasGatheredViolations() below.
495            return null;
496        }
497    };
498
499    /**
500     * Sets the policy for what actions on the current thread should
501     * be detected, as well as the penalty if such actions occur.
502     *
503     * <p>Internally this sets a thread-local variable which is
504     * propagated across cross-process IPC calls, meaning you can
505     * catch violations when a system service or another process
506     * accesses the disk or network on your behalf.
507     *
508     * @param policy the policy to put into place
509     */
510    public static void setThreadPolicy(final ThreadPolicy policy) {
511        setThreadPolicyMask(policy.mask);
512    }
513
514    private static void setThreadPolicyMask(final int policyMask) {
515        // In addition to the Java-level thread-local in Dalvik's
516        // BlockGuard, we also need to keep a native thread-local in
517        // Binder in order to propagate the value across Binder calls,
518        // even across native-only processes.  The two are kept in
519        // sync via the callback to onStrictModePolicyChange, below.
520        setBlockGuardPolicy(policyMask);
521
522        // And set the Android native version...
523        Binder.setThreadStrictModePolicy(policyMask);
524    }
525
526    // Sets the policy in Dalvik/libcore (BlockGuard)
527    private static void setBlockGuardPolicy(final int policyMask) {
528        if (policyMask == 0) {
529            BlockGuard.setThreadPolicy(BlockGuard.LAX_POLICY);
530            return;
531        }
532        BlockGuard.Policy policy = BlockGuard.getThreadPolicy();
533        if (!(policy instanceof AndroidBlockGuardPolicy)) {
534            BlockGuard.setThreadPolicy(new AndroidBlockGuardPolicy(policyMask));
535        } else {
536            AndroidBlockGuardPolicy androidPolicy = (AndroidBlockGuardPolicy) policy;
537            androidPolicy.setPolicyMask(policyMask);
538        }
539    }
540
541    private static class StrictModeNetworkViolation extends BlockGuard.BlockGuardPolicyException {
542        public StrictModeNetworkViolation(int policyMask) {
543            super(policyMask, DETECT_NETWORK);
544        }
545    }
546
547    private static class StrictModeDiskReadViolation extends BlockGuard.BlockGuardPolicyException {
548        public StrictModeDiskReadViolation(int policyMask) {
549            super(policyMask, DETECT_DISK_READ);
550        }
551    }
552
553    private static class StrictModeDiskWriteViolation extends BlockGuard.BlockGuardPolicyException {
554        public StrictModeDiskWriteViolation(int policyMask) {
555            super(policyMask, DETECT_DISK_WRITE);
556        }
557    }
558
559    /**
560     * Returns the bitmask of the current thread's policy.
561     *
562     * @return the bitmask of all the DETECT_* and PENALTY_* bits currently enabled
563     *
564     * @hide
565     */
566    public static int getThreadPolicyMask() {
567        return BlockGuard.getThreadPolicy().getPolicyMask();
568    }
569
570    /**
571     * Returns the current thread's policy.
572     */
573    public static ThreadPolicy getThreadPolicy() {
574        return new ThreadPolicy(getThreadPolicyMask());
575    }
576
577    /**
578     * A convenience wrapper that takes the current
579     * {@link ThreadPolicy} from {@link #getThreadPolicy}, modifies it
580     * to permit both disk reads &amp; writes, and sets the new policy
581     * with {@link #setThreadPolicy}, returning the old policy so you
582     * can restore it at the end of a block.
583     *
584     * @return the old policy, to be passed to {@link #setThreadPolicy} to
585     *         restore the policy at the end of a block
586     */
587    public static ThreadPolicy allowThreadDiskWrites() {
588        int oldPolicyMask = getThreadPolicyMask();
589        int newPolicyMask = oldPolicyMask & ~(DETECT_DISK_WRITE | DETECT_DISK_READ);
590        if (newPolicyMask != oldPolicyMask) {
591            setThreadPolicyMask(newPolicyMask);
592        }
593        return new ThreadPolicy(oldPolicyMask);
594    }
595
596    /**
597     * A convenience wrapper that takes the current
598     * {@link ThreadPolicy} from {@link #getThreadPolicy}, modifies it
599     * to permit disk reads, and sets the new policy
600     * with {@link #setThreadPolicy}, returning the old policy so you
601     * can restore it at the end of a block.
602     *
603     * @return the old policy, to be passed to setThreadPolicy to
604     *         restore the policy.
605     */
606    public static ThreadPolicy allowThreadDiskReads() {
607        int oldPolicyMask = getThreadPolicyMask();
608        int newPolicyMask = oldPolicyMask & ~(DETECT_DISK_READ);
609        if (newPolicyMask != oldPolicyMask) {
610            setThreadPolicyMask(newPolicyMask);
611        }
612        return new ThreadPolicy(oldPolicyMask);
613    }
614
615    /**
616     * Enable DropBox logging for debug phone builds.
617     *
618     * @hide
619     */
620    public static boolean conditionallyEnableDebugLogging() {
621        // For debug builds, log event loop stalls to dropbox for analysis.
622        // Similar logic also appears in ActivityThread.java for system apps.
623        if ("user".equals(Build.TYPE)) {
624            return false;
625        }
626        StrictMode.setThreadPolicyMask(
627            StrictMode.DETECT_DISK_WRITE |
628            StrictMode.DETECT_DISK_READ |
629            StrictMode.DETECT_NETWORK |
630            StrictMode.PENALTY_DROPBOX);
631        sVmPolicyMask = StrictMode.DETECT_VM_CURSOR_LEAKS |
632                StrictMode.PENALTY_DROPBOX |
633                StrictMode.PENALTY_LOG;
634        return true;
635    }
636
637    /**
638     * Parses the BlockGuard policy mask out from the Exception's
639     * getMessage() String value.  Kinda gross, but least
640     * invasive.  :/
641     *
642     * Input is of form "policy=137 violation=64"
643     *
644     * Returns 0 on failure, which is a valid policy, but not a
645     * valid policy during a violation (else there must've been
646     * some policy in effect to violate).
647     */
648    private static int parsePolicyFromMessage(String message) {
649        if (message == null || !message.startsWith("policy=")) {
650            return 0;
651        }
652        int spaceIndex = message.indexOf(' ');
653        if (spaceIndex == -1) {
654            return 0;
655        }
656        String policyString = message.substring(7, spaceIndex);
657        try {
658            return Integer.valueOf(policyString).intValue();
659        } catch (NumberFormatException e) {
660            return 0;
661        }
662    }
663
664    /**
665     * Like parsePolicyFromMessage(), but returns the violation.
666     */
667    private static int parseViolationFromMessage(String message) {
668        if (message == null) {
669            return 0;
670        }
671        int violationIndex = message.indexOf("violation=");
672        if (violationIndex == -1) {
673            return 0;
674        }
675        String violationString = message.substring(violationIndex + 10);
676        try {
677            return Integer.valueOf(violationString).intValue();
678        } catch (NumberFormatException e) {
679            return 0;
680        }
681    }
682
683    private static class AndroidBlockGuardPolicy implements BlockGuard.Policy {
684        private int mPolicyMask;
685
686        // Map from violation stacktrace hashcode -> uptimeMillis of
687        // last violation.  No locking needed, as this is only
688        // accessed by the same thread.
689        private final HashMap<Integer, Long> mLastViolationTime = new HashMap<Integer, Long>();
690
691        public AndroidBlockGuardPolicy(final int policyMask) {
692            mPolicyMask = policyMask;
693        }
694
695        @Override
696        public String toString() {
697            return "AndroidBlockGuardPolicy; mPolicyMask=" + mPolicyMask;
698        }
699
700        // Part of BlockGuard.Policy interface:
701        public int getPolicyMask() {
702            return mPolicyMask;
703        }
704
705        // Part of BlockGuard.Policy interface:
706        public void onWriteToDisk() {
707            if ((mPolicyMask & DETECT_DISK_WRITE) == 0) {
708                return;
709            }
710            BlockGuard.BlockGuardPolicyException e = new StrictModeDiskWriteViolation(mPolicyMask);
711            e.fillInStackTrace();
712            startHandlingViolationException(e);
713        }
714
715        // Part of BlockGuard.Policy interface:
716        public void onReadFromDisk() {
717            if ((mPolicyMask & DETECT_DISK_READ) == 0) {
718                return;
719            }
720            BlockGuard.BlockGuardPolicyException e = new StrictModeDiskReadViolation(mPolicyMask);
721            e.fillInStackTrace();
722            startHandlingViolationException(e);
723        }
724
725        // Part of BlockGuard.Policy interface:
726        public void onNetwork() {
727            if ((mPolicyMask & DETECT_NETWORK) == 0) {
728                return;
729            }
730            BlockGuard.BlockGuardPolicyException e = new StrictModeNetworkViolation(mPolicyMask);
731            e.fillInStackTrace();
732            startHandlingViolationException(e);
733        }
734
735        public void setPolicyMask(int policyMask) {
736            mPolicyMask = policyMask;
737        }
738
739        // Start handling a violation that just started and hasn't
740        // actually run yet (e.g. no disk write or network operation
741        // has yet occurred).  This sees if we're in an event loop
742        // thread and, if so, uses it to roughly measure how long the
743        // violation took.
744        void startHandlingViolationException(BlockGuard.BlockGuardPolicyException e) {
745            final ViolationInfo info = new ViolationInfo(e, e.getPolicy());
746            info.violationUptimeMillis = SystemClock.uptimeMillis();
747            handleViolationWithTimingAttempt(info);
748        }
749
750        private static final ThreadLocal<ArrayList<ViolationInfo>> violationsBeingTimed =
751                new ThreadLocal<ArrayList<ViolationInfo>>() {
752            @Override protected ArrayList<ViolationInfo> initialValue() {
753                return new ArrayList<ViolationInfo>();
754            }
755        };
756
757        // Attempts to fill in the provided ViolationInfo's
758        // durationMillis field if this thread has a Looper we can use
759        // to measure with.  We measure from the time of violation
760        // until the time the looper is idle again (right before
761        // the next epoll_wait)
762        void handleViolationWithTimingAttempt(final ViolationInfo info) {
763            Looper looper = Looper.myLooper();
764
765            // Without a Looper, we're unable to time how long the
766            // violation takes place.  This case should be rare, as
767            // most users will care about timing violations that
768            // happen on their main UI thread.  Note that this case is
769            // also hit when a violation takes place in a Binder
770            // thread, in "gather" mode.  In this case, the duration
771            // of the violation is computed by the ultimate caller and
772            // its Looper, if any.
773            // TODO: if in gather mode, ignore Looper.myLooper() and always
774            //       go into this immediate mode?
775            if (looper == null) {
776                info.durationMillis = -1;  // unknown (redundant, already set)
777                handleViolation(info);
778                return;
779            }
780
781            MessageQueue queue = Looper.myQueue();
782            final ArrayList<ViolationInfo> records = violationsBeingTimed.get();
783            if (records.size() >= 10) {
784                // Not worth measuring.  Too many offenses in one loop.
785                return;
786            }
787            records.add(info);
788            if (records.size() > 1) {
789                // There's already been a violation this loop, so we've already
790                // registered an idle handler to process the list of violations
791                // at the end of this Looper's loop.
792                return;
793            }
794
795            queue.addIdleHandler(new MessageQueue.IdleHandler() {
796                    public boolean queueIdle() {
797                        long loopFinishTime = SystemClock.uptimeMillis();
798                        for (int n = 0; n < records.size(); ++n) {
799                            ViolationInfo v = records.get(n);
800                            v.violationNumThisLoop = n + 1;
801                            v.durationMillis =
802                                    (int) (loopFinishTime - v.violationUptimeMillis);
803                            handleViolation(v);
804                        }
805                        records.clear();
806                        return false;  // remove this idle handler from the array
807                    }
808                });
809        }
810
811        // Note: It's possible (even quite likely) that the
812        // thread-local policy mask has changed from the time the
813        // violation fired and now (after the violating code ran) due
814        // to people who push/pop temporary policy in regions of code,
815        // hence the policy being passed around.
816        void handleViolation(final ViolationInfo info) {
817            if (info == null || info.crashInfo == null || info.crashInfo.stackTrace == null) {
818                Log.wtf(TAG, "unexpected null stacktrace");
819                return;
820            }
821
822            if (LOG_V) Log.d(TAG, "handleViolation; policy=" + info.policy);
823
824            if ((info.policy & PENALTY_GATHER) != 0) {
825                ArrayList<ViolationInfo> violations = gatheredViolations.get();
826                if (violations == null) {
827                    violations = new ArrayList<ViolationInfo>(1);
828                    gatheredViolations.set(violations);
829                } else if (violations.size() >= 5) {
830                    // Too many.  In a loop or something?  Don't gather them all.
831                    return;
832                }
833                for (ViolationInfo previous : violations) {
834                    if (info.crashInfo.stackTrace.equals(previous.crashInfo.stackTrace)) {
835                        // Duplicate. Don't log.
836                        return;
837                    }
838                }
839                violations.add(info);
840                return;
841            }
842
843            // Not perfect, but fast and good enough for dup suppression.
844            Integer crashFingerprint = info.crashInfo.stackTrace.hashCode();
845            long lastViolationTime = 0;
846            if (mLastViolationTime.containsKey(crashFingerprint)) {
847                lastViolationTime = mLastViolationTime.get(crashFingerprint);
848            }
849            long now = SystemClock.uptimeMillis();
850            mLastViolationTime.put(crashFingerprint, now);
851            long timeSinceLastViolationMillis = lastViolationTime == 0 ?
852                    Long.MAX_VALUE : (now - lastViolationTime);
853
854            if ((info.policy & PENALTY_LOG) != 0 &&
855                timeSinceLastViolationMillis > MIN_LOG_INTERVAL_MS) {
856                if (info.durationMillis != -1) {
857                    Log.d(TAG, "StrictMode policy violation; ~duration=" +
858                          info.durationMillis + " ms: " + info.crashInfo.stackTrace);
859                } else {
860                    Log.d(TAG, "StrictMode policy violation: " + info.crashInfo.stackTrace);
861                }
862            }
863
864            // The violationMask, passed to ActivityManager, is a
865            // subset of the original StrictMode policy bitmask, with
866            // only the bit violated and penalty bits to be executed
867            // by the ActivityManagerService remaining set.
868            int violationMaskSubset = 0;
869
870            if ((info.policy & PENALTY_DIALOG) != 0 &&
871                timeSinceLastViolationMillis > MIN_DIALOG_INTERVAL_MS) {
872                violationMaskSubset |= PENALTY_DIALOG;
873            }
874
875            if ((info.policy & PENALTY_DROPBOX) != 0 && lastViolationTime == 0) {
876                violationMaskSubset |= PENALTY_DROPBOX;
877            }
878
879            if (violationMaskSubset != 0) {
880                int violationBit = parseViolationFromMessage(info.crashInfo.exceptionMessage);
881                violationMaskSubset |= violationBit;
882                final int savedPolicyMask = getThreadPolicyMask();
883                try {
884                    // First, remove any policy before we call into the Activity Manager,
885                    // otherwise we'll infinite recurse as we try to log policy violations
886                    // to disk, thus violating policy, thus requiring logging, etc...
887                    // We restore the current policy below, in the finally block.
888                    setThreadPolicyMask(0);
889
890                    ActivityManagerNative.getDefault().handleApplicationStrictModeViolation(
891                        RuntimeInit.getApplicationObject(),
892                        violationMaskSubset,
893                        info);
894                } catch (RemoteException e) {
895                    Log.e(TAG, "RemoteException trying to handle StrictMode violation", e);
896                } finally {
897                    // Restore the policy.
898                    setThreadPolicyMask(savedPolicyMask);
899                }
900            }
901
902            if ((info.policy & PENALTY_DEATH) != 0) {
903                System.err.println("StrictMode policy violation with POLICY_DEATH; shutting down.");
904                Process.killProcess(Process.myPid());
905                System.exit(10);
906            }
907        }
908    }
909
910    /**
911     * Called from Parcel.writeNoException()
912     */
913    /* package */ static boolean hasGatheredViolations() {
914        return gatheredViolations.get() != null;
915    }
916
917    /**
918     * Called from Parcel.writeException(), so we drop this memory and
919     * don't incorrectly attribute it to the wrong caller on the next
920     * Binder call on this thread.
921     */
922    /* package */ static void clearGatheredViolations() {
923        gatheredViolations.set(null);
924    }
925
926    /**
927     * Sets the policy for what actions in the VM process (on any
928     * thread) should be detected, as well as the penalty if such
929     * actions occur.
930     *
931     * @param policy the policy to put into place
932     */
933    public static void setVmPolicy(final VmPolicy policy) {
934        sVmPolicyMask = policy.mask;
935    }
936
937    /**
938     * Gets the current VM policy.
939     */
940    public static VmPolicy getVmPolicy() {
941        return new VmPolicy(sVmPolicyMask);
942    }
943
944    /**
945     * @hide
946     */
947    public static boolean vmSqliteObjectLeaksEnabled() {
948        return (sVmPolicyMask & DETECT_VM_CURSOR_LEAKS) != 0;
949    }
950
951    /**
952     * @hide
953     */
954    public static void onSqliteObjectLeaked(String message, Throwable originStack) {
955        if ((sVmPolicyMask & PENALTY_LOG) != 0) {
956            Log.e(TAG, message, originStack);
957        }
958
959        if ((sVmPolicyMask & PENALTY_DROPBOX) != 0) {
960            final ViolationInfo info = new ViolationInfo(originStack, sVmPolicyMask);
961
962            // The violationMask, passed to ActivityManager, is a
963            // subset of the original StrictMode policy bitmask, with
964            // only the bit violated and penalty bits to be executed
965            // by the ActivityManagerService remaining set.
966            int violationMaskSubset = PENALTY_DROPBOX | DETECT_VM_CURSOR_LEAKS;
967            final int savedPolicyMask = getThreadPolicyMask();
968            try {
969                // First, remove any policy before we call into the Activity Manager,
970                // otherwise we'll infinite recurse as we try to log policy violations
971                // to disk, thus violating policy, thus requiring logging, etc...
972                // We restore the current policy below, in the finally block.
973                setThreadPolicyMask(0);
974
975                ActivityManagerNative.getDefault().handleApplicationStrictModeViolation(
976                    RuntimeInit.getApplicationObject(),
977                    violationMaskSubset,
978                    info);
979            } catch (RemoteException e) {
980                Log.e(TAG, "RemoteException trying to handle StrictMode violation", e);
981            } finally {
982                // Restore the policy.
983                setThreadPolicyMask(savedPolicyMask);
984            }
985        }
986
987        if ((sVmPolicyMask & PENALTY_DEATH) != 0) {
988            System.err.println("StrictMode VmPolicy violation with POLICY_DEATH; shutting down.");
989            Process.killProcess(Process.myPid());
990            System.exit(10);
991        }
992    }
993
994    /**
995     * Called from Parcel.writeNoException()
996     */
997    /* package */ static void writeGatheredViolationsToParcel(Parcel p) {
998        ArrayList<ViolationInfo> violations = gatheredViolations.get();
999        if (violations == null) {
1000            p.writeInt(0);
1001        } else {
1002            p.writeInt(violations.size());
1003            for (int i = 0; i < violations.size(); ++i) {
1004                violations.get(i).writeToParcel(p, 0 /* unused flags? */);
1005            }
1006            if (LOG_V) Log.d(TAG, "wrote violations to response parcel; num=" + violations.size());
1007            violations.clear(); // somewhat redundant, as we're about to null the threadlocal
1008        }
1009        gatheredViolations.set(null);
1010    }
1011
1012    private static class LogStackTrace extends Exception {}
1013
1014    /**
1015     * Called from Parcel.readException() when the exception is EX_STRICT_MODE_VIOLATIONS,
1016     * we here read back all the encoded violations.
1017     */
1018    /* package */ static void readAndHandleBinderCallViolations(Parcel p) {
1019        // Our own stack trace to append
1020        StringWriter sw = new StringWriter();
1021        new LogStackTrace().printStackTrace(new PrintWriter(sw));
1022        String ourStack = sw.toString();
1023
1024        int policyMask = getThreadPolicyMask();
1025        boolean currentlyGathering = (policyMask & PENALTY_GATHER) != 0;
1026
1027        int numViolations = p.readInt();
1028        for (int i = 0; i < numViolations; ++i) {
1029            if (LOG_V) Log.d(TAG, "strict mode violation stacks read from binder call.  i=" + i);
1030            ViolationInfo info = new ViolationInfo(p, !currentlyGathering);
1031            info.crashInfo.stackTrace += "# via Binder call with stack:\n" + ourStack;
1032            BlockGuard.Policy policy = BlockGuard.getThreadPolicy();
1033            if (policy instanceof AndroidBlockGuardPolicy) {
1034                ((AndroidBlockGuardPolicy) policy).handleViolationWithTimingAttempt(info);
1035            }
1036        }
1037    }
1038
1039    /**
1040     * Called from android_util_Binder.cpp's
1041     * android_os_Parcel_enforceInterface when an incoming Binder call
1042     * requires changing the StrictMode policy mask.  The role of this
1043     * function is to ask Binder for its current (native) thread-local
1044     * policy value and synchronize it to libcore's (Java)
1045     * thread-local policy value.
1046     */
1047    private static void onBinderStrictModePolicyChange(int newPolicy) {
1048        setBlockGuardPolicy(newPolicy);
1049    }
1050
1051    /**
1052     * Parcelable that gets sent in Binder call headers back to callers
1053     * to report violations that happened during a cross-process call.
1054     *
1055     * @hide
1056     */
1057    public static class ViolationInfo {
1058        /**
1059         * Stack and other stuff info.
1060         */
1061        public final ApplicationErrorReport.CrashInfo crashInfo;
1062
1063        /**
1064         * The strict mode policy mask at the time of violation.
1065         */
1066        public final int policy;
1067
1068        /**
1069         * The wall time duration of the violation, when known.  -1 when
1070         * not known.
1071         */
1072        public int durationMillis = -1;
1073
1074        /**
1075         * Which violation number this was (1-based) since the last Looper loop,
1076         * from the perspective of the root caller (if it crossed any processes
1077         * via Binder calls).  The value is 0 if the root caller wasn't on a Looper
1078         * thread.
1079         */
1080        public int violationNumThisLoop;
1081
1082        /**
1083         * The time (in terms of SystemClock.uptimeMillis()) that the
1084         * violation occurred.
1085         */
1086        public long violationUptimeMillis;
1087
1088        /**
1089         * Create an uninitialized instance of ViolationInfo
1090         */
1091        public ViolationInfo() {
1092            crashInfo = null;
1093            policy = 0;
1094        }
1095
1096        /**
1097         * Create an instance of ViolationInfo initialized from an exception.
1098         */
1099        public ViolationInfo(Throwable tr, int policy) {
1100            crashInfo = new ApplicationErrorReport.CrashInfo(tr);
1101            violationUptimeMillis = SystemClock.uptimeMillis();
1102            this.policy = policy;
1103        }
1104
1105        /**
1106         * Create an instance of ViolationInfo initialized from a Parcel.
1107         */
1108        public ViolationInfo(Parcel in) {
1109            this(in, false);
1110        }
1111
1112        /**
1113         * Create an instance of ViolationInfo initialized from a Parcel.
1114         *
1115         * @param unsetGatheringBit if true, the caller is the root caller
1116         *   and the gathering penalty should be removed.
1117         */
1118        public ViolationInfo(Parcel in, boolean unsetGatheringBit) {
1119            crashInfo = new ApplicationErrorReport.CrashInfo(in);
1120            int rawPolicy = in.readInt();
1121            if (unsetGatheringBit) {
1122                policy = rawPolicy & ~PENALTY_GATHER;
1123            } else {
1124                policy = rawPolicy;
1125            }
1126            durationMillis = in.readInt();
1127            violationNumThisLoop = in.readInt();
1128            violationUptimeMillis = in.readLong();
1129        }
1130
1131        /**
1132         * Save a ViolationInfo instance to a parcel.
1133         */
1134        public void writeToParcel(Parcel dest, int flags) {
1135            crashInfo.writeToParcel(dest, flags);
1136            dest.writeInt(policy);
1137            dest.writeInt(durationMillis);
1138            dest.writeInt(violationNumThisLoop);
1139            dest.writeLong(violationUptimeMillis);
1140        }
1141
1142
1143        /**
1144         * Dump a ViolationInfo instance to a Printer.
1145         */
1146        public void dump(Printer pw, String prefix) {
1147            crashInfo.dump(pw, prefix);
1148            pw.println(prefix + "policy: " + policy);
1149            if (durationMillis != -1) {
1150                pw.println(prefix + "durationMillis: " + durationMillis);
1151            }
1152            if (violationNumThisLoop != 0) {
1153                pw.println(prefix + "violationNumThisLoop: " + violationNumThisLoop);
1154            }
1155            pw.println(prefix + "violationUptimeMillis: " + violationUptimeMillis);
1156        }
1157
1158    }
1159}
1160