Loading core/java/android/os/StrictMode.java +47 −16 Original line number Diff line number Diff line Loading @@ -84,6 +84,8 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Deque; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.concurrent.Executor; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.atomic.AtomicInteger; Loading Loading @@ -189,6 +191,9 @@ public final class StrictMode { // Only show an annoying dialog at most every 30 seconds private static final long MIN_DIALOG_INTERVAL_MS = 30000; // Only log a dropbox entry at most every 30 seconds private static final long MIN_DROPBOX_INTERVAL_MS = 3000; // How many Span tags (e.g. animations) to report. private static final int MAX_SPAN_TAGS = 20; Loading Loading @@ -1752,16 +1757,20 @@ public final class StrictMode { // Not perfect, but fast and good enough for dup suppression. Integer crashFingerprint = info.hashCode(); long lastViolationTime = 0; long now = SystemClock.uptimeMillis(); if (sLogger == LOGCAT_LOGGER) { // Don't throttle it if there is a non-default logger if (mLastViolationTime != null) { Long vtime = mLastViolationTime.get(crashFingerprint); if (vtime != null) { lastViolationTime = vtime; } clampViolationTimeMap(mLastViolationTime, Math.max(MIN_LOG_INTERVAL_MS, Math.max(MIN_DIALOG_INTERVAL_MS, MIN_DROPBOX_INTERVAL_MS))); } else { mLastViolationTime = new ArrayMap<>(1); } long now = SystemClock.uptimeMillis(); mLastViolationTime.put(crashFingerprint, now); } long timeSinceLastViolationMillis = lastViolationTime == 0 ? Long.MAX_VALUE : (now - lastViolationTime); Loading @@ -1780,7 +1789,8 @@ public final class StrictMode { penaltyMask |= PENALTY_DIALOG; } if (info.penaltyEnabled(PENALTY_DROPBOX) && lastViolationTime == 0) { if (info.penaltyEnabled(PENALTY_DROPBOX) && timeSinceLastViolationMillis > MIN_DROPBOX_INTERVAL_MS) { penaltyMask |= PENALTY_DROPBOX; } Loading Loading @@ -2215,6 +2225,23 @@ public final class StrictMode { @UnsupportedAppUsage private static final HashMap<Integer, Long> sLastVmViolationTime = new HashMap<>(); /** * Clamp the given map by removing elements with timestamp older than the given retainSince. */ private static void clampViolationTimeMap(final @NonNull Map<Integer, Long> violationTime, final long retainSince) { final Iterator<Map.Entry<Integer, Long>> iterator = violationTime.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry<Integer, Long> e = iterator.next(); if (e.getValue() < retainSince) { // Remove stale entries iterator.remove(); } } // Ideally we'd cap the total size of the map, though it'll involve quickselect of topK, // seems not worth it (saving some space immediately but they will be obsoleted soon anyway) } /** @hide */ public static void onVmPolicyViolation(Violation originStack) { onVmPolicyViolation(originStack, false); Loading @@ -2238,6 +2265,7 @@ public final class StrictMode { final long now = SystemClock.uptimeMillis(); long lastViolationTime; long timeSinceLastViolationMillis = Long.MAX_VALUE; if (sLogger == LOGCAT_LOGGER) { // Don't throttle it if there is a non-default logger synchronized (sLastVmViolationTime) { if (sLastVmViolationTime.containsKey(fingerprint)) { lastViolationTime = sLastVmViolationTime.get(fingerprint); Loading @@ -2246,6 +2274,9 @@ public final class StrictMode { if (timeSinceLastViolationMillis > MIN_VM_INTERVAL_MS) { sLastVmViolationTime.put(fingerprint, now); } clampViolationTimeMap(sLastVmViolationTime, now - Math.max(MIN_VM_INTERVAL_MS, MIN_LOG_INTERVAL_MS)); } } if (timeSinceLastViolationMillis <= MIN_VM_INTERVAL_MS) { // Rate limit all penalties. Loading core/java/android/os/strictmode/Violation.java +51 −0 Original line number Diff line number Diff line Loading @@ -18,7 +18,58 @@ package android.os.strictmode; /** Root class for all StrictMode violations. */ public abstract class Violation extends Throwable { private int mHashCode; private boolean mHashCodeValid; Violation(String message) { super(message); } @Override public int hashCode() { synchronized (this) { if (mHashCodeValid) { return mHashCode; } final String message = getMessage(); final Throwable cause = getCause(); int hashCode = message != null ? message.hashCode() : getClass().hashCode(); hashCode = hashCode * 37 + calcStackTraceHashCode(getStackTrace()); hashCode = hashCode * 37 + (cause != null ? cause.toString().hashCode() : 0); mHashCodeValid = true; return mHashCode = hashCode; } } @Override public synchronized Throwable initCause(Throwable cause) { mHashCodeValid = false; return super.initCause(cause); } @Override public void setStackTrace(StackTraceElement[] stackTrace) { super.setStackTrace(stackTrace); synchronized (this) { mHashCodeValid = false; } } @Override public synchronized Throwable fillInStackTrace() { mHashCodeValid = false; return super.fillInStackTrace(); } private static int calcStackTraceHashCode(final StackTraceElement[] stackTrace) { int hashCode = 17; if (stackTrace != null) { for (int i = 0; i < stackTrace.length; i++) { if (stackTrace[i] != null) { hashCode = hashCode * 37 + stackTrace[i].hashCode(); } } } return hashCode; } } Loading
core/java/android/os/StrictMode.java +47 −16 Original line number Diff line number Diff line Loading @@ -84,6 +84,8 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Deque; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.concurrent.Executor; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.atomic.AtomicInteger; Loading Loading @@ -189,6 +191,9 @@ public final class StrictMode { // Only show an annoying dialog at most every 30 seconds private static final long MIN_DIALOG_INTERVAL_MS = 30000; // Only log a dropbox entry at most every 30 seconds private static final long MIN_DROPBOX_INTERVAL_MS = 3000; // How many Span tags (e.g. animations) to report. private static final int MAX_SPAN_TAGS = 20; Loading Loading @@ -1752,16 +1757,20 @@ public final class StrictMode { // Not perfect, but fast and good enough for dup suppression. Integer crashFingerprint = info.hashCode(); long lastViolationTime = 0; long now = SystemClock.uptimeMillis(); if (sLogger == LOGCAT_LOGGER) { // Don't throttle it if there is a non-default logger if (mLastViolationTime != null) { Long vtime = mLastViolationTime.get(crashFingerprint); if (vtime != null) { lastViolationTime = vtime; } clampViolationTimeMap(mLastViolationTime, Math.max(MIN_LOG_INTERVAL_MS, Math.max(MIN_DIALOG_INTERVAL_MS, MIN_DROPBOX_INTERVAL_MS))); } else { mLastViolationTime = new ArrayMap<>(1); } long now = SystemClock.uptimeMillis(); mLastViolationTime.put(crashFingerprint, now); } long timeSinceLastViolationMillis = lastViolationTime == 0 ? Long.MAX_VALUE : (now - lastViolationTime); Loading @@ -1780,7 +1789,8 @@ public final class StrictMode { penaltyMask |= PENALTY_DIALOG; } if (info.penaltyEnabled(PENALTY_DROPBOX) && lastViolationTime == 0) { if (info.penaltyEnabled(PENALTY_DROPBOX) && timeSinceLastViolationMillis > MIN_DROPBOX_INTERVAL_MS) { penaltyMask |= PENALTY_DROPBOX; } Loading Loading @@ -2215,6 +2225,23 @@ public final class StrictMode { @UnsupportedAppUsage private static final HashMap<Integer, Long> sLastVmViolationTime = new HashMap<>(); /** * Clamp the given map by removing elements with timestamp older than the given retainSince. */ private static void clampViolationTimeMap(final @NonNull Map<Integer, Long> violationTime, final long retainSince) { final Iterator<Map.Entry<Integer, Long>> iterator = violationTime.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry<Integer, Long> e = iterator.next(); if (e.getValue() < retainSince) { // Remove stale entries iterator.remove(); } } // Ideally we'd cap the total size of the map, though it'll involve quickselect of topK, // seems not worth it (saving some space immediately but they will be obsoleted soon anyway) } /** @hide */ public static void onVmPolicyViolation(Violation originStack) { onVmPolicyViolation(originStack, false); Loading @@ -2238,6 +2265,7 @@ public final class StrictMode { final long now = SystemClock.uptimeMillis(); long lastViolationTime; long timeSinceLastViolationMillis = Long.MAX_VALUE; if (sLogger == LOGCAT_LOGGER) { // Don't throttle it if there is a non-default logger synchronized (sLastVmViolationTime) { if (sLastVmViolationTime.containsKey(fingerprint)) { lastViolationTime = sLastVmViolationTime.get(fingerprint); Loading @@ -2246,6 +2274,9 @@ public final class StrictMode { if (timeSinceLastViolationMillis > MIN_VM_INTERVAL_MS) { sLastVmViolationTime.put(fingerprint, now); } clampViolationTimeMap(sLastVmViolationTime, now - Math.max(MIN_VM_INTERVAL_MS, MIN_LOG_INTERVAL_MS)); } } if (timeSinceLastViolationMillis <= MIN_VM_INTERVAL_MS) { // Rate limit all penalties. Loading
core/java/android/os/strictmode/Violation.java +51 −0 Original line number Diff line number Diff line Loading @@ -18,7 +18,58 @@ package android.os.strictmode; /** Root class for all StrictMode violations. */ public abstract class Violation extends Throwable { private int mHashCode; private boolean mHashCodeValid; Violation(String message) { super(message); } @Override public int hashCode() { synchronized (this) { if (mHashCodeValid) { return mHashCode; } final String message = getMessage(); final Throwable cause = getCause(); int hashCode = message != null ? message.hashCode() : getClass().hashCode(); hashCode = hashCode * 37 + calcStackTraceHashCode(getStackTrace()); hashCode = hashCode * 37 + (cause != null ? cause.toString().hashCode() : 0); mHashCodeValid = true; return mHashCode = hashCode; } } @Override public synchronized Throwable initCause(Throwable cause) { mHashCodeValid = false; return super.initCause(cause); } @Override public void setStackTrace(StackTraceElement[] stackTrace) { super.setStackTrace(stackTrace); synchronized (this) { mHashCodeValid = false; } } @Override public synchronized Throwable fillInStackTrace() { mHashCodeValid = false; return super.fillInStackTrace(); } private static int calcStackTraceHashCode(final StackTraceElement[] stackTrace) { int hashCode = 17; if (stackTrace != null) { for (int i = 0; i < stackTrace.length; i++) { if (stackTrace[i] != null) { hashCode = hashCode * 37 + stackTrace[i].hashCode(); } } } return hashCode; } }