summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Brad Fitzpatrick <bradfitz@android.com> 2011-01-20 15:12:08 -0800
committer Brad Fitzpatrick <bradfitz@android.com> 2011-01-20 15:12:08 -0800
commit5f8b5c191cae77f536ee64f0b625e4a7f8596787 (patch)
treefa6b2df76244e2cd54f9e10d84b1007de2e14cbc
parent9c91c7e27fbfff5abc34e19779a9477239ab9b10 (diff)
Fixes for StrictMode instance count checking.
Misc stuff found after looking at the first day of data, Jesse's review, and comments from Dianne about tracking Activity counts better. Change-Id: Ifee1ef8f59f41061d4aac8c02765627dbf3cd8e4
-rw-r--r--core/java/android/app/Activity.java1
-rw-r--r--core/java/android/app/ActivityThread.java5
-rw-r--r--core/java/android/os/StrictMode.java96
3 files changed, 74 insertions, 28 deletions
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 2aef860a62b0..22971a24beeb 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -859,7 +859,6 @@ public class Activity extends ContextThemeWrapper
mFragments.restoreAllState(p, mLastNonConfigurationInstances != null
? mLastNonConfigurationInstances.fragments : null);
}
- StrictMode.noteActivityClass(this.getClass());
mFragments.dispatchCreate();
mCalled = true;
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 7cf60f99efbd..2389f01cd54f 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -1616,6 +1616,7 @@ public final class ActivityThread {
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
+ StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
if (r.state != null) {
r.state.setClassLoader(cl);
@@ -2686,8 +2687,10 @@ public final class ActivityThread {
private final ActivityClientRecord performDestroyActivity(IBinder token, boolean finishing,
int configChanges, boolean getNonConfigInstance) {
ActivityClientRecord r = mActivities.get(token);
+ Class activityClass = null;
if (localLOGV) Slog.v(TAG, "Performing finish of " + r);
if (r != null) {
+ activityClass = r.activity.getClass();
r.activity.mConfigChangeFlags |= configChanges;
if (finishing) {
r.activity.mFinished = true;
@@ -2765,7 +2768,7 @@ public final class ActivityThread {
}
}
mActivities.remove(token);
-
+ StrictMode.decrementExpectedActivityCount(activityClass);
return r;
}
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index ae92b09ed484..a53818efca1a 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -37,6 +37,7 @@ import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
+import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
/**
@@ -1370,8 +1371,9 @@ public final class StrictMode {
}
Runtime.getRuntime().gc();
// Note: classInstanceLimit is immutable, so this is lock-free
- for (Class klass : policy.classInstanceLimit.keySet()) {
- int limit = policy.classInstanceLimit.get(klass);
+ for (Map.Entry<Class, Integer> entry : policy.classInstanceLimit.entrySet()) {
+ Class klass = entry.getKey();
+ int limit = entry.getValue();
long instances = VMDebug.countInstancesOfClass(klass, false);
if (instances <= limit) {
continue;
@@ -1382,7 +1384,7 @@ public final class StrictMode {
}
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 =
new MessageQueue.IdleHandler() {
public boolean queueIdle() {
@@ -1403,14 +1405,14 @@ public final class StrictMode {
* @param policy the policy to put into place
*/
public static void setVmPolicy(final VmPolicy policy) {
- sVmPolicy = policy;
- sVmPolicyMask = policy.mask;
- setCloseGuardEnabled(vmClosableObjectLeaksEnabled());
-
- Looper looper = Looper.getMainLooper();
- if (looper != null) {
- MessageQueue mq = looper.mQueue;
- synchronized (sProcessIdleHandler) {
+ synchronized (StrictMode.class) {
+ sVmPolicy = policy;
+ sVmPolicyMask = policy.mask;
+ setCloseGuardEnabled(vmClosableObjectLeaksEnabled());
+
+ Looper looper = Looper.getMainLooper();
+ if (looper != null) {
+ MessageQueue mq = looper.mQueue;
if (policy.classInstanceLimit.size() == 0) {
mq.removeIdleHandler(sProcessIdleHandler);
} else if (!sIsIdlerRegistered) {
@@ -1425,7 +1427,9 @@ public final class StrictMode {
* Gets the current VM policy.
*/
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 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 long now = SystemClock.uptimeMillis();
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) {
Log.e(TAG, message, originStack);
}
@@ -1799,18 +1806,57 @@ public final class StrictMode {
((AndroidBlockGuardPolicy) policy).onWriteToDisk();
}
+ // Guarded by StrictMode.class
+ private static final HashMap<Class, Integer> sExpectedActivityInstanceCount =
+ new HashMap<Class, Integer>();
+
/**
* @hide
*/
- public static void noteActivityClass(Class klass) {
- if ((sVmPolicy.mask & DETECT_VM_ACTIVITY_LEAKS) == 0) {
+ public static void incrementExpectedActivityCount(Class klass) {
+ if (klass == null || (sVmPolicy.mask & DETECT_VM_ACTIVITY_LEAKS) == 0) {
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;
}
- // Note: capping at 2, not 1, to give some breathing room.
- setVmPolicy(new VmPolicy.Builder(sVmPolicy).setClassInstanceLimit(klass, 2).build());
+ synchronized (StrictMode.class) {
+ 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 int mLimit;
- private static final StackTraceElement[] FAKE_STACK = new StackTraceElement[1];
- static {
- FAKE_STACK[0] = new StackTraceElement("android.os.StrictMode", "setClassInstanceLimit",
- "StrictMode.java", 1);
- }
+ private static final StackTraceElement[] FAKE_STACK = {
+ new StackTraceElement("android.os.StrictMode", "setClassInstanceLimit",
+ "StrictMode.java", 1)
+ };
public InstanceCountViolation(Class klass, long instances, int limit) {
- // Note: now including instances here, otherwise signatures would all be different.
- super(klass.toString() + "; limit=" + limit);
+ super(klass.toString() + "; instances=" + instances + "; limit=" + limit);
setStackTrace(FAKE_STACK);
mClass = klass;
mInstances = instances;