Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9358bd39 authored by Brad Fitzpatrick's avatar Brad Fitzpatrick Committed by Android (Google) Code Review
Browse files

Merge "Fixes for StrictMode instance count checking." into honeycomb

parents e69e0fde 5f8b5c19
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -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;
    }
+4 −1
Original line number Diff line number Diff line
@@ -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;
    }

+70 −26
Original line number Diff line number Diff line
@@ -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,6 +1405,7 @@ public final class StrictMode {
     * @param policy the policy to put into place
     */
    public static void setVmPolicy(final VmPolicy policy) {
        synchronized (StrictMode.class) {
            sVmPolicy = policy;
            sVmPolicyMask = policy.mask;
            setCloseGuardEnabled(vmClosableObjectLeaksEnabled());
@@ -1410,7 +1413,6 @@ public final class StrictMode {
            Looper looper = Looper.getMainLooper();
            if (looper != null) {
                MessageQueue mq = looper.mQueue;
            synchronized (sProcessIdleHandler) {
                if (policy.classInstanceLimit.size() == 0) {
                    mq.removeIdleHandler(sProcessIdleHandler);
                } else if (!sIsIdlerRegistered) {
@@ -1425,8 +1427,10 @@ public final class StrictMode {
     * Gets the current VM policy.
     */
    public static VmPolicy getVmPolicy() {
        synchronized (StrictMode.class) {
            return sVmPolicy;
        }
    }

    /**
     * Enable the recommended StrictMode defaults, with violations just being logged.
@@ -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;