diff options
-rw-r--r-- | core/java/android/app/Activity.java | 1 | ||||
-rw-r--r-- | core/java/android/app/ActivityThread.java | 5 | ||||
-rw-r--r-- | core/java/android/os/StrictMode.java | 96 |
3 files changed, 74 insertions, 28 deletions
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 2aef860..22971a2 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 7cf60f9..2389f01 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 ae92b09..a53818e 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; |