Merge "More StrictMode work, handling violations in ActivityManagerService." into gingerbread
This commit is contained in:
committed by
Android (Google) Code Review
commit
94f14aeca9
@ -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();
|
||||||
|
@ -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 |
|
||||||
|
@ -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}.
|
||||||
|
@ -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;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -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());
|
||||||
|
@ -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.
|
||||||
|
@ -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) {
|
||||||
|
@ -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) {
|
||||||
|
Reference in New Issue
Block a user