diff options
author | Brad Fitzpatrick <bradfitz@android.com> | 2010-06-11 18:27:20 -0700 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2010-06-11 18:27:20 -0700 |
commit | 94f14aeca9e6c6d07b39a7f708eacadcfeb6fbd2 (patch) | |
tree | 8ce9cb5280609ee89e40cc90e2f7a3fa95aa5f8d | |
parent | 3a010fa6192f09121fc920810c5a8366b5b09f46 (diff) | |
parent | 46d42387464a651268648659e91d022566d4844c (diff) | |
download | frameworks_base-94f14aeca9e6c6d07b39a7f708eacadcfeb6fbd2.zip frameworks_base-94f14aeca9e6c6d07b39a7f708eacadcfeb6fbd2.tar.gz frameworks_base-94f14aeca9e6c6d07b39a7f708eacadcfeb6fbd2.tar.bz2 |
Merge "More StrictMode work, handling violations in ActivityManagerService." into gingerbread
8 files changed, 90 insertions, 50 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()); diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 0946ba2..e93f7ff 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -97,6 +97,7 @@ import android.os.Process; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.StrictMode; import android.os.SystemClock; import android.os.SystemProperties; import android.provider.Settings; @@ -9354,27 +9355,34 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } public void handleApplicationStrictModeViolation( - IBinder app, ApplicationErrorReport.CrashInfo crashInfo) { + IBinder app, int violationMask, ApplicationErrorReport.CrashInfo crashInfo) { ProcessRecord r = findAppProcess(app); // TODO: implement Log.w(TAG, "handleApplicationStrictModeViolation."); - AppErrorResult result = new AppErrorResult(); - synchronized (this) { - final long origId = Binder.clearCallingIdentity(); + if ((violationMask & StrictMode.PENALTY_DROPBOX) != 0) { + Integer crashFingerprint = crashInfo.stackTrace.hashCode(); + Log.d(TAG, "supposed to drop box for fingerprint " + crashFingerprint); + } - Message msg = Message.obtain(); - msg.what = SHOW_STRICT_MODE_VIOLATION_MSG; - HashMap<String, Object> data = new HashMap<String, Object>(); - data.put("result", result); - data.put("app", r); - msg.obj = data; - mHandler.sendMessage(msg); + if ((violationMask & StrictMode.PENALTY_DIALOG) != 0) { + AppErrorResult result = new AppErrorResult(); + synchronized (this) { + final long origId = Binder.clearCallingIdentity(); - Binder.restoreCallingIdentity(origId); + Message msg = Message.obtain(); + msg.what = SHOW_STRICT_MODE_VIOLATION_MSG; + HashMap<String, Object> data = new HashMap<String, Object>(); + data.put("result", result); + data.put("app", r); + msg.obj = data; + mHandler.sendMessage(msg); + + Binder.restoreCallingIdentity(origId); + } + int res = result.get(); + Log.w(TAG, "handleApplicationStrictModeViolation; res=" + res); } - int res = result.get(); - Log.w(TAG, "handleApplicationStrictModeViolation; res=" + res); } /** diff --git a/services/java/com/android/server/am/AppErrorDialog.java b/services/java/com/android/server/am/AppErrorDialog.java index 3a1aad6..a769c05 100644 --- a/services/java/com/android/server/am/AppErrorDialog.java +++ b/services/java/com/android/server/am/AppErrorDialog.java @@ -80,9 +80,6 @@ class AppErrorDialog extends BaseErrorDialog { DISMISS_TIMEOUT); } - public void onStop() { - } - private final Handler mHandler = new Handler() { public void handleMessage(Message msg) { synchronized (mProc) { diff --git a/services/java/com/android/server/am/StrictModeViolationDialog.java b/services/java/com/android/server/am/StrictModeViolationDialog.java index f4329e2..fe76d18 100644 --- a/services/java/com/android/server/am/StrictModeViolationDialog.java +++ b/services/java/com/android/server/am/StrictModeViolationDialog.java @@ -81,9 +81,6 @@ class StrictModeViolationDialog extends BaseErrorDialog { DISMISS_TIMEOUT); } - public void onStop() { - } - private final Handler mHandler = new Handler() { public void handleMessage(Message msg) { synchronized (mProc) { |