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