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: {
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();

View File

@ -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 |

View File

@ -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.
*/
@ -73,6 +72,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}.

View File

@ -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;
/*

View File

@ -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());

View File

@ -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,11 +9355,17 @@ 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.");
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();
synchronized (this) {
final long origId = Binder.clearCallingIdentity();
@ -9376,6 +9383,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
int res = result.get();
Log.w(TAG, "handleApplicationStrictModeViolation; res=" + res);
}
}
/**
* 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);
}
public void onStop() {
}
private final Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
synchronized (mProc) {

View File

@ -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) {