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