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