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