diff options
author | Brad Fitzpatrick <bradfitz@android.com> | 2010-10-01 13:57:04 -0700 |
---|---|---|
committer | Brad Fitzpatrick <bradfitz@android.com> | 2010-10-01 13:57:04 -0700 |
commit | e0ad63bf1e038dd84ec2502243236f86104f990d (patch) | |
tree | f05b9ed0e839b84ae5f35025e1a50da56b68b2bc | |
parent | 866717406710595a487cdca33f698876dcd4e8af (diff) | |
parent | 6718b365bcce5bd9e67867bd165d771c2226582d (diff) | |
download | frameworks_base-e0ad63bf1e038dd84ec2502243236f86104f990d.zip frameworks_base-e0ad63bf1e038dd84ec2502243236f86104f990d.tar.gz frameworks_base-e0ad63bf1e038dd84ec2502243236f86104f990d.tar.bz2 |
resolved conflicts for merge of 6718b365 to master
Change-Id: I32762a4a3b00856f6765d50667b667264a385fc6
-rw-r--r-- | api/current.xml | 322 | ||||
-rw-r--r-- | core/java/android/database/sqlite/SQLiteCompiledSql.java | 11 | ||||
-rw-r--r-- | core/java/android/database/sqlite/SQLiteCursor.java | 8 | ||||
-rw-r--r-- | core/java/android/os/StrictMode.java | 570 |
4 files changed, 778 insertions, 133 deletions
diff --git a/api/current.xml b/api/current.xml index ba7e7f1..aadffa3 100644 --- a/api/current.xml +++ b/api/current.xml @@ -139872,7 +139872,7 @@ visibility="public" > <method name="allowThreadDiskReads" - return="int" + return="android.os.StrictMode.ThreadPolicy" abstract="false" native="false" synchronized="false" @@ -139883,7 +139883,7 @@ > </method> <method name="allowThreadDiskWrites" - return="int" + return="android.os.StrictMode.ThreadPolicy" abstract="false" native="false" synchronized="false" @@ -139894,7 +139894,18 @@ > </method> <method name="getThreadPolicy" - return="int" + return="android.os.StrictMode.ThreadPolicy" + abstract="false" + native="false" + synchronized="false" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="getVmPolicy" + return="android.os.StrictMode.VmPolicy" abstract="false" native="false" synchronized="false" @@ -139914,86 +139925,313 @@ deprecated="not deprecated" visibility="public" > -<parameter name="policyMask" type="int"> +<parameter name="policy" type="android.os.StrictMode.ThreadPolicy"> </parameter> </method> -<field name="DISALLOW_DISK_READ" - type="int" - transient="false" - volatile="false" - value="2" +<method name="setVmPolicy" + return="void" + abstract="false" + native="false" + synchronized="false" static="true" - final="true" + final="false" deprecated="not deprecated" visibility="public" > -</field> -<field name="DISALLOW_DISK_WRITE" - type="int" - transient="false" - volatile="false" - value="1" +<parameter name="policy" type="android.os.StrictMode.VmPolicy"> +</parameter> +</method> +</class> +<class name="StrictMode.ThreadPolicy" + extends="java.lang.Object" + abstract="false" static="true" final="true" deprecated="not deprecated" visibility="public" > -</field> -<field name="DISALLOW_NETWORK" - type="int" +<field name="LAX" + type="android.os.StrictMode.ThreadPolicy" transient="false" volatile="false" - value="4" static="true" final="true" deprecated="not deprecated" visibility="public" > </field> -<field name="PENALTY_DEATH" - type="int" - transient="false" - volatile="false" - value="64" +</class> +<class name="StrictMode.ThreadPolicy.Builder" + extends="java.lang.Object" + abstract="false" static="true" final="true" deprecated="not deprecated" visibility="public" > -</field> -<field name="PENALTY_DIALOG" - type="int" - transient="false" - volatile="false" - value="32" +<constructor name="StrictMode.ThreadPolicy.Builder" + type="android.os.StrictMode.ThreadPolicy.Builder" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</constructor> +<constructor name="StrictMode.ThreadPolicy.Builder" + type="android.os.StrictMode.ThreadPolicy.Builder" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="policy" type="android.os.StrictMode.ThreadPolicy"> +</parameter> +</constructor> +<method name="build" + return="android.os.StrictMode.ThreadPolicy" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="detectAll" + return="android.os.StrictMode.ThreadPolicy.Builder" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="detectDiskReads" + return="android.os.StrictMode.ThreadPolicy.Builder" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="detectDiskWrites" + return="android.os.StrictMode.ThreadPolicy.Builder" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="detectNetwork" + return="android.os.StrictMode.ThreadPolicy.Builder" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="penaltyDeath" + return="android.os.StrictMode.ThreadPolicy.Builder" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="penaltyDialog" + return="android.os.StrictMode.ThreadPolicy.Builder" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="penaltyDropBox" + return="android.os.StrictMode.ThreadPolicy.Builder" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="penaltyLog" + return="android.os.StrictMode.ThreadPolicy.Builder" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="permitAll" + return="android.os.StrictMode.ThreadPolicy.Builder" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="permitDiskReads" + return="android.os.StrictMode.ThreadPolicy.Builder" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="permitDiskWrites" + return="android.os.StrictMode.ThreadPolicy.Builder" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="permitNetwork" + return="android.os.StrictMode.ThreadPolicy.Builder" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +</class> +<class name="StrictMode.VmPolicy" + extends="java.lang.Object" + abstract="false" static="true" final="true" deprecated="not deprecated" visibility="public" > -</field> -<field name="PENALTY_DROPBOX" - type="int" +<field name="LAX" + type="android.os.StrictMode.VmPolicy" transient="false" volatile="false" - value="128" static="true" final="true" deprecated="not deprecated" visibility="public" > </field> -<field name="PENALTY_LOG" - type="int" - transient="false" - volatile="false" - value="16" +</class> +<class name="StrictMode.VmPolicy.Builder" + extends="java.lang.Object" + abstract="false" static="true" final="true" deprecated="not deprecated" visibility="public" > -</field> +<constructor name="StrictMode.VmPolicy.Builder" + type="android.os.StrictMode.VmPolicy.Builder" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</constructor> +<method name="build" + return="android.os.StrictMode.VmPolicy" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="detectAll" + return="android.os.StrictMode.VmPolicy.Builder" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="detectLeakedSqlLiteObjects" + return="android.os.StrictMode.VmPolicy.Builder" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="penaltyDeath" + return="android.os.StrictMode.VmPolicy.Builder" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="penaltyDropBox" + return="android.os.StrictMode.VmPolicy.Builder" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="penaltyLog" + return="android.os.StrictMode.VmPolicy.Builder" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> </class> <class name="SystemClock" extends="java.lang.Object" @@ -249759,7 +249997,7 @@ deprecated="not deprecated" visibility="public" > -<parameter name="n" type="long"> +<parameter name="byteCount" type="long"> </parameter> <exception name="IOException" type="java.io.IOException"> </exception> diff --git a/core/java/android/database/sqlite/SQLiteCompiledSql.java b/core/java/android/database/sqlite/SQLiteCompiledSql.java index 6ed1a90..a7ad757 100644 --- a/core/java/android/database/sqlite/SQLiteCompiledSql.java +++ b/core/java/android/database/sqlite/SQLiteCompiledSql.java @@ -16,6 +16,7 @@ package android.database.sqlite; +import android.os.StrictMode; import android.util.Log; /** @@ -106,11 +107,13 @@ import android.util.Log; // but if the database itself is not closed and is GC'ed, then // all sub-objects attached to the database could end up getting GC'ed too. // in that case, don't print any warning. - if (mInUse) { + if (mInUse && StrictMode.vmSqliteObjectLeaksEnabled()) { int len = mSqlStmt.length(); - Log.w(TAG, "Releasing statement in a finalizer. Please ensure " + - "that you explicitly call close() on your cursor: " + - mSqlStmt.substring(0, (len > 100) ? 100 : len), mStackTrace); + StrictMode.onSqliteObjectLeaked( + "Releasing statement in a finalizer. Please ensure " + + "that you explicitly call close() on your cursor: " + + mSqlStmt.substring(0, (len > 100) ? 100 : len), + mStackTrace); } releaseSqlStatement(); } finally { diff --git a/core/java/android/database/sqlite/SQLiteCursor.java b/core/java/android/database/sqlite/SQLiteCursor.java index fa7763d..89e8ab7 100644 --- a/core/java/android/database/sqlite/SQLiteCursor.java +++ b/core/java/android/database/sqlite/SQLiteCursor.java @@ -25,6 +25,7 @@ import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.Process; +import android.os.StrictMode; import android.util.Config; import android.util.Log; @@ -505,11 +506,14 @@ public class SQLiteCursor extends AbstractWindowedCursor { try { // if the cursor hasn't been closed yet, close it first if (mWindow != null) { - int len = mQuery.mSql.length(); - Log.e(TAG, "Finalizing a Cursor that has not been deactivated or closed. " + + if (StrictMode.vmSqliteObjectLeaksEnabled()) { + int len = mQuery.mSql.length(); + StrictMode.onSqliteObjectLeaked( + "Finalizing a Cursor that has not been deactivated or closed. " + "database = " + mQuery.mDatabase.getPath() + ", table = " + mEditTable + ", query = " + mQuery.mSql.substring(0, (len > 100) ? 100 : len), mStackTrace); + } close(); SQLiteDebug.notifyActiveCursorFinalized(); } else { diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java index 3ddaad9..9494a06 100644 --- a/core/java/android/os/StrictMode.java +++ b/core/java/android/os/StrictMode.java @@ -30,8 +30,9 @@ import java.util.ArrayList; import java.util.HashMap; /** - * <p>StrictMode is a developer tool which lets you impose stricter - * rules under which your application runs. + * <p>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. * * <p>StrictMode is most commonly used to catch accidental disk or * network access on the application's main thread, where UI @@ -55,24 +56,33 @@ import java.util.HashMap; * <pre> * public void onCreate() { * if (DEVELOPER_MODE) { - * StrictMode.setThreadPolicy(StrictMode.DISALLOW_DISK_WRITE | - * StrictMode.DISALLOW_DISK_READ | - * StrictMode.DISALLOW_NETWORK | - * StrictMode.PENALTY_LOG); + * 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}() + * .detectLeakedSqlLiteCursors() + * .penaltyLog() + * .penaltyDeath() + * .build()); * } * super.onCreate(); * } * </pre> * - * <p>Then you can watch the output of <code>adb logcat</code> while you - * use your application. + * <p>You can decide what should happen when a violation is detected. + * For example, using {@link ThreadPolicy.Builder#penaltyLog} you can + * watch the output of <code>adb logcat</code> while you use your + * application to see the violations as they happen. * * <p>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, - * a lot of disk accesses are often necessary during the normal activity lifecycle. Use - * StrictMode to find things you did on accident. Network requests on the UI thread + * 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. * * <p class="note">StrictMode is not a security mechanism and is not @@ -94,55 +104,50 @@ public final class StrictMode { // Only show an annoying dialog at most every 30 seconds private static final long MIN_DIALOG_INTERVAL_MS = 30000; - private StrictMode() {} + // Thread-policy: /** - * Flag for {@link #setThreadPolicy} to signal that you don't intend for this - * thread to write to disk. + * @hide */ - public static final int DISALLOW_DISK_WRITE = 0x01; + public static final int DETECT_DISK_WRITE = 0x01; // for ThreadPolicy /** - * Flag for {@link #setThreadPolicy} to signal that you don't intend for this - * thread to read from disk. + * @hide */ - public static final int DISALLOW_DISK_READ = 0x02; + public static final int DETECT_DISK_READ = 0x02; // for ThreadPolicy /** - * Flag for {@link #setThreadPolicy} to signal that you don't intend for this - * thread to access the network. + * @hide */ - public static final int DISALLOW_NETWORK = 0x04; + public static final int DETECT_NETWORK = 0x04; // for ThreadPolicy - /** @hide */ - public static final int DISALLOW_MASK = - DISALLOW_DISK_WRITE | DISALLOW_DISK_READ | DISALLOW_NETWORK; + // Process-policy: /** - * Penalty flag for {@link #setThreadPolicy} to log violations to - * the system log, visible with <code>adb logcat</code>. + * Note, a "VM_" bit, not thread. + * @hide + */ + public static final int DETECT_VM_CURSOR_LEAKS = 0x200; // for ProcessPolicy + + /** + * @hide */ public static final int PENALTY_LOG = 0x10; // normal android.util.Log + // Used for both process and thread policy: + /** - * Penalty flag for {@link #setThreadPolicy} to show an annoying - * dialog to the developer, rate-limited to be only a little - * annoying. + * @hide */ public static final int PENALTY_DIALOG = 0x20; /** - * Penalty flag for {@link #setThreadPolicy} to crash hard if - * policy is violated. + * @hide */ public static final int PENALTY_DEATH = 0x40; /** - * Penalty flag for {@link #setThreadPolicy} to 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. + * @hide */ public static final int PENALTY_DROPBOX = 0x80; @@ -159,10 +164,321 @@ public final class StrictMode { */ public static final int PENALTY_GATHER = 0x100; - /** @hide */ - public static final int PENALTY_MASK = - PENALTY_LOG | PENALTY_DIALOG | - PENALTY_DROPBOX | PENALTY_DEATH; + /** + * The current VmPolicy in effect. + */ + private static volatile int sVmPolicyMask = 0; + + private StrictMode() {} + + /** + * {@link StrictMode} policy applied to a certain thread. + * + * <p>The policy is enabled by {@link #setThreadPolicy}. The current policy + * can be retrieved with {@link #getThreadPolicy}. + * + * <p>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 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. + * + * <p>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. + * + * <p>For example, detect everything and log anything that's found: + * <pre> + * StrictMode.VmPolicy policy = new StrictMode.VmPolicy.Builder() + * .detectAll() + * .penaltyLog() + * .build(); + * StrictMode.setVmPolicy(policy); + * </pre> + */ + 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. + * + * <p>As of the Gingerbread release this includes network and + * disk operations but will likely expand in future releases. + */ + public Builder detectAll() { + return enable(DETECT_DISK_WRITE | DETECT_DISK_READ | DETECT_NETWORK); + } + + /** + * Disable the detection of everything. + */ + public Builder permitAll() { + return disable(DETECT_DISK_WRITE | DETECT_DISK_READ | DETECT_NETWORK); + } + + /** + * 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 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. + */ + public Builder penaltyDeath() { + return enable(PENALTY_DEATH); + } + + /** + * 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. + * + * <p>Note: if no penalties are enabled before calling + * <code>build</code>, {@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. + * + * <p>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); + + final int mask; + + private VmPolicy(int mask) { + this.mask = mask; + } + + @Override + public String toString() { + return "[StrictMode.VmPolicy; mask=" + mask + "]"; + } + + /** + * Creates {@link VmPolicy} 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. + * + * <p>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. + * + * <p>For example, detect everything and log anything that's found: + * <pre> + * StrictMode.VmPolicy policy = new StrictMode.VmPolicy.Builder() + * .detectAll() + * .penaltyLog() + * .build(); + * StrictMode.setVmPolicy(policy); + * </pre> + */ + public static final class Builder { + private int mMask; + + /** + * Detect everything that's potentially suspect. + * + * <p>As of the Gingerbread release this only includes + * SQLite cursor leaks but will likely expand in future + * releases. + */ + public Builder detectAll() { + return enable(DETECT_VM_CURSOR_LEAKS); + } + + /** + * Detect when an + * {@link android.database.sqlite.SQLiteCursor} or other + * SQLite object is finalized without having been closed. + * + * <p>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); + } + + /** + * Crashes the whole process on violation. This penalty runs at + * the end of all enabled penalties so yo you'll still get + * your logging or other violations before the process dies. + */ + public Builder penaltyDeath() { + return enable(PENALTY_DEATH); + } + + /** + * 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. + * + * <p>Note: if no penalties are enabled before calling + * <code>build</code>, {@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); + } + } + } /** * Log of strict mode violation stack traces that have occurred @@ -181,19 +497,21 @@ public final class StrictMode { }; /** - * Sets the policy for what actions the current thread isn't - * expected to do, as well as the penalty if it does. + * Sets the policy for what actions on the current thread should + * be detected, as well as the penalty if such actions occur. * - * <p>Internally this sets a thread-local integer which is + * <p>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 policyMask a bitmask of DISALLOW_* and PENALTY_* values, - * e.g. {@link #DISALLOW_DISK_READ}, {@link #DISALLOW_DISK_WRITE}, - * {@link #DISALLOW_NETWORK}, {@link #PENALTY_LOG}. + * @param policy the policy to put into place */ - public static void setThreadPolicy(final int policyMask) { + 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, @@ -222,65 +540,76 @@ public final class StrictMode { private static class StrictModeNetworkViolation extends BlockGuard.BlockGuardPolicyException { public StrictModeNetworkViolation(int policyMask) { - super(policyMask, DISALLOW_NETWORK); + super(policyMask, DETECT_NETWORK); } } private static class StrictModeDiskReadViolation extends BlockGuard.BlockGuardPolicyException { public StrictModeDiskReadViolation(int policyMask) { - super(policyMask, DISALLOW_DISK_READ); + super(policyMask, DETECT_DISK_READ); } } private static class StrictModeDiskWriteViolation extends BlockGuard.BlockGuardPolicyException { public StrictModeDiskWriteViolation(int policyMask) { - super(policyMask, DISALLOW_DISK_WRITE); + super(policyMask, DETECT_DISK_WRITE); } } /** * Returns the bitmask of the current thread's policy. * - * @return the bitmask of all the DISALLOW_* and PENALTY_* bits currently enabled + * @return the bitmask of all the DETECT_* and PENALTY_* bits currently enabled + * + * @hide */ - public static int getThreadPolicy() { + public static int getThreadPolicyMask() { return BlockGuard.getThreadPolicy().getPolicyMask(); } /** - * A convenience wrapper around {@link #getThreadPolicy} and - * {@link #setThreadPolicy}. Updates the current thread's policy - * mask to allow both reading & writing to disk, returning the - * old policy so you can restore it at the end of a block. + * Returns the current thread's policy. + */ + public static ThreadPolicy getThreadPolicy() { + 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 mask, to be passed to setThreadPolicy to - * restore the policy. + * @return the old policy, to be passed to {@link #setThreadPolicy} to + * restore the policy at the end of a block */ - public static int allowThreadDiskWrites() { - int oldPolicy = getThreadPolicy(); - int newPolicy = oldPolicy & ~(DISALLOW_DISK_WRITE | DISALLOW_DISK_READ); - if (newPolicy != oldPolicy) { - setThreadPolicy(newPolicy); + public static ThreadPolicy allowThreadDiskWrites() { + int oldPolicyMask = getThreadPolicyMask(); + int newPolicyMask = oldPolicyMask & ~(DETECT_DISK_WRITE | DETECT_DISK_READ); + if (newPolicyMask != oldPolicyMask) { + setThreadPolicyMask(newPolicyMask); } - return oldPolicy; + return new ThreadPolicy(oldPolicyMask); } /** - * A convenience wrapper around {@link #getThreadPolicy} and - * {@link #setThreadPolicy}. Updates the current thread's policy - * mask to allow reading from disk, returning the old - * policy so you can restore it at the end of a block. + * 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 mask, to be passed to setThreadPolicy to + * @return the old policy, to be passed to setThreadPolicy to * restore the policy. */ - public static int allowThreadDiskReads() { - int oldPolicy = getThreadPolicy(); - int newPolicy = oldPolicy & ~(DISALLOW_DISK_READ); - if (newPolicy != oldPolicy) { - setThreadPolicy(newPolicy); + public static ThreadPolicy allowThreadDiskReads() { + int oldPolicyMask = getThreadPolicyMask(); + int newPolicyMask = oldPolicyMask & ~(DETECT_DISK_READ); + if (newPolicyMask != oldPolicyMask) { + setThreadPolicyMask(newPolicyMask); } - return oldPolicy; + return new ThreadPolicy(oldPolicyMask); } /** @@ -294,11 +623,14 @@ public final class StrictMode { if ("user".equals(Build.TYPE)) { return false; } - StrictMode.setThreadPolicy( - StrictMode.DISALLOW_DISK_WRITE | - StrictMode.DISALLOW_DISK_READ | - StrictMode.DISALLOW_NETWORK | + StrictMode.setThreadPolicyMask( + StrictMode.DETECT_DISK_WRITE | + StrictMode.DETECT_DISK_READ | + StrictMode.DETECT_NETWORK | StrictMode.PENALTY_DROPBOX); + sVmPolicyMask = StrictMode.DETECT_VM_CURSOR_LEAKS | + StrictMode.PENALTY_DROPBOX | + StrictMode.PENALTY_LOG; return true; } @@ -372,7 +704,7 @@ public final class StrictMode { // Part of BlockGuard.Policy interface: public void onWriteToDisk() { - if ((mPolicyMask & DISALLOW_DISK_WRITE) == 0) { + if ((mPolicyMask & DETECT_DISK_WRITE) == 0) { return; } BlockGuard.BlockGuardPolicyException e = new StrictModeDiskWriteViolation(mPolicyMask); @@ -382,7 +714,7 @@ public final class StrictMode { // Part of BlockGuard.Policy interface: public void onReadFromDisk() { - if ((mPolicyMask & DISALLOW_DISK_READ) == 0) { + if ((mPolicyMask & DETECT_DISK_READ) == 0) { return; } BlockGuard.BlockGuardPolicyException e = new StrictModeDiskReadViolation(mPolicyMask); @@ -392,7 +724,7 @@ public final class StrictMode { // Part of BlockGuard.Policy interface: public void onNetwork() { - if ((mPolicyMask & DISALLOW_NETWORK) == 0) { + if ((mPolicyMask & DETECT_NETWORK) == 0) { return; } BlockGuard.BlockGuardPolicyException e = new StrictModeNetworkViolation(mPolicyMask); @@ -547,13 +879,13 @@ public final class StrictMode { if (violationMaskSubset != 0) { int violationBit = parseViolationFromMessage(info.crashInfo.exceptionMessage); violationMaskSubset |= violationBit; - final int savedPolicy = getThreadPolicy(); + final int savedPolicyMask = getThreadPolicyMask(); try { // First, remove any policy before we call into the Activity Manager, // otherwise we'll infinite recurse as we try to log policy violations // to disk, thus violating policy, thus requiring logging, etc... // We restore the current policy below, in the finally block. - setThreadPolicy(0); + setThreadPolicyMask(0); ActivityManagerNative.getDefault().handleApplicationStrictModeViolation( RuntimeInit.getApplicationObject(), @@ -563,7 +895,7 @@ public final class StrictMode { Log.e(TAG, "RemoteException trying to handle StrictMode violation", e); } finally { // Restore the policy. - setThreadPolicy(savedPolicy); + setThreadPolicyMask(savedPolicyMask); } } @@ -592,6 +924,74 @@ public final class StrictMode { } /** + * Sets the policy for what actions in the VM process (on any + * thread) should be detected, as well as the penalty if such + * actions occur. + * + * @param policy the policy to put into place + */ + public static void setVmPolicy(final VmPolicy policy) { + sVmPolicyMask = policy.mask; + } + + /** + * Gets the current VM policy. + */ + public static VmPolicy getVmPolicy() { + return new VmPolicy(sVmPolicyMask); + } + + /** + * @hide + */ + public static boolean vmSqliteObjectLeaksEnabled() { + return (sVmPolicyMask & DETECT_VM_CURSOR_LEAKS) != 0; + } + + /** + * @hide + */ + public static void onSqliteObjectLeaked(String message, Throwable originStack) { + if ((sVmPolicyMask & PENALTY_LOG) != 0) { + Log.e(TAG, message, originStack); + } + + if ((sVmPolicyMask & PENALTY_DROPBOX) != 0) { + final ViolationInfo info = new ViolationInfo(originStack, sVmPolicyMask); + + // The violationMask, passed to ActivityManager, is a + // subset of the original StrictMode policy bitmask, with + // only the bit violated and penalty bits to be executed + // by the ActivityManagerService remaining set. + int violationMaskSubset = PENALTY_DROPBOX | DETECT_VM_CURSOR_LEAKS; + final int savedPolicyMask = getThreadPolicyMask(); + try { + // First, remove any policy before we call into the Activity Manager, + // otherwise we'll infinite recurse as we try to log policy violations + // to disk, thus violating policy, thus requiring logging, etc... + // We restore the current policy below, in the finally block. + setThreadPolicyMask(0); + + ActivityManagerNative.getDefault().handleApplicationStrictModeViolation( + RuntimeInit.getApplicationObject(), + violationMaskSubset, + info); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException trying to handle StrictMode violation", e); + } finally { + // Restore the policy. + setThreadPolicyMask(savedPolicyMask); + } + } + + if ((sVmPolicyMask & PENALTY_DEATH) != 0) { + System.err.println("StrictMode VmPolicy violation with POLICY_DEATH; shutting down."); + Process.killProcess(Process.myPid()); + System.exit(10); + } + } + + /** * Called from Parcel.writeNoException() */ /* package */ static void writeGatheredViolationsToParcel(Parcel p) { @@ -621,7 +1021,7 @@ public final class StrictMode { new LogStackTrace().printStackTrace(new PrintWriter(sw)); String ourStack = sw.toString(); - int policyMask = getThreadPolicy(); + int policyMask = getThreadPolicyMask(); boolean currentlyGathering = (policyMask & PENALTY_GATHER) != 0; int numViolations = p.readInt(); |