Merge "More StrictMode work, handling violations in ActivityManagerService." into gingerbread

This commit is contained in:
Brad Fitzpatrick
2010-06-11 18:27:20 -07:00
committed by Android (Google) Code Review
8 changed files with 92 additions and 52 deletions

View File

@ -1065,8 +1065,9 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
case HANDLE_APPLICATION_STRICT_MODE_VIOLATION_TRANSACTION: { case HANDLE_APPLICATION_STRICT_MODE_VIOLATION_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor); data.enforceInterface(IActivityManager.descriptor);
IBinder app = data.readStrongBinder(); IBinder app = data.readStrongBinder();
int violationMask = data.readInt();
ApplicationErrorReport.CrashInfo ci = new ApplicationErrorReport.CrashInfo(data); ApplicationErrorReport.CrashInfo ci = new ApplicationErrorReport.CrashInfo(data);
handleApplicationStrictModeViolation(app, ci); handleApplicationStrictModeViolation(app, violationMask, ci);
reply.writeNoException(); reply.writeNoException();
return true; return true;
} }
@ -2551,12 +2552,14 @@ class ActivityManagerProxy implements IActivityManager
} }
public void handleApplicationStrictModeViolation(IBinder app, public void handleApplicationStrictModeViolation(IBinder app,
int violationMask,
ApplicationErrorReport.CrashInfo crashInfo) throws RemoteException ApplicationErrorReport.CrashInfo crashInfo) throws RemoteException
{ {
Parcel data = Parcel.obtain(); Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain(); Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor); data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(app); data.writeStrongBinder(app);
data.writeInt(violationMask);
crashInfo.writeToParcel(data, 0); crashInfo.writeToParcel(data, 0);
mRemote.transact(HANDLE_APPLICATION_STRICT_MODE_VIOLATION_TRANSACTION, data, reply, 0); mRemote.transact(HANDLE_APPLICATION_STRICT_MODE_VIOLATION_TRANSACTION, data, reply, 0);
reply.readException(); reply.readException();

View File

@ -4139,7 +4139,6 @@ public final class ActivityThread {
*/ */
if ((data.appInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0 && if ((data.appInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0 &&
!"user".equals(Build.TYPE)) { !"user".equals(Build.TYPE)) {
StrictMode.setDropBoxManager(ContextImpl.createDropBoxManager());
StrictMode.setThreadBlockingPolicy( StrictMode.setThreadBlockingPolicy(
StrictMode.DISALLOW_DISK_WRITE | StrictMode.DISALLOW_DISK_WRITE |
StrictMode.DISALLOW_DISK_READ | StrictMode.DISALLOW_DISK_READ |

View File

@ -52,7 +52,6 @@ public class ApplicationErrorReport implements Parcelable {
// System property defining default error report receiver // System property defining default error report receiver
static final String DEFAULT_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.default"; static final String DEFAULT_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.default";
/** /**
* Uninitialized error report. * Uninitialized error report.
*/ */
@ -73,6 +72,11 @@ public class ApplicationErrorReport implements Parcelable {
*/ */
public static final int TYPE_BATTERY = 3; 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}, * Type of this report. Can be one of {@link #TYPE_NONE},
* {@link #TYPE_CRASH}, {@link #TYPE_ANR}, or {@link #TYPE_BATTERY}. * {@link #TYPE_CRASH}, {@link #TYPE_ANR}, or {@link #TYPE_BATTERY}.

View File

@ -256,7 +256,12 @@ public interface IActivityManager extends IInterface {
ApplicationErrorReport.CrashInfo crashInfo) throws RemoteException; ApplicationErrorReport.CrashInfo crashInfo) throws RemoteException;
public boolean handleApplicationWtf(IBinder app, String tag, public boolean handleApplicationWtf(IBinder app, String tag,
ApplicationErrorReport.CrashInfo crashInfo) throws RemoteException; 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; ApplicationErrorReport.CrashInfo crashInfo) throws RemoteException;
/* /*

View File

@ -23,6 +23,8 @@ import com.android.internal.os.RuntimeInit;
import dalvik.system.BlockGuard; import dalvik.system.BlockGuard;
import java.util.HashMap;
/** /**
* <p>StrictMode lets you impose stricter rules under which your * <p>StrictMode lets you impose stricter rules under which your
* application runs.</p> * application runs.</p>
@ -30,6 +32,12 @@ import dalvik.system.BlockGuard;
public final class StrictMode { public final class StrictMode {
private static final String TAG = "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() {} private StrictMode() {}
public static final int DISALLOW_DISK_WRITE = 0x01; 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. * @param policyMask a bitmask of DISALLOW_* and PENALTY_* values.
*/ */
public static void setThreadBlockingPolicy(final int policyMask) { public static void setThreadBlockingPolicy(final int policyMask) {
if (policyMask == 0) {
BlockGuard.setThreadPolicy(BlockGuard.LAX_POLICY);
return;
}
BlockGuard.Policy policy = BlockGuard.getThreadPolicy(); BlockGuard.Policy policy = BlockGuard.getThreadPolicy();
if (!(policy instanceof AndroidBlockGuardPolicy)) { if (!(policy instanceof AndroidBlockGuardPolicy)) {
BlockGuard.setThreadPolicy(new AndroidBlockGuardPolicy(policyMask)); BlockGuard.setThreadPolicy(new AndroidBlockGuardPolicy(policyMask));
@ -91,19 +103,13 @@ public final class StrictMode {
return BlockGuard.getThreadPolicy().getPolicyMask(); 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 static class AndroidBlockGuardPolicy implements BlockGuard.Policy {
private int mPolicyMask; 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) { public AndroidBlockGuardPolicy(final int policyMask) {
mPolicyMask = policyMask; mPolicyMask = policyMask;
@ -142,10 +148,6 @@ public final class StrictMode {
mPolicyMask = policyMask; mPolicyMask = policyMask;
} }
public void setDropBoxManager(DropBoxManager dropBoxManager) {
mDropBoxManager = dropBoxManager;
}
private void handleViolation(int violationBit) { private void handleViolation(int violationBit) {
final BlockGuard.BlockGuardPolicyException violation = final BlockGuard.BlockGuardPolicyException violation =
new BlockGuard.BlockGuardPolicyException(mPolicyMask, violationBit); new BlockGuard.BlockGuardPolicyException(mPolicyMask, violationBit);
@ -182,7 +184,23 @@ public final class StrictMode {
// the old policy here. // the old policy here.
int policy = violation.getPolicy(); 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) { if (durationMillis != -1) {
Log.d(TAG, "StrictMode policy violation; ~duration=" + durationMillis + " ms", Log.d(TAG, "StrictMode policy violation; ~duration=" + durationMillis + " ms",
violation); violation);
@ -191,24 +209,33 @@ public final class StrictMode {
} }
} }
if ((policy & PENALTY_DIALOG) != 0) { // The violationMask, passed to ActivityManager, is a
// Currently this is just used for the dialog. // 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 { try {
ActivityManagerNative.getDefault().handleApplicationStrictModeViolation( ActivityManagerNative.getDefault().handleApplicationStrictModeViolation(
RuntimeInit.getApplicationObject(), RuntimeInit.getApplicationObject(),
violationMask,
new ApplicationErrorReport.CrashInfo(violation)); new ApplicationErrorReport.CrashInfo(violation));
} catch (RemoteException e) { } 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) { if ((policy & PENALTY_DEATH) != 0) {
System.err.println("StrictMode policy violation with POLICY_DEATH; shutting down."); System.err.println("StrictMode policy violation with POLICY_DEATH; shutting down.");
Process.killProcess(Process.myPid()); Process.killProcess(Process.myPid());

View File

@ -97,6 +97,7 @@ import android.os.Process;
import android.os.RemoteCallbackList; import android.os.RemoteCallbackList;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.ServiceManager; import android.os.ServiceManager;
import android.os.StrictMode;
import android.os.SystemClock; import android.os.SystemClock;
import android.os.SystemProperties; import android.os.SystemProperties;
import android.provider.Settings; import android.provider.Settings;
@ -9354,11 +9355,17 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
} }
public void handleApplicationStrictModeViolation( public void handleApplicationStrictModeViolation(
IBinder app, ApplicationErrorReport.CrashInfo crashInfo) { IBinder app, int violationMask, ApplicationErrorReport.CrashInfo crashInfo) {
ProcessRecord r = findAppProcess(app); ProcessRecord r = findAppProcess(app);
// TODO: implement // TODO: implement
Log.w(TAG, "handleApplicationStrictModeViolation."); Log.w(TAG, "handleApplicationStrictModeViolation.");
if ((violationMask & StrictMode.PENALTY_DROPBOX) != 0) {
Integer crashFingerprint = crashInfo.stackTrace.hashCode();
Log.d(TAG, "supposed to drop box for fingerprint " + crashFingerprint);
}
if ((violationMask & StrictMode.PENALTY_DIALOG) != 0) {
AppErrorResult result = new AppErrorResult(); AppErrorResult result = new AppErrorResult();
synchronized (this) { synchronized (this) {
final long origId = Binder.clearCallingIdentity(); final long origId = Binder.clearCallingIdentity();
@ -9376,6 +9383,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
int res = result.get(); int res = result.get();
Log.w(TAG, "handleApplicationStrictModeViolation; res=" + res); Log.w(TAG, "handleApplicationStrictModeViolation; res=" + res);
} }
}
/** /**
* Used by {@link Log} via {@link com.android.internal.os.RuntimeInit} to report serious errors. * Used by {@link Log} via {@link com.android.internal.os.RuntimeInit} to report serious errors.

View File

@ -80,9 +80,6 @@ class AppErrorDialog extends BaseErrorDialog {
DISMISS_TIMEOUT); DISMISS_TIMEOUT);
} }
public void onStop() {
}
private final Handler mHandler = new Handler() { private final Handler mHandler = new Handler() {
public void handleMessage(Message msg) { public void handleMessage(Message msg) {
synchronized (mProc) { synchronized (mProc) {

View File

@ -81,9 +81,6 @@ class StrictModeViolationDialog extends BaseErrorDialog {
DISMISS_TIMEOUT); DISMISS_TIMEOUT);
} }
public void onStop() {
}
private final Handler mHandler = new Handler() { private final Handler mHandler = new Handler() {
public void handleMessage(Message msg) { public void handleMessage(Message msg) {
synchronized (mProc) { synchronized (mProc) {