am 9358bd39: Merge "Fixes for StrictMode instance count checking." into honeycomb
* commit '9358bd39dc8829ef8413294da70d44cd928ca878': Fixes for StrictMode instance count checking.
This commit is contained in:
@@ -859,7 +859,6 @@ public class Activity extends ContextThemeWrapper
|
|||||||
mFragments.restoreAllState(p, mLastNonConfigurationInstances != null
|
mFragments.restoreAllState(p, mLastNonConfigurationInstances != null
|
||||||
? mLastNonConfigurationInstances.fragments : null);
|
? mLastNonConfigurationInstances.fragments : null);
|
||||||
}
|
}
|
||||||
StrictMode.noteActivityClass(this.getClass());
|
|
||||||
mFragments.dispatchCreate();
|
mFragments.dispatchCreate();
|
||||||
mCalled = true;
|
mCalled = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1631,6 +1631,7 @@ public final class ActivityThread {
|
|||||||
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
|
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
|
||||||
activity = mInstrumentation.newActivity(
|
activity = mInstrumentation.newActivity(
|
||||||
cl, component.getClassName(), r.intent);
|
cl, component.getClassName(), r.intent);
|
||||||
|
StrictMode.incrementExpectedActivityCount(activity.getClass());
|
||||||
r.intent.setExtrasClassLoader(cl);
|
r.intent.setExtrasClassLoader(cl);
|
||||||
if (r.state != null) {
|
if (r.state != null) {
|
||||||
r.state.setClassLoader(cl);
|
r.state.setClassLoader(cl);
|
||||||
@@ -2712,8 +2713,10 @@ public final class ActivityThread {
|
|||||||
private final ActivityClientRecord performDestroyActivity(IBinder token, boolean finishing,
|
private final ActivityClientRecord performDestroyActivity(IBinder token, boolean finishing,
|
||||||
int configChanges, boolean getNonConfigInstance) {
|
int configChanges, boolean getNonConfigInstance) {
|
||||||
ActivityClientRecord r = mActivities.get(token);
|
ActivityClientRecord r = mActivities.get(token);
|
||||||
|
Class activityClass = null;
|
||||||
if (localLOGV) Slog.v(TAG, "Performing finish of " + r);
|
if (localLOGV) Slog.v(TAG, "Performing finish of " + r);
|
||||||
if (r != null) {
|
if (r != null) {
|
||||||
|
activityClass = r.activity.getClass();
|
||||||
r.activity.mConfigChangeFlags |= configChanges;
|
r.activity.mConfigChangeFlags |= configChanges;
|
||||||
if (finishing) {
|
if (finishing) {
|
||||||
r.activity.mFinished = true;
|
r.activity.mFinished = true;
|
||||||
@@ -2791,7 +2794,7 @@ public final class ActivityThread {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
mActivities.remove(token);
|
mActivities.remove(token);
|
||||||
|
StrictMode.decrementExpectedActivityCount(activityClass);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ import java.io.StringWriter;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1370,8 +1371,9 @@ public final class StrictMode {
|
|||||||
}
|
}
|
||||||
Runtime.getRuntime().gc();
|
Runtime.getRuntime().gc();
|
||||||
// Note: classInstanceLimit is immutable, so this is lock-free
|
// Note: classInstanceLimit is immutable, so this is lock-free
|
||||||
for (Class klass : policy.classInstanceLimit.keySet()) {
|
for (Map.Entry<Class, Integer> entry : policy.classInstanceLimit.entrySet()) {
|
||||||
int limit = policy.classInstanceLimit.get(klass);
|
Class klass = entry.getKey();
|
||||||
|
int limit = entry.getValue();
|
||||||
long instances = VMDebug.countInstancesOfClass(klass, false);
|
long instances = VMDebug.countInstancesOfClass(klass, false);
|
||||||
if (instances <= limit) {
|
if (instances <= limit) {
|
||||||
continue;
|
continue;
|
||||||
@@ -1382,7 +1384,7 @@ public final class StrictMode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static long sLastInstanceCountCheckMillis = 0;
|
private static long sLastInstanceCountCheckMillis = 0;
|
||||||
private static boolean sIsIdlerRegistered = false; // guarded by sProcessIdleHandler
|
private static boolean sIsIdlerRegistered = false; // guarded by StrictMode.class
|
||||||
private static final MessageQueue.IdleHandler sProcessIdleHandler =
|
private static final MessageQueue.IdleHandler sProcessIdleHandler =
|
||||||
new MessageQueue.IdleHandler() {
|
new MessageQueue.IdleHandler() {
|
||||||
public boolean queueIdle() {
|
public boolean queueIdle() {
|
||||||
@@ -1403,14 +1405,14 @@ public final class StrictMode {
|
|||||||
* @param policy the policy to put into place
|
* @param policy the policy to put into place
|
||||||
*/
|
*/
|
||||||
public static void setVmPolicy(final VmPolicy policy) {
|
public static void setVmPolicy(final VmPolicy policy) {
|
||||||
sVmPolicy = policy;
|
synchronized (StrictMode.class) {
|
||||||
sVmPolicyMask = policy.mask;
|
sVmPolicy = policy;
|
||||||
setCloseGuardEnabled(vmClosableObjectLeaksEnabled());
|
sVmPolicyMask = policy.mask;
|
||||||
|
setCloseGuardEnabled(vmClosableObjectLeaksEnabled());
|
||||||
|
|
||||||
Looper looper = Looper.getMainLooper();
|
Looper looper = Looper.getMainLooper();
|
||||||
if (looper != null) {
|
if (looper != null) {
|
||||||
MessageQueue mq = looper.mQueue;
|
MessageQueue mq = looper.mQueue;
|
||||||
synchronized (sProcessIdleHandler) {
|
|
||||||
if (policy.classInstanceLimit.size() == 0) {
|
if (policy.classInstanceLimit.size() == 0) {
|
||||||
mq.removeIdleHandler(sProcessIdleHandler);
|
mq.removeIdleHandler(sProcessIdleHandler);
|
||||||
} else if (!sIsIdlerRegistered) {
|
} else if (!sIsIdlerRegistered) {
|
||||||
@@ -1425,7 +1427,9 @@ public final class StrictMode {
|
|||||||
* Gets the current VM policy.
|
* Gets the current VM policy.
|
||||||
*/
|
*/
|
||||||
public static VmPolicy getVmPolicy() {
|
public static VmPolicy getVmPolicy() {
|
||||||
return sVmPolicy;
|
synchronized (StrictMode.class) {
|
||||||
|
return sVmPolicy;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1480,6 +1484,11 @@ public final class StrictMode {
|
|||||||
final boolean penaltyLog = (sVmPolicyMask & PENALTY_LOG) != 0;
|
final boolean penaltyLog = (sVmPolicyMask & PENALTY_LOG) != 0;
|
||||||
final ViolationInfo info = new ViolationInfo(originStack, sVmPolicyMask);
|
final ViolationInfo info = new ViolationInfo(originStack, sVmPolicyMask);
|
||||||
|
|
||||||
|
// Erase stuff not relevant for process-wide violations
|
||||||
|
info.numAnimationsRunning = 0;
|
||||||
|
info.tags = null;
|
||||||
|
info.broadcastIntentAction = null;
|
||||||
|
|
||||||
final Integer fingerprint = info.hashCode();
|
final Integer fingerprint = info.hashCode();
|
||||||
final long now = SystemClock.uptimeMillis();
|
final long now = SystemClock.uptimeMillis();
|
||||||
long lastViolationTime = 0;
|
long lastViolationTime = 0;
|
||||||
@@ -1494,8 +1503,6 @@ public final class StrictMode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.d(TAG, "Time since last vm violation: " + timeSinceLastViolationMillis);
|
|
||||||
|
|
||||||
if (penaltyLog && timeSinceLastViolationMillis > MIN_LOG_INTERVAL_MS) {
|
if (penaltyLog && timeSinceLastViolationMillis > MIN_LOG_INTERVAL_MS) {
|
||||||
Log.e(TAG, message, originStack);
|
Log.e(TAG, message, originStack);
|
||||||
}
|
}
|
||||||
@@ -1799,18 +1806,57 @@ public final class StrictMode {
|
|||||||
((AndroidBlockGuardPolicy) policy).onWriteToDisk();
|
((AndroidBlockGuardPolicy) policy).onWriteToDisk();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Guarded by StrictMode.class
|
||||||
|
private static final HashMap<Class, Integer> sExpectedActivityInstanceCount =
|
||||||
|
new HashMap<Class, Integer>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
public static void noteActivityClass(Class klass) {
|
public static void incrementExpectedActivityCount(Class klass) {
|
||||||
if ((sVmPolicy.mask & DETECT_VM_ACTIVITY_LEAKS) == 0) {
|
if (klass == null || (sVmPolicy.mask & DETECT_VM_ACTIVITY_LEAKS) == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (sVmPolicy.classInstanceLimit.containsKey(klass)) {
|
synchronized (StrictMode.class) {
|
||||||
|
Integer expected = sExpectedActivityInstanceCount.get(klass);
|
||||||
|
Integer newExpected = expected == null ? 1 : expected + 1;
|
||||||
|
sExpectedActivityInstanceCount.put(klass, newExpected);
|
||||||
|
// Note: adding 1 here to give some breathing room during
|
||||||
|
// orientation changes. (shouldn't be necessary, though?)
|
||||||
|
setExpectedClassInstanceCount(klass, newExpected + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public static void decrementExpectedActivityCount(Class klass) {
|
||||||
|
if (klass == null || (sVmPolicy.mask & DETECT_VM_ACTIVITY_LEAKS) == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Note: capping at 2, not 1, to give some breathing room.
|
synchronized (StrictMode.class) {
|
||||||
setVmPolicy(new VmPolicy.Builder(sVmPolicy).setClassInstanceLimit(klass, 2).build());
|
Integer expected = sExpectedActivityInstanceCount.get(klass);
|
||||||
|
Integer newExpected = (expected == null || expected == 0) ? 0 : expected - 1;
|
||||||
|
if (newExpected == 0) {
|
||||||
|
sExpectedActivityInstanceCount.remove(klass);
|
||||||
|
} else {
|
||||||
|
sExpectedActivityInstanceCount.put(klass, newExpected);
|
||||||
|
}
|
||||||
|
// Note: adding 1 here to give some breathing room during
|
||||||
|
// orientation changes. (shouldn't be necessary, though?)
|
||||||
|
setExpectedClassInstanceCount(klass, newExpected + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public static void setExpectedClassInstanceCount(Class klass, int count) {
|
||||||
|
synchronized (StrictMode.class) {
|
||||||
|
setVmPolicy(new VmPolicy.Builder(sVmPolicy)
|
||||||
|
.setClassInstanceLimit(klass, count)
|
||||||
|
.build());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -2020,15 +2066,13 @@ public final class StrictMode {
|
|||||||
final long mInstances;
|
final long mInstances;
|
||||||
final int mLimit;
|
final int mLimit;
|
||||||
|
|
||||||
private static final StackTraceElement[] FAKE_STACK = new StackTraceElement[1];
|
private static final StackTraceElement[] FAKE_STACK = {
|
||||||
static {
|
new StackTraceElement("android.os.StrictMode", "setClassInstanceLimit",
|
||||||
FAKE_STACK[0] = new StackTraceElement("android.os.StrictMode", "setClassInstanceLimit",
|
"StrictMode.java", 1)
|
||||||
"StrictMode.java", 1);
|
};
|
||||||
}
|
|
||||||
|
|
||||||
public InstanceCountViolation(Class klass, long instances, int limit) {
|
public InstanceCountViolation(Class klass, long instances, int limit) {
|
||||||
// Note: now including instances here, otherwise signatures would all be different.
|
super(klass.toString() + "; instances=" + instances + "; limit=" + limit);
|
||||||
super(klass.toString() + "; limit=" + limit);
|
|
||||||
setStackTrace(FAKE_STACK);
|
setStackTrace(FAKE_STACK);
|
||||||
mClass = klass;
|
mClass = klass;
|
||||||
mInstances = instances;
|
mInstances = instances;
|
||||||
|
|||||||
Reference in New Issue
Block a user