diff options
author | Brad Fitzpatrick <bradfitz@android.com> | 2010-06-11 13:57:58 -0700 |
---|---|---|
committer | Brad Fitzpatrick <bradfitz@android.com> | 2010-06-11 16:11:26 -0700 |
commit | 46d42387464a651268648659e91d022566d4844c (patch) | |
tree | 1252f3113aea8f95506bc0860b461fe3737c45c7 /core/java/android | |
parent | 126ca6f9ecab6f912ea9f4f00af35c410aae504b (diff) | |
download | frameworks_base-46d42387464a651268648659e91d022566d4844c.zip frameworks_base-46d42387464a651268648659e91d022566d4844c.tar.gz frameworks_base-46d42387464a651268648659e91d022566d4844c.tar.bz2 |
More StrictMode work, handling violations in ActivityManagerService.
Also starts to do duplicate-suppression.
Change-Id: I0502f6ab6c45fa319298de4874ecfe44b7829d21
Diffstat (limited to 'core/java/android')
-rw-r--r-- | core/java/android/app/ActivityManagerNative.java | 5 | ||||
-rw-r--r-- | core/java/android/app/ActivityThread.java | 1 | ||||
-rw-r--r-- | core/java/android/app/ApplicationErrorReport.java | 6 | ||||
-rw-r--r-- | core/java/android/app/IActivityManager.java | 7 | ||||
-rw-r--r-- | core/java/android/os/StrictMode.java | 79 |
5 files changed, 68 insertions, 30 deletions
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index b4c7edc..2c1f2da 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -1065,8 +1065,9 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM case HANDLE_APPLICATION_STRICT_MODE_VIOLATION_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); IBinder app = data.readStrongBinder(); + int violationMask = data.readInt(); ApplicationErrorReport.CrashInfo ci = new ApplicationErrorReport.CrashInfo(data); - handleApplicationStrictModeViolation(app, ci); + handleApplicationStrictModeViolation(app, violationMask, ci); reply.writeNoException(); return true; } @@ -2551,12 +2552,14 @@ class ActivityManagerProxy implements IActivityManager } public void handleApplicationStrictModeViolation(IBinder app, + int violationMask, ApplicationErrorReport.CrashInfo crashInfo) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); data.writeStrongBinder(app); + data.writeInt(violationMask); crashInfo.writeToParcel(data, 0); mRemote.transact(HANDLE_APPLICATION_STRICT_MODE_VIOLATION_TRANSACTION, data, reply, 0); reply.readException(); diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 49f1a8f..0ce790e 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -4139,7 +4139,6 @@ public final class ActivityThread { */ if ((data.appInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0 && !"user".equals(Build.TYPE)) { - StrictMode.setDropBoxManager(ContextImpl.createDropBoxManager()); StrictMode.setThreadBlockingPolicy( StrictMode.DISALLOW_DISK_WRITE | StrictMode.DISALLOW_DISK_READ | diff --git a/core/java/android/app/ApplicationErrorReport.java b/core/java/android/app/ApplicationErrorReport.java index f0cef98..57a23ae 100644 --- a/core/java/android/app/ApplicationErrorReport.java +++ b/core/java/android/app/ApplicationErrorReport.java @@ -52,7 +52,6 @@ public class ApplicationErrorReport implements Parcelable { // System property defining default error report receiver static final String DEFAULT_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.default"; - /** * Uninitialized error report. */ @@ -74,6 +73,11 @@ public class ApplicationErrorReport implements Parcelable { public static final int TYPE_BATTERY = 3; /** + * An error report about a StrictMode violation. + */ + public static final int TYPE_STRICT_MODE_VIOLATION = 4; + + /** * Type of this report. Can be one of {@link #TYPE_NONE}, * {@link #TYPE_CRASH}, {@link #TYPE_ANR}, or {@link #TYPE_BATTERY}. */ diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index ca09290..542bc41 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -256,7 +256,12 @@ public interface IActivityManager extends IInterface { ApplicationErrorReport.CrashInfo crashInfo) throws RemoteException; public boolean handleApplicationWtf(IBinder app, String tag, ApplicationErrorReport.CrashInfo crashInfo) throws RemoteException; - public void handleApplicationStrictModeViolation(IBinder app, + + // A StrictMode violation to be handled. The violationMask 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. + public void handleApplicationStrictModeViolation(IBinder app, int violationMask, ApplicationErrorReport.CrashInfo crashInfo) throws RemoteException; /* diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java index 876ec39..c0ae263 100644 --- a/core/java/android/os/StrictMode.java +++ b/core/java/android/os/StrictMode.java @@ -23,6 +23,8 @@ import com.android.internal.os.RuntimeInit; import dalvik.system.BlockGuard; +import java.util.HashMap; + /** * <p>StrictMode lets you impose stricter rules under which your * application runs.</p> @@ -30,6 +32,12 @@ import dalvik.system.BlockGuard; public final class StrictMode { private static final String TAG = "StrictMode"; + // 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; + private StrictMode() {} public static final int DISALLOW_DISK_WRITE = 0x01; @@ -73,6 +81,10 @@ public final class StrictMode { * @param policyMask a bitmask of DISALLOW_* and PENALTY_* values. */ public static void setThreadBlockingPolicy(final int policyMask) { + if (policyMask == 0) { + BlockGuard.setThreadPolicy(BlockGuard.LAX_POLICY); + return; + } BlockGuard.Policy policy = BlockGuard.getThreadPolicy(); if (!(policy instanceof AndroidBlockGuardPolicy)) { BlockGuard.setThreadPolicy(new AndroidBlockGuardPolicy(policyMask)); @@ -91,19 +103,13 @@ public final class StrictMode { return BlockGuard.getThreadPolicy().getPolicyMask(); } - /** @hide */ - public static void setDropBoxManager(DropBoxManager dropBoxManager) { - BlockGuard.Policy policy = BlockGuard.getThreadPolicy(); - if (!(policy instanceof AndroidBlockGuardPolicy)) { - policy = new AndroidBlockGuardPolicy(0); - BlockGuard.setThreadPolicy(policy); - } - ((AndroidBlockGuardPolicy) policy).setDropBoxManager(dropBoxManager); - } - private static class AndroidBlockGuardPolicy implements BlockGuard.Policy { private int mPolicyMask; - private DropBoxManager mDropBoxManager = null; + + // Map from violation stacktrace hashcode -> uptimeMillis of + // last violation. No locking needed, as this is only + // accessed by the same thread. + private final HashMap<Integer, Long> mLastViolationTime = new HashMap<Integer, Long>(); public AndroidBlockGuardPolicy(final int policyMask) { mPolicyMask = policyMask; @@ -142,10 +148,6 @@ public final class StrictMode { mPolicyMask = policyMask; } - public void setDropBoxManager(DropBoxManager dropBoxManager) { - mDropBoxManager = dropBoxManager; - } - private void handleViolation(int violationBit) { final BlockGuard.BlockGuardPolicyException violation = new BlockGuard.BlockGuardPolicyException(mPolicyMask, violationBit); @@ -182,7 +184,23 @@ public final class StrictMode { // the old policy here. int policy = violation.getPolicy(); - if ((policy & PENALTY_LOG) != 0) { + // Not _really_ a Crash, but we use the same data structure... + ApplicationErrorReport.CrashInfo crashInfo = + new ApplicationErrorReport.CrashInfo(violation); + + // Not perfect, but fast and good enough for dup suppression. + Integer crashFingerprint = crashInfo.stackTrace.hashCode(); + long lastViolationTime = 0; + if (mLastViolationTime.containsKey(crashFingerprint)) { + lastViolationTime = mLastViolationTime.get(crashFingerprint); + } + long now = SystemClock.uptimeMillis(); + mLastViolationTime.put(crashFingerprint, now); + long timeSinceLastViolationMillis = lastViolationTime == 0 ? + Long.MAX_VALUE : (now - lastViolationTime); + + if ((policy & PENALTY_LOG) != 0 && + timeSinceLastViolationMillis > MIN_LOG_INTERVAL_MS) { if (durationMillis != -1) { Log.d(TAG, "StrictMode policy violation; ~duration=" + durationMillis + " ms", violation); @@ -191,24 +209,33 @@ public final class StrictMode { } } - if ((policy & PENALTY_DIALOG) != 0) { - // Currently this is just used for the dialog. + // 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 violationMask = 0; + + if ((policy & PENALTY_DIALOG) != 0 && + timeSinceLastViolationMillis > MIN_DIALOG_INTERVAL_MS) { + violationMask |= PENALTY_DIALOG; + } + + if ((policy & PENALTY_DROPBOX) != 0 && lastViolationTime == 0) { + violationMask |= PENALTY_DROPBOX; + } + + if (violationMask != 0) { + violationMask |= violation.getPolicyViolation(); try { ActivityManagerNative.getDefault().handleApplicationStrictModeViolation( RuntimeInit.getApplicationObject(), + violationMask, new ApplicationErrorReport.CrashInfo(violation)); } catch (RemoteException e) { - Log.e(TAG, "RemoteException trying to open strict mode dialog", e); + Log.e(TAG, "RemoteException trying to handle StrictMode violation", e); } } - if ((policy & PENALTY_DROPBOX) != 0) { - // TODO: call into ActivityManagerNative to do the dropboxing. - // But do the first-layer signature dup-checking first client-side. - // This conditional should be combined with the above, too, along - // with PENALTY_DEATH below. - } - if ((policy & PENALTY_DEATH) != 0) { System.err.println("StrictMode policy violation with POLICY_DEATH; shutting down."); Process.killProcess(Process.myPid()); |