diff options
8 files changed, 90 insertions, 50 deletions
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index b4c7edc71ba9..2c1f2dafc027 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 49f1a8f92018..0ce790e4fe07 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 f0cef98751af..57a23aeb8914 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 ca09290125e3..542bc411acc3 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 876ec3956d6c..c0ae263d7c2c 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 0946ba27cc1a..e93f7ff2c669 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 3a1aad67c88a..a769c05c1648 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 f4329e2d09ab..fe76d18c7279 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) {  |