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

Commit 75803575 authored by Brad Fitzpatrick's avatar Brad Fitzpatrick
Browse files

StrictMode class instance limit interface.

Change-Id: Ic5eea539586e5d4965d83364bf9f623d1d89f2b1
parent 48395385
Loading
Loading
Loading
Loading
+25 −0
Original line number Diff line number Diff line
@@ -146691,6 +146691,16 @@
 visibility="public"
>
</constructor>
<constructor name="StrictMode.VmPolicy.Builder"
 type="android.os.StrictMode.VmPolicy.Builder"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="base" type="android.os.StrictMode.VmPolicy">
</parameter>
</constructor>
<method name="build"
 return="android.os.StrictMode.VmPolicy"
 abstract="false"
@@ -146768,6 +146778,21 @@
 visibility="public"
>
</method>
<method name="setClassInstanceLimit"
 return="android.os.StrictMode.VmPolicy.Builder"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="klass" type="java.lang.Class">
</parameter>
<parameter name="instanceLimit" type="int">
</parameter>
</method>
</class>
<class name="SystemClock"
 extends="java.lang.Object"
+2 −0
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ import android.os.IBinder;
import android.os.Looper;
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.StrictMode;
import android.text.Selection;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
@@ -858,6 +859,7 @@ public class Activity extends ContextThemeWrapper
            mFragments.restoreAllState(p, mLastNonConfigurationInstances != null
                    ? mLastNonConfigurationInstances.fragments : null);
        }
        StrictMode.noteActivityClass(this.getClass());
        mFragments.dispatchCreate();
        mCalled = true;
    }
+90 −10
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ import dalvik.system.CloseGuard;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.concurrent.atomic.AtomicInteger;

@@ -166,13 +167,19 @@ public final class StrictMode {
     * Note, a "VM_" bit, not thread.
     * @hide
     */
    public static final int DETECT_VM_CURSOR_LEAKS = 0x200;  // for ProcessPolicy
    public static final int DETECT_VM_CURSOR_LEAKS = 0x200;  // for VmPolicy

    /**
     * Note, a "VM_" bit, not thread.
     * @hide
     */
    public static final int DETECT_VM_CLOSABLE_LEAKS = 0x400;  // for ProcessPolicy
    public static final int DETECT_VM_CLOSABLE_LEAKS = 0x400;  // for VmPolicy

    /**
     * Note, a "VM_" bit, not thread.
     * @hide
     */
    public static final int DETECT_VM_ACTIVITY_LEAKS = 0x800;  // for VmPolicy

    /**
     * @hide
@@ -232,10 +239,18 @@ public final class StrictMode {
            PENALTY_LOG | PENALTY_DIALOG | PENALTY_DEATH | PENALTY_DROPBOX | PENALTY_GATHER |
            PENALTY_DEATH_ON_NETWORK | PENALTY_FLASH;


    // TODO: wrap in some ImmutableHashMap thing.
    // Note: must be before static initialization of sVmPolicy.
    private static final HashMap<Class, Integer> EMPTY_CLASS_LIMIT_MAP = new HashMap<Class, Integer>();

    /**
     * The current VmPolicy in effect.
     *
     * TODO: these are redundant (mask is in VmPolicy).  Should remove sVmPolicyMask.
     */
    private static volatile int sVmPolicyMask = 0;
    private static volatile VmPolicy sVmPolicy = VmPolicy.LAX;

    /**
     * The number of threads trying to do an async dropbox write.
@@ -481,12 +496,19 @@ public final class StrictMode {
        /**
         * The default, lax policy which doesn't catch anything.
         */
        public static final VmPolicy LAX = new VmPolicy(0);
        public static final VmPolicy LAX = new VmPolicy(0, EMPTY_CLASS_LIMIT_MAP);

        final int mask;

        private VmPolicy(int mask) {
        // Map from class to max number of allowed instances in memory.
        final HashMap<Class, Integer> classInstanceLimit;

        private VmPolicy(int mask, HashMap<Class, Integer> classInstanceLimit) {
            if (classInstanceLimit == null) {
                throw new NullPointerException("classInstanceLimit == null");
            }
            this.mask = mask;
            this.classInstanceLimit = classInstanceLimit;
        }

        @Override
@@ -516,6 +538,49 @@ public final class StrictMode {
        public static final class Builder {
            private int mMask;

            private HashMap<Class, Integer> mClassInstanceLimit;  // null until needed
            private boolean mClassInstanceLimitNeedCow = false;  // need copy-on-write

            public Builder() {
                mMask = 0;
            }

            /**
             * Build upon an existing VmPolicy.
             */
            public Builder(VmPolicy base) {
                mMask = base.mask;
                mClassInstanceLimitNeedCow = true;
                mClassInstanceLimit = base.classInstanceLimit;
            }

            /**
             * Set an upper bound on how many instances of a class can be in memory
             * at once.  Helps to prevent object leaks.
             */
            public Builder setClassInstanceLimit(Class klass, int instanceLimit) {
                if (klass == null) {
                    throw new NullPointerException("klass == null");
                }
                if (mClassInstanceLimitNeedCow) {
                    if (mClassInstanceLimit.containsKey(klass) &&
                        mClassInstanceLimit.get(klass) == instanceLimit) {
                        // no-op; don't break COW
                        return this;
                    }
                    mClassInstanceLimitNeedCow = false;
                    mClassInstanceLimit = (HashMap<Class, Integer>) mClassInstanceLimit.clone();
                } else if (mClassInstanceLimit == null) {
                    mClassInstanceLimit = new HashMap<Class, Integer>();
                }
                mClassInstanceLimit.put(klass, instanceLimit);
                return this;
            }

            private Builder detectActivityLeaks() {
                return enable(DETECT_VM_ACTIVITY_LEAKS);
            }

            /**
             * Detect everything that's potentially suspect.
             *
@@ -524,7 +589,8 @@ public final class StrictMode {
             * likely expand in future releases.
             */
            public Builder detectAll() {
                return enable(DETECT_VM_CURSOR_LEAKS | DETECT_VM_CLOSABLE_LEAKS);
                return enable(DETECT_VM_ACTIVITY_LEAKS |
                        DETECT_VM_CURSOR_LEAKS | DETECT_VM_CLOSABLE_LEAKS);
            }

            /**
@@ -598,7 +664,8 @@ public final class StrictMode {
                              PENALTY_DROPBOX | PENALTY_DIALOG)) == 0) {
                    penaltyLog();
                }
                return new VmPolicy(mMask);
                return new VmPolicy(mMask,
                        mClassInstanceLimit != null ? mClassInstanceLimit : EMPTY_CLASS_LIMIT_MAP);
            }
        }
    }
@@ -829,9 +896,7 @@ public final class StrictMode {
        if (IS_USER_BUILD) {
            setCloseGuardEnabled(false);
        } else {
            sVmPolicyMask = StrictMode.DETECT_VM_CURSOR_LEAKS |
                    StrictMode.DETECT_VM_CLOSABLE_LEAKS |
                    StrictMode.PENALTY_DROPBOX;
            setVmPolicy(new VmPolicy.Builder().detectAll().penaltyDropBox().build());
            setCloseGuardEnabled(vmClosableObjectLeaksEnabled());
        }
        return true;
@@ -1289,6 +1354,7 @@ 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());
    }
@@ -1297,7 +1363,7 @@ public final class StrictMode {
     * Gets the current VM policy.
     */
    public static VmPolicy getVmPolicy() {
        return new VmPolicy(sVmPolicyMask);
        return sVmPolicy;
    }

    /**
@@ -1651,6 +1717,20 @@ public final class StrictMode {
        ((AndroidBlockGuardPolicy) policy).onWriteToDisk();
    }

    /**
     * @hide
     */
    public static void noteActivityClass(Class klass) {
        if ((sVmPolicy.mask & DETECT_VM_ACTIVITY_LEAKS) == 0) {
            return;
        }
        if (sVmPolicy.classInstanceLimit.containsKey(klass)) {
            return;
        }
        // Note: capping at 2, not 1, to give some breathing room.
        setVmPolicy(new VmPolicy.Builder(sVmPolicy).setClassInstanceLimit(klass, 2).build());
    }

    /**
     * Parcelable that gets sent in Binder call headers back to callers
     * to report violations that happened during a cross-process call.