/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.os; import android.animation.ValueAnimator; import android.app.ActivityManagerNative; import android.app.ActivityThread; import android.app.ApplicationErrorReport; import android.app.IActivityManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.net.Uri; import android.util.ArrayMap; import android.util.Log; import android.util.Printer; import android.util.Singleton; import android.util.Slog; import android.view.IWindowManager; import com.android.internal.os.RuntimeInit; import com.android.internal.util.FastPrintWriter; import com.android.internal.util.HexDump; import dalvik.system.BlockGuard; import dalvik.system.CloseGuard; import dalvik.system.VMDebug; import java.io.PrintWriter; import java.io.StringWriter; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.concurrent.atomic.AtomicInteger; /** *
StrictMode is a developer tool which detects things you might be * doing by accident and brings them to your attention so you can fix * them. * *
StrictMode is most commonly used to catch accidental disk or * network access on the application's main thread, where UI * operations are received and animations take place. Keeping disk * and network operations off the main thread makes for much smoother, * more responsive applications. By keeping your application's main thread * responsive, you also prevent * ANR dialogs * from being shown to users. * *
Note that even though an Android device's disk is * often on flash memory, many devices run a filesystem on top of that * memory with very limited concurrency. It's often the case that * almost all disk accesses are fast, but may in individual cases be * dramatically slower when certain I/O is happening in the background * from other processes. If possible, it's best to assume that such * things are not fast.
* *Example code to enable from early in your * {@link android.app.Application}, {@link android.app.Activity}, or * other application component's * {@link android.app.Application#onCreate} method: * *
* public void onCreate() { * if (DEVELOPER_MODE) { * StrictMode.setThreadPolicy(new {@link ThreadPolicy.Builder StrictMode.ThreadPolicy.Builder}() * .detectDiskReads() * .detectDiskWrites() * .detectNetwork() // or .detectAll() for all detectable problems * .penaltyLog() * .build()); * StrictMode.setVmPolicy(new {@link VmPolicy.Builder StrictMode.VmPolicy.Builder}() * .detectLeakedSqlLiteObjects() * .detectLeakedClosableObjects() * .penaltyLog() * .penaltyDeath() * .build()); * } * super.onCreate(); * } ** *
You can decide what should happen when a violation is detected.
* For example, using {@link ThreadPolicy.Builder#penaltyLog} you can
* watch the output of adb logcat
while you use your
* application to see the violations as they happen.
*
*
If you find violations that you feel are problematic, there are * a variety of tools to help solve them: threads, {@link android.os.Handler}, * {@link android.os.AsyncTask}, {@link android.app.IntentService}, etc. * But don't feel compelled to fix everything that StrictMode finds. In particular, * many cases of disk access are often necessary during the normal activity lifecycle. Use * StrictMode to find things you did by accident. Network requests on the UI thread * are almost always a problem, though. * *
StrictMode is not a security mechanism and is not
* guaranteed to find all disk or network accesses. While it does
* propagate its state across process boundaries when doing
* {@link android.os.Binder} calls, it's still ultimately a best
* effort mechanism. Notably, disk or network access from JNI calls
* won't necessarily trigger it. Future versions of Android may catch
* more (or fewer) operations, so you should never leave StrictMode
* enabled in applications distributed on Google Play.
*/
public final class StrictMode {
private static final String TAG = "StrictMode";
private static final boolean LOG_V = Log.isLoggable(TAG, Log.VERBOSE);
private static final boolean IS_USER_BUILD = "user".equals(Build.TYPE);
private static final boolean IS_ENG_BUILD = "eng".equals(Build.TYPE);
/**
* Boolean system property to disable strict mode checks outright.
* Set this to 'true' to force disable; 'false' has no effect on other
* enable/disable policy.
* @hide
*/
public static final String DISABLE_PROPERTY = "persist.sys.strictmode.disable";
/**
* The boolean system property to control screen flashes on violations.
*
* @hide
*/
public static final String VISUAL_PROPERTY = "persist.sys.strictmode.visual";
/**
* Temporary property used to include {@link #DETECT_VM_CLEARTEXT_NETWORK}
* in {@link VmPolicy.Builder#detectAll()}. Apps can still always opt-into
* detection using {@link VmPolicy.Builder#detectCleartextNetwork()}.
*/
private static final String CLEARTEXT_PROPERTY = "persist.sys.strictmode.clear";
// Only log a duplicate stack trace to the logs every second.
private static final long MIN_LOG_INTERVAL_MS = 1000;
// Only show an annoying dialog at most every 30 seconds
private static final long MIN_DIALOG_INTERVAL_MS = 30000;
// How many Span tags (e.g. animations) to report.
private static final int MAX_SPAN_TAGS = 20;
// How many offending stacks to keep track of (and time) per loop
// of the Looper.
private static final int MAX_OFFENSES_PER_LOOP = 10;
// Byte 1: Thread-policy
/**
* @hide
*/
public static final int DETECT_DISK_WRITE = 0x01; // for ThreadPolicy
/**
* @hide
*/
public static final int DETECT_DISK_READ = 0x02; // for ThreadPolicy
/**
* @hide
*/
public static final int DETECT_NETWORK = 0x04; // for ThreadPolicy
/**
* For StrictMode.noteSlowCall()
*
* @hide
*/
public static final int DETECT_CUSTOM = 0x08; // for ThreadPolicy
/**
* For StrictMode.noteResourceMismatch()
*
* @hide
*/
public static final int DETECT_RESOURCE_MISMATCH = 0x10; // for ThreadPolicy
private static final int ALL_THREAD_DETECT_BITS =
DETECT_DISK_WRITE | DETECT_DISK_READ | DETECT_NETWORK | DETECT_CUSTOM |
DETECT_RESOURCE_MISMATCH;
// Byte 2: Process-policy
/**
* Note, a "VM_" bit, not thread.
* @hide
*/
public static final int DETECT_VM_CURSOR_LEAKS = 0x01 << 8; // for VmPolicy
/**
* Note, a "VM_" bit, not thread.
* @hide
*/
public static final int DETECT_VM_CLOSABLE_LEAKS = 0x02 << 8; // for VmPolicy
/**
* Note, a "VM_" bit, not thread.
* @hide
*/
public static final int DETECT_VM_ACTIVITY_LEAKS = 0x04 << 8; // for VmPolicy
/**
* @hide
*/
private static final int DETECT_VM_INSTANCE_LEAKS = 0x08 << 8; // for VmPolicy
/**
* @hide
*/
public static final int DETECT_VM_REGISTRATION_LEAKS = 0x10 << 8; // for VmPolicy
/**
* @hide
*/
private static final int DETECT_VM_FILE_URI_EXPOSURE = 0x20 << 8; // for VmPolicy
/**
* @hide
*/
private static final int DETECT_VM_CLEARTEXT_NETWORK = 0x40 << 8; // for VmPolicy
private static final int ALL_VM_DETECT_BITS =
DETECT_VM_CURSOR_LEAKS | DETECT_VM_CLOSABLE_LEAKS |
DETECT_VM_ACTIVITY_LEAKS | DETECT_VM_INSTANCE_LEAKS |
DETECT_VM_REGISTRATION_LEAKS | DETECT_VM_FILE_URI_EXPOSURE |
DETECT_VM_CLEARTEXT_NETWORK;
// Byte 3: Penalty
/** {@hide} */
public static final int PENALTY_LOG = 0x01 << 16; // normal android.util.Log
/** {@hide} */
public static final int PENALTY_DIALOG = 0x02 << 16;
/** {@hide} */
public static final int PENALTY_DEATH = 0x04 << 16;
/** {@hide} */
public static final int PENALTY_FLASH = 0x10 << 16;
/** {@hide} */
public static final int PENALTY_DROPBOX = 0x20 << 16;
/**
* Non-public penalty mode which overrides all the other penalty
* bits and signals that we're in a Binder call and we should
* ignore the other penalty bits and instead serialize back all
* our offending stack traces to the caller to ultimately handle
* in the originating process.
*
* This must be kept in sync with the constant in libs/binder/Parcel.cpp
*
* @hide
*/
public static final int PENALTY_GATHER = 0x40 << 16;
// Byte 4: Special cases
/**
* Death when network traffic is detected on main thread.
*
* @hide
*/
public static final int PENALTY_DEATH_ON_NETWORK = 0x01 << 24;
/**
* Death when cleartext network traffic is detected.
*
* @hide
*/
public static final int PENALTY_DEATH_ON_CLEARTEXT_NETWORK = 0x02 << 24;
/**
* Death when file exposure is detected.
*
* @hide
*/
public static final int PENALTY_DEATH_ON_FILE_URI_EXPOSURE = 0x04 << 24;
/**
* Mask of all the penalty bits valid for thread policies.
*/
private static final int THREAD_PENALTY_MASK =
PENALTY_LOG | PENALTY_DIALOG | PENALTY_DEATH | PENALTY_DROPBOX | PENALTY_GATHER |
PENALTY_DEATH_ON_NETWORK | PENALTY_FLASH;
/**
* Mask of all the penalty bits valid for VM policies.
*/
private static final int VM_PENALTY_MASK = PENALTY_LOG | PENALTY_DEATH | PENALTY_DROPBOX
| PENALTY_DEATH_ON_CLEARTEXT_NETWORK | PENALTY_DEATH_ON_FILE_URI_EXPOSURE;
/** {@hide} */
public static final int NETWORK_POLICY_ACCEPT = 0;
/** {@hide} */
public static final int NETWORK_POLICY_LOG = 1;
/** {@hide} */
public static final int NETWORK_POLICY_REJECT = 2;
// TODO: wrap in some ImmutableHashMap thing.
// Note: must be before static initialization of sVmPolicy.
private static final HashMap The policy is enabled by {@link #setThreadPolicy}. The current policy
* can be retrieved with {@link #getThreadPolicy}.
*
* Note that multiple penalties may be provided and they're run
* in order from least to most severe (logging before process
* death, for example). There's currently no mechanism to choose
* different penalties for different detected actions.
*/
public static final class ThreadPolicy {
/**
* The default, lax policy which doesn't catch anything.
*/
public static final ThreadPolicy LAX = new ThreadPolicy(0);
final int mask;
private ThreadPolicy(int mask) {
this.mask = mask;
}
@Override
public String toString() {
return "[StrictMode.ThreadPolicy; mask=" + mask + "]";
}
/**
* Creates {@link ThreadPolicy} instances. Methods whose names start
* with {@code detect} specify what problems we should look
* for. Methods whose names start with {@code penalty} specify what
* we should do when we detect a problem.
*
* You can call as many {@code detect} and {@code penalty}
* methods as you like. Currently order is insignificant: all
* penalties apply to all detected problems.
*
* For example, detect everything and log anything that's found:
* As of the Gingerbread release this includes network and
* disk operations but will likely expand in future releases.
*/
public Builder detectAll() {
return enable(ALL_THREAD_DETECT_BITS);
}
/**
* Disable the detection of everything.
*/
public Builder permitAll() {
return disable(ALL_THREAD_DETECT_BITS);
}
/**
* Enable detection of network operations.
*/
public Builder detectNetwork() {
return enable(DETECT_NETWORK);
}
/**
* Disable detection of network operations.
*/
public Builder permitNetwork() {
return disable(DETECT_NETWORK);
}
/**
* Enable detection of disk reads.
*/
public Builder detectDiskReads() {
return enable(DETECT_DISK_READ);
}
/**
* Disable detection of disk reads.
*/
public Builder permitDiskReads() {
return disable(DETECT_DISK_READ);
}
/**
* Enable detection of slow calls.
*/
public Builder detectCustomSlowCalls() {
return enable(DETECT_CUSTOM);
}
/**
* Disable detection of slow calls.
*/
public Builder permitCustomSlowCalls() {
return disable(DETECT_CUSTOM);
}
/**
* Disable detection of mismatches between defined resource types
* and getter calls.
*/
public Builder permitResourceMismatches() {
return disable(DETECT_RESOURCE_MISMATCH);
}
/**
* Enables detection of mismatches between defined resource types
* and getter calls.
*
* This helps detect accidental type mismatches and potentially
* expensive type conversions when obtaining typed resources.
*
* For example, a strict mode violation would be thrown when
* calling {@link android.content.res.TypedArray#getInt(int, int)}
* on an index that contains a String-type resource. If the string
* value can be parsed as an integer, this method call will return
* a value without crashing; however, the developer should format
* the resource as an integer to avoid unnecessary type conversion.
*/
public Builder detectResourceMismatches() {
return enable(DETECT_RESOURCE_MISMATCH);
}
/**
* Enable detection of disk writes.
*/
public Builder detectDiskWrites() {
return enable(DETECT_DISK_WRITE);
}
/**
* Disable detection of disk writes.
*/
public Builder permitDiskWrites() {
return disable(DETECT_DISK_WRITE);
}
/**
* Show an annoying dialog to the developer on detected
* violations, rate-limited to be only a little annoying.
*/
public Builder penaltyDialog() {
return enable(PENALTY_DIALOG);
}
/**
* Crash the whole process on violation. This penalty runs at
* the end of all enabled penalties so you'll still get
* see logging or other violations before the process dies.
*
* Unlike {@link #penaltyDeathOnNetwork}, this applies
* to disk reads, disk writes, and network usage if their
* corresponding detect flags are set.
*/
public Builder penaltyDeath() {
return enable(PENALTY_DEATH);
}
/**
* Crash the whole process on any network usage. Unlike
* {@link #penaltyDeath}, this penalty runs
* before anything else. You must still have
* called {@link #detectNetwork} to enable this.
*
* In the Honeycomb or later SDKs, this is on by default.
*/
public Builder penaltyDeathOnNetwork() {
return enable(PENALTY_DEATH_ON_NETWORK);
}
/**
* Flash the screen during a violation.
*/
public Builder penaltyFlashScreen() {
return enable(PENALTY_FLASH);
}
/**
* Log detected violations to the system log.
*/
public Builder penaltyLog() {
return enable(PENALTY_LOG);
}
/**
* Enable detected violations log a stacktrace and timing data
* to the {@link android.os.DropBoxManager DropBox} on policy
* violation. Intended mostly for platform integrators doing
* beta user field data collection.
*/
public Builder penaltyDropBox() {
return enable(PENALTY_DROPBOX);
}
private Builder enable(int bit) {
mMask |= bit;
return this;
}
private Builder disable(int bit) {
mMask &= ~bit;
return this;
}
/**
* Construct the ThreadPolicy instance.
*
* Note: if no penalties are enabled before calling
* The policy is enabled by {@link #setVmPolicy}.
*/
public static final class VmPolicy {
/**
* The default, lax policy which doesn't catch anything.
*/
public static final VmPolicy LAX = new VmPolicy(0, EMPTY_CLASS_LIMIT_MAP);
final int mask;
// Map from class to max number of allowed instances in memory.
final HashMap You can call as many {@code detect} and {@code penalty}
* methods as you like. Currently order is insignificant: all
* penalties apply to all detected problems.
*
* For example, detect everything and log anything that's found:
* In the Honeycomb release this includes leaks of
* SQLite cursors, Activities, and other closable objects
* but will likely expand in future releases.
*/
public Builder detectAll() {
int flags = DETECT_VM_ACTIVITY_LEAKS | DETECT_VM_CURSOR_LEAKS
| DETECT_VM_CLOSABLE_LEAKS | DETECT_VM_REGISTRATION_LEAKS
| DETECT_VM_FILE_URI_EXPOSURE;
// TODO: always add DETECT_VM_CLEARTEXT_NETWORK once we have facility
// for apps to mark sockets that should be ignored
if (SystemProperties.getBoolean(CLEARTEXT_PROPERTY, false)) {
flags |= DETECT_VM_CLEARTEXT_NETWORK;
}
return enable(flags);
}
/**
* Detect when an
* {@link android.database.sqlite.SQLiteCursor} or other
* SQLite object is finalized without having been closed.
*
* You always want to explicitly close your SQLite
* cursors to avoid unnecessary database contention and
* temporary memory leaks.
*/
public Builder detectLeakedSqlLiteObjects() {
return enable(DETECT_VM_CURSOR_LEAKS);
}
/**
* Detect when an {@link java.io.Closeable} or other
* object with a explict termination method is finalized
* without having been closed.
*
* You always want to explicitly close such objects to
* avoid unnecessary resources leaks.
*/
public Builder detectLeakedClosableObjects() {
return enable(DETECT_VM_CLOSABLE_LEAKS);
}
/**
* Detect when a {@link BroadcastReceiver} or
* {@link ServiceConnection} is leaked during {@link Context}
* teardown.
*/
public Builder detectLeakedRegistrationObjects() {
return enable(DETECT_VM_REGISTRATION_LEAKS);
}
/**
* Detect when this application exposes a {@code file://}
* {@link android.net.Uri} to another app.
*
* This exposure is discouraged since the receiving app may not have
* access to the shared path. For example, the receiving app may not
* have requested the
* {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} runtime
* permission, or the platform may be sharing the
* {@link android.net.Uri} across user profile boundaries.
*
* Instead, apps should use {@code content://} Uris so the platform
* can extend temporary permission for the receiving app to access
* the resource.
*
* @see android.support.v4.content.FileProvider
* @see Intent#FLAG_GRANT_READ_URI_PERMISSION
*/
public Builder detectFileUriExposure() {
return enable(DETECT_VM_FILE_URI_EXPOSURE);
}
/**
* Detect any network traffic from the calling app which is not
* wrapped in SSL/TLS. This can help you detect places that your app
* is inadvertently sending cleartext data across the network.
*
* Using {@link #penaltyDeath()} or
* {@link #penaltyDeathOnCleartextNetwork()} will block further
* traffic on that socket to prevent accidental data leakage, in
* addition to crashing your process.
*
* Using {@link #penaltyDropBox()} will log the raw contents of the
* packet that triggered the violation.
*
* This inspects both IPv4/IPv6 and TCP/UDP network traffic, but it
* may be subject to false positives, such as when STARTTLS
* protocols or HTTP proxies are used.
*/
public Builder detectCleartextNetwork() {
return enable(DETECT_VM_CLEARTEXT_NETWORK);
}
/**
* Crashes the whole process on violation. This penalty runs at the
* end of all enabled penalties so you'll still get your logging or
* other violations before the process dies.
*/
public Builder penaltyDeath() {
return enable(PENALTY_DEATH);
}
/**
* Crashes the whole process when cleartext network traffic is
* detected.
*
* @see #detectCleartextNetwork()
*/
public Builder penaltyDeathOnCleartextNetwork() {
return enable(PENALTY_DEATH_ON_CLEARTEXT_NETWORK);
}
/**
* Crashes the whole process when a {@code file://}
* {@link android.net.Uri} is exposed beyond this app.
*
* @see #detectFileUriExposure()
*/
public Builder penaltyDeathOnFileUriExposure() {
return enable(PENALTY_DEATH_ON_FILE_URI_EXPOSURE);
}
/**
* Log detected violations to the system log.
*/
public Builder penaltyLog() {
return enable(PENALTY_LOG);
}
/**
* Enable detected violations log a stacktrace and timing data
* to the {@link android.os.DropBoxManager DropBox} on policy
* violation. Intended mostly for platform integrators doing
* beta user field data collection.
*/
public Builder penaltyDropBox() {
return enable(PENALTY_DROPBOX);
}
private Builder enable(int bit) {
mMask |= bit;
return this;
}
/**
* Construct the VmPolicy instance.
*
* Note: if no penalties are enabled before calling
* Internally this sets a thread-local variable which is
* propagated across cross-process IPC calls, meaning you can
* catch violations when a system service or another process
* accesses the disk or network on your behalf.
*
* @param policy the policy to put into place
*/
public static void setThreadPolicy(final ThreadPolicy policy) {
setThreadPolicyMask(policy.mask);
}
private static void setThreadPolicyMask(final int policyMask) {
// In addition to the Java-level thread-local in Dalvik's
// BlockGuard, we also need to keep a native thread-local in
// Binder in order to propagate the value across Binder calls,
// even across native-only processes. The two are kept in
// sync via the callback to onStrictModePolicyChange, below.
setBlockGuardPolicy(policyMask);
// And set the Android native version...
Binder.setThreadStrictModePolicy(policyMask);
}
// Sets the policy in Dalvik/libcore (BlockGuard)
private static void setBlockGuardPolicy(final int policyMask) {
if (policyMask == 0) {
BlockGuard.setThreadPolicy(BlockGuard.LAX_POLICY);
return;
}
final BlockGuard.Policy policy = BlockGuard.getThreadPolicy();
final AndroidBlockGuardPolicy androidPolicy;
if (policy instanceof AndroidBlockGuardPolicy) {
androidPolicy = (AndroidBlockGuardPolicy) policy;
} else {
androidPolicy = threadAndroidPolicy.get();
BlockGuard.setThreadPolicy(androidPolicy);
}
androidPolicy.setPolicyMask(policyMask);
}
// Sets up CloseGuard in Dalvik/libcore
private static void setCloseGuardEnabled(boolean enabled) {
if (!(CloseGuard.getReporter() instanceof AndroidCloseGuardReporter)) {
CloseGuard.setReporter(new AndroidCloseGuardReporter());
}
CloseGuard.setEnabled(enabled);
}
/**
* @hide
*/
public static class StrictModeViolation extends BlockGuard.BlockGuardPolicyException {
public StrictModeViolation(int policyState, int policyViolated, String message) {
super(policyState, policyViolated, message);
}
}
/**
* @hide
*/
public static class StrictModeNetworkViolation extends StrictModeViolation {
public StrictModeNetworkViolation(int policyMask) {
super(policyMask, DETECT_NETWORK, null);
}
}
/**
* @hide
*/
private static class StrictModeDiskReadViolation extends StrictModeViolation {
public StrictModeDiskReadViolation(int policyMask) {
super(policyMask, DETECT_DISK_READ, null);
}
}
/**
* @hide
*/
private static class StrictModeDiskWriteViolation extends StrictModeViolation {
public StrictModeDiskWriteViolation(int policyMask) {
super(policyMask, DETECT_DISK_WRITE, null);
}
}
/**
* @hide
*/
private static class StrictModeCustomViolation extends StrictModeViolation {
public StrictModeCustomViolation(int policyMask, String name) {
super(policyMask, DETECT_CUSTOM, name);
}
}
/**
* @hide
*/
private static class StrictModeResourceMismatchViolation extends StrictModeViolation {
public StrictModeResourceMismatchViolation(int policyMask, Object tag) {
super(policyMask, DETECT_RESOURCE_MISMATCH, tag != null ? tag.toString() : null);
}
}
/**
* Returns the bitmask of the current thread's policy.
*
* @return the bitmask of all the DETECT_* and PENALTY_* bits currently enabled
*
* @hide
*/
public static int getThreadPolicyMask() {
return BlockGuard.getThreadPolicy().getPolicyMask();
}
/**
* Returns the current thread's policy.
*/
public static ThreadPolicy getThreadPolicy() {
// TODO: this was a last minute Gingerbread API change (to
// introduce VmPolicy cleanly) but this isn't particularly
// optimal for users who might call this method often. This
// should be in a thread-local and not allocate on each call.
return new ThreadPolicy(getThreadPolicyMask());
}
/**
* A convenience wrapper that takes the current
* {@link ThreadPolicy} from {@link #getThreadPolicy}, modifies it
* to permit both disk reads & writes, and sets the new policy
* with {@link #setThreadPolicy}, returning the old policy so you
* can restore it at the end of a block.
*
* @return the old policy, to be passed to {@link #setThreadPolicy} to
* restore the policy at the end of a block
*/
public static ThreadPolicy allowThreadDiskWrites() {
int oldPolicyMask = getThreadPolicyMask();
int newPolicyMask = oldPolicyMask & ~(DETECT_DISK_WRITE | DETECT_DISK_READ);
if (newPolicyMask != oldPolicyMask) {
setThreadPolicyMask(newPolicyMask);
}
return new ThreadPolicy(oldPolicyMask);
}
/**
* A convenience wrapper that takes the current
* {@link ThreadPolicy} from {@link #getThreadPolicy}, modifies it
* to permit disk reads, and sets the new policy
* with {@link #setThreadPolicy}, returning the old policy so you
* can restore it at the end of a block.
*
* @return the old policy, to be passed to setThreadPolicy to
* restore the policy.
*/
public static ThreadPolicy allowThreadDiskReads() {
int oldPolicyMask = getThreadPolicyMask();
int newPolicyMask = oldPolicyMask & ~(DETECT_DISK_READ);
if (newPolicyMask != oldPolicyMask) {
setThreadPolicyMask(newPolicyMask);
}
return new ThreadPolicy(oldPolicyMask);
}
// We don't want to flash the screen red in the system server
// process, nor do we want to modify all the call sites of
// conditionallyEnableDebugLogging() in the system server,
// so instead we use this to determine if we are the system server.
private static boolean amTheSystemServerProcess() {
// Fast path. Most apps don't have the system server's UID.
if (Process.myUid() != Process.SYSTEM_UID) {
return false;
}
// The settings app, though, has the system server's UID so
// look up our stack to see if we came from the system server.
Throwable stack = new Throwable();
stack.fillInStackTrace();
for (StackTraceElement ste : stack.getStackTrace()) {
String clsName = ste.getClassName();
if (clsName != null && clsName.startsWith("com.android.server.")) {
return true;
}
}
return false;
}
/**
* Enable DropBox logging for debug phone builds.
*
* @hide
*/
public static boolean conditionallyEnableDebugLogging() {
boolean doFlashes = SystemProperties.getBoolean(VISUAL_PROPERTY, false)
&& !amTheSystemServerProcess();
final boolean suppress = SystemProperties.getBoolean(DISABLE_PROPERTY, false);
// For debug builds, log event loop stalls to dropbox for analysis.
// Similar logic also appears in ActivityThread.java for system apps.
if (!doFlashes && (IS_USER_BUILD || suppress)) {
setCloseGuardEnabled(false);
return false;
}
// Eng builds have flashes on all the time. The suppression property
// overrides this, so we force the behavior only after the short-circuit
// check above.
if (IS_ENG_BUILD) {
doFlashes = true;
}
// Thread policy controls BlockGuard.
int threadPolicyMask = StrictMode.DETECT_DISK_WRITE |
StrictMode.DETECT_DISK_READ |
StrictMode.DETECT_NETWORK;
if (!IS_USER_BUILD) {
threadPolicyMask |= StrictMode.PENALTY_DROPBOX;
}
if (doFlashes) {
threadPolicyMask |= StrictMode.PENALTY_FLASH;
}
StrictMode.setThreadPolicyMask(threadPolicyMask);
// VM Policy controls CloseGuard, detection of Activity leaks,
// and instance counting.
if (IS_USER_BUILD) {
setCloseGuardEnabled(false);
} else {
VmPolicy.Builder policyBuilder = new VmPolicy.Builder().detectAll().penaltyDropBox();
if (IS_ENG_BUILD) {
policyBuilder.penaltyLog();
}
setVmPolicy(policyBuilder.build());
setCloseGuardEnabled(vmClosableObjectLeaksEnabled());
}
return true;
}
/**
* Used by the framework to make network usage on the main
* thread a fatal error.
*
* @hide
*/
public static void enableDeathOnNetwork() {
int oldPolicy = getThreadPolicyMask();
int newPolicy = oldPolicy | DETECT_NETWORK | PENALTY_DEATH_ON_NETWORK;
setThreadPolicyMask(newPolicy);
}
/**
* Used by the framework to make file usage a fatal error.
*
* @hide
*/
public static void enableDeathOnFileUriExposure() {
sVmPolicyMask |= DETECT_VM_FILE_URI_EXPOSURE | PENALTY_DEATH_ON_FILE_URI_EXPOSURE;
}
/**
* Used by lame internal apps that haven't done the hard work to get
* themselves off file:// Uris yet.
*
* @hide
*/
public static void disableDeathOnFileUriExposure() {
sVmPolicyMask &= ~(DETECT_VM_FILE_URI_EXPOSURE | PENALTY_DEATH_ON_FILE_URI_EXPOSURE);
}
/**
* Parses the BlockGuard policy mask out from the Exception's
* getMessage() String value. Kinda gross, but least
* invasive. :/
*
* Input is of the following forms:
* "policy=137 violation=64"
* "policy=137 violation=64 msg=Arbitrary text"
*
* Returns 0 on failure, which is a valid policy, but not a
* valid policy during a violation (else there must've been
* some policy in effect to violate).
*/
private static int parsePolicyFromMessage(String message) {
if (message == null || !message.startsWith("policy=")) {
return 0;
}
int spaceIndex = message.indexOf(' ');
if (spaceIndex == -1) {
return 0;
}
String policyString = message.substring(7, spaceIndex);
try {
return Integer.parseInt(policyString);
} catch (NumberFormatException e) {
return 0;
}
}
/**
* Like parsePolicyFromMessage(), but returns the violation.
*/
private static int parseViolationFromMessage(String message) {
if (message == null) {
return 0;
}
int violationIndex = message.indexOf("violation=");
if (violationIndex == -1) {
return 0;
}
int numberStartIndex = violationIndex + "violation=".length();
int numberEndIndex = message.indexOf(' ', numberStartIndex);
if (numberEndIndex == -1) {
numberEndIndex = message.length();
}
String violationString = message.substring(numberStartIndex, numberEndIndex);
try {
return Integer.parseInt(violationString);
} catch (NumberFormatException e) {
return 0;
}
}
private static final ThreadLocal This catches disk and network access on the main thread, as
* well as leaked SQLite cursors and unclosed resources. This is
* simply a wrapper around {@link #setVmPolicy} and {@link
* #setThreadPolicy}.
*/
public static void enableDefaults() {
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectAll()
.penaltyLog()
.build());
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
.detectAll()
.penaltyLog()
.build());
}
/**
* @hide
*/
public static boolean vmSqliteObjectLeaksEnabled() {
return (sVmPolicyMask & DETECT_VM_CURSOR_LEAKS) != 0;
}
/**
* @hide
*/
public static boolean vmClosableObjectLeaksEnabled() {
return (sVmPolicyMask & DETECT_VM_CLOSABLE_LEAKS) != 0;
}
/**
* @hide
*/
public static boolean vmRegistrationLeaksEnabled() {
return (sVmPolicyMask & DETECT_VM_REGISTRATION_LEAKS) != 0;
}
/**
* @hide
*/
public static boolean vmFileUriExposureEnabled() {
return (sVmPolicyMask & DETECT_VM_FILE_URI_EXPOSURE) != 0;
}
/**
* @hide
*/
public static boolean vmCleartextNetworkEnabled() {
return (sVmPolicyMask & DETECT_VM_CLEARTEXT_NETWORK) != 0;
}
/**
* @hide
*/
public static void onSqliteObjectLeaked(String message, Throwable originStack) {
onVmPolicyViolation(message, originStack);
}
/**
* @hide
*/
public static void onWebViewMethodCalledOnWrongThread(Throwable originStack) {
onVmPolicyViolation(null, originStack);
}
/**
* @hide
*/
public static void onIntentReceiverLeaked(Throwable originStack) {
onVmPolicyViolation(null, originStack);
}
/**
* @hide
*/
public static void onServiceConnectionLeaked(Throwable originStack) {
onVmPolicyViolation(null, originStack);
}
/**
* @hide
*/
public static void onFileUriExposed(Uri uri, String location) {
final String message = uri + " exposed beyond app through " + location;
if ((sVmPolicyMask & PENALTY_DEATH_ON_FILE_URI_EXPOSURE) != 0) {
throw new FileUriExposedException(message);
} else {
onVmPolicyViolation(null, new Throwable(message));
}
}
/**
* @hide
*/
public static void onCleartextNetworkDetected(byte[] firstPacket) {
byte[] rawAddr = null;
if (firstPacket != null) {
if (firstPacket.length >= 20 && (firstPacket[0] & 0xf0) == 0x40) {
// IPv4
rawAddr = new byte[4];
System.arraycopy(firstPacket, 16, rawAddr, 0, 4);
} else if (firstPacket.length >= 40 && (firstPacket[0] & 0xf0) == 0x60) {
// IPv6
rawAddr = new byte[16];
System.arraycopy(firstPacket, 24, rawAddr, 0, 16);
}
}
final int uid = android.os.Process.myUid();
String msg = "Detected cleartext network traffic from UID " + uid;
if (rawAddr != null) {
try {
msg = "Detected cleartext network traffic from UID " + uid + " to "
+ InetAddress.getByAddress(rawAddr);
} catch (UnknownHostException ignored) {
}
}
final boolean forceDeath = (sVmPolicyMask & PENALTY_DEATH_ON_CLEARTEXT_NETWORK) != 0;
onVmPolicyViolation(HexDump.dumpHexString(firstPacket).trim(), new Throwable(msg),
forceDeath);
}
// Map from VM violation fingerprint to uptime millis.
private static final HashMap The name is an arbitary label (or tag) that will be applied
* to any strictmode violation that happens while this span is
* active. You must call finish() on the span when done.
*
* This will never return null, but on devices without debugging
* enabled, this may return a dummy object on which the finish()
* method is a no-op.
*
* TODO: add CloseGuard to this, verifying callers call finish.
*
* @hide
*/
public static Span enterCriticalSpan(String name) {
if (IS_USER_BUILD) {
return NO_OP_SPAN;
}
if (name == null || name.isEmpty()) {
throw new IllegalArgumentException("name must be non-null and non-empty");
}
ThreadSpanState state = sThisThreadSpanState.get();
Span span = null;
synchronized (state) {
if (state.mFreeListHead != null) {
span = state.mFreeListHead;
state.mFreeListHead = span.mNext;
state.mFreeListSize--;
} else {
// Shouldn't have to do this often.
span = new Span(state);
}
span.mName = name;
span.mCreateMillis = SystemClock.uptimeMillis();
span.mNext = state.mActiveHead;
span.mPrev = null;
state.mActiveHead = span;
state.mActiveSize++;
if (span.mNext != null) {
span.mNext.mPrev = span;
}
if (LOG_V) Log.d(TAG, "Span enter=" + name + "; size=" + state.mActiveSize);
}
return span;
}
/**
* For code to note that it's slow. This is a no-op unless the
* current thread's {@link android.os.StrictMode.ThreadPolicy} has
* {@link android.os.StrictMode.ThreadPolicy.Builder#detectCustomSlowCalls}
* enabled.
*
* @param name a short string for the exception stack trace that's
* built if when this fires.
*/
public static void noteSlowCall(String name) {
BlockGuard.Policy policy = BlockGuard.getThreadPolicy();
if (!(policy instanceof AndroidBlockGuardPolicy)) {
// StrictMode not enabled.
return;
}
((AndroidBlockGuardPolicy) policy).onCustomSlowCall(name);
}
/**
* For code to note that a resource was obtained using a type other than
* its defined type. This is a no-op unless the current thread's
* {@link android.os.StrictMode.ThreadPolicy} has
* {@link android.os.StrictMode.ThreadPolicy.Builder#detectResourceMismatches()}
* enabled.
*
* @param tag an object for the exception stack trace that's
* built if when this fires.
* @hide
*/
public static void noteResourceMismatch(Object tag) {
BlockGuard.Policy policy = BlockGuard.getThreadPolicy();
if (!(policy instanceof AndroidBlockGuardPolicy)) {
// StrictMode not enabled.
return;
}
((AndroidBlockGuardPolicy) policy).onResourceMismatch(tag);
}
/**
* @hide
*/
public static void noteDiskRead() {
BlockGuard.Policy policy = BlockGuard.getThreadPolicy();
if (!(policy instanceof AndroidBlockGuardPolicy)) {
// StrictMode not enabled.
return;
}
((AndroidBlockGuardPolicy) policy).onReadFromDisk();
}
/**
* @hide
*/
public static void noteDiskWrite() {
BlockGuard.Policy policy = BlockGuard.getThreadPolicy();
if (!(policy instanceof AndroidBlockGuardPolicy)) {
// StrictMode not enabled.
return;
}
((AndroidBlockGuardPolicy) policy).onWriteToDisk();
}
// Guarded by StrictMode.class
private static final HashMap
* StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder()
* .detectAll()
* .penaltyLog()
* .build();
* StrictMode.setThreadPolicy(policy);
*
*/
public static final class Builder {
private int mMask = 0;
/**
* Create a Builder that detects nothing and has no
* violations. (but note that {@link #build} will default
* to enabling {@link #penaltyLog} if no other penalties
* are specified)
*/
public Builder() {
mMask = 0;
}
/**
* Initialize a Builder from an existing ThreadPolicy.
*/
public Builder(ThreadPolicy policy) {
mMask = policy.mask;
}
/**
* Detect everything that's potentially suspect.
*
* build
, {@link #penaltyLog} is implicitly
* set.
*/
public ThreadPolicy build() {
// If there are detection bits set but no violation bits
// set, enable simple logging.
if (mMask != 0 &&
(mMask & (PENALTY_DEATH | PENALTY_LOG |
PENALTY_DROPBOX | PENALTY_DIALOG)) == 0) {
penaltyLog();
}
return new ThreadPolicy(mMask);
}
}
}
/**
* {@link StrictMode} policy applied to all threads in the virtual machine's process.
*
*
* StrictMode.VmPolicy policy = new StrictMode.VmPolicy.Builder()
* .detectAll()
* .penaltyLog()
* .build();
* StrictMode.setVmPolicy(policy);
*
*/
public static final class Builder {
private int mMask;
private HashMapbuild
, {@link #penaltyLog} is implicitly
* set.
*/
public VmPolicy build() {
// If there are detection bits set but no violation bits
// set, enable simple logging.
if (mMask != 0 &&
(mMask & (PENALTY_DEATH | PENALTY_LOG |
PENALTY_DROPBOX | PENALTY_DIALOG)) == 0) {
penaltyLog();
}
return new VmPolicy(mMask,
mClassInstanceLimit != null ? mClassInstanceLimit : EMPTY_CLASS_LIMIT_MAP);
}
}
}
/**
* Log of strict mode violation stack traces that have occurred
* during a Binder call, to be serialized back later to the caller
* via Parcel.writeNoException() (amusingly) where the caller can
* choose how to react.
*/
private static final ThreadLocal