Loading api/current.xml +11 −0 Original line number Diff line number Diff line Loading @@ -146705,6 +146705,17 @@ visibility="public" > </method> <method name="detectActivityLeaks" return="android.os.StrictMode.VmPolicy.Builder" abstract="false" native="false" synchronized="false" static="false" final="false" deprecated="not deprecated" visibility="public" > </method> <method name="detectAll" return="android.os.StrictMode.VmPolicy.Builder" abstract="false" core/java/android/app/Activity.java +3 −0 Original line number Diff line number Diff line Loading @@ -4433,6 +4433,9 @@ public class Activity extends ContextThemeWrapper mStopped = true; } mResumed = false; // Check for Activity leaks, if enabled. StrictMode.conditionallyCheckInstanceCounts(); } final void performDestroy() { Loading core/java/android/os/StrictMode.java +131 −10 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import com.android.internal.os.RuntimeInit; import dalvik.system.BlockGuard; import dalvik.system.CloseGuard; import dalvik.system.VMDebug; import java.io.PrintWriter; import java.io.StringWriter; Loading Loading @@ -181,6 +182,15 @@ public final class StrictMode { */ public static final int DETECT_VM_ACTIVITY_LEAKS = 0x800; // for VmPolicy /** * @hide */ private static final int DETECT_VM_INSTANCE_LEAKS = 0x1000; // for VmPolicy private static final int ALL_VM_DETECT_BITS = DETECT_VM_CURSOR_LEAKS | DETECT_VM_CLOSABLE_LEAKS | DETECT_VM_ACTIVITY_LEAKS | DETECT_VM_INSTANCE_LEAKS; /** * @hide */ Loading Loading @@ -573,11 +583,15 @@ public final class StrictMode { } else if (mClassInstanceLimit == null) { mClassInstanceLimit = new HashMap<Class, Integer>(); } mMask |= DETECT_VM_INSTANCE_LEAKS; mClassInstanceLimit.put(klass, instanceLimit); return this; } private Builder detectActivityLeaks() { /** * Detect leaks of {@link android.app.Activity} subclasses. */ public Builder detectActivityLeaks() { return enable(DETECT_VM_ACTIVITY_LEAKS); } Loading @@ -585,8 +599,8 @@ public final class StrictMode { * Detect everything that's potentially suspect. * * <p>In the Honeycomb release this includes leaks of * SQLite cursors and other closable objects but will * likely expand in future releases. * SQLite cursors, Activities, and other closable objects * but will likely expand in future releases. */ public Builder detectAll() { return enable(DETECT_VM_ACTIVITY_LEAKS | Loading Loading @@ -1346,6 +1360,41 @@ public final class StrictMode { gatheredViolations.set(null); } /** * @hide */ public static void conditionallyCheckInstanceCounts() { VmPolicy policy = getVmPolicy(); if (policy.classInstanceLimit.size() == 0) { return; } Runtime.getRuntime().gc(); // Note: classInstanceLimit is immutable, so this is lock-free for (Class klass : policy.classInstanceLimit.keySet()) { int limit = policy.classInstanceLimit.get(klass); long instances = VMDebug.countInstancesOfClass(klass, false); if (instances <= limit) { continue; } Throwable tr = new InstanceCountViolation(klass, instances, limit); onVmPolicyViolation(tr.getMessage(), tr); } } private static long sLastInstanceCountCheckMillis = 0; private static boolean sIsIdlerRegistered = false; // guarded by sProcessIdleHandler private static final MessageQueue.IdleHandler sProcessIdleHandler = new MessageQueue.IdleHandler() { public boolean queueIdle() { long now = SystemClock.uptimeMillis(); if (now - sLastInstanceCountCheckMillis > 30 * 1000) { sLastInstanceCountCheckMillis = now; conditionallyCheckInstanceCounts(); } return true; } }; /** * Sets the policy for what actions in the VM process (on any * thread) should be detected, as well as the penalty if such Loading @@ -1357,6 +1406,19 @@ public final class StrictMode { sVmPolicy = policy; sVmPolicyMask = policy.mask; setCloseGuardEnabled(vmClosableObjectLeaksEnabled()); Looper looper = Looper.getMainLooper(); if (looper != null) { MessageQueue mq = looper.mQueue; synchronized (sProcessIdleHandler) { if (policy.classInstanceLimit.size() == 0) { mq.removeIdleHandler(sProcessIdleHandler); } else if (!sIsIdlerRegistered) { mq.addIdleHandler(sProcessIdleHandler); sIsIdlerRegistered = true; } } } } /** Loading Loading @@ -1406,19 +1468,39 @@ public final class StrictMode { onVmPolicyViolation(message, originStack); } // Map from VM violation fingerprint to uptime millis. private static final HashMap<Integer, Long> sLastVmViolationTime = new HashMap<Integer, Long>(); /** * @hide */ public static void onVmPolicyViolation(String message, Throwable originStack) { if ((sVmPolicyMask & PENALTY_LOG) != 0) { Log.e(TAG, message, originStack); final boolean penaltyDropbox = (sVmPolicyMask & PENALTY_DROPBOX) != 0; final boolean penaltyDeath = (sVmPolicyMask & PENALTY_DEATH) != 0; final boolean penaltyLog = (sVmPolicyMask & PENALTY_LOG) != 0; final ViolationInfo info = new ViolationInfo(originStack, sVmPolicyMask); final Integer fingerprint = info.hashCode(); final long now = SystemClock.uptimeMillis(); long lastViolationTime = 0; long timeSinceLastViolationMillis = Long.MAX_VALUE; synchronized (sLastVmViolationTime) { if (sLastVmViolationTime.containsKey(fingerprint)) { lastViolationTime = sLastVmViolationTime.get(fingerprint); timeSinceLastViolationMillis = now - lastViolationTime; } if (timeSinceLastViolationMillis > MIN_LOG_INTERVAL_MS) { sLastVmViolationTime.put(fingerprint, now); } } boolean penaltyDropbox = (sVmPolicyMask & PENALTY_DROPBOX) != 0; boolean penaltyDeath = (sVmPolicyMask & PENALTY_DEATH) != 0; Log.d(TAG, "Time since last vm violation: " + timeSinceLastViolationMillis); if (penaltyLog && timeSinceLastViolationMillis > MIN_LOG_INTERVAL_MS) { Log.e(TAG, message, originStack); } int violationMaskSubset = PENALTY_DROPBOX | DETECT_VM_CURSOR_LEAKS; ViolationInfo info = new ViolationInfo(originStack, sVmPolicyMask); int violationMaskSubset = PENALTY_DROPBOX | (ALL_VM_DETECT_BITS & sVmPolicyMask); if (penaltyDropbox && !penaltyDeath) { // Common case for userdebug/eng builds. If no death and Loading @@ -1428,7 +1510,7 @@ public final class StrictMode { return; } if (penaltyDropbox) { if (penaltyDropbox && lastViolationTime == 0) { // The violationMask, passed to ActivityManager, is a // subset of the original StrictMode policy bitmask, with // only the bit violated and penalty bits to be executed Loading Loading @@ -1785,6 +1867,12 @@ public final class StrictMode { */ public String broadcastIntentAction; /** * If this is a instance count violation, the number of instances in memory, * else -1. */ public long numInstances = -1; /** * Create an uninitialized instance of ViolationInfo */ Loading @@ -1806,6 +1894,9 @@ public final class StrictMode { broadcastIntentAction = broadcastIntent.getAction(); } ThreadSpanState state = sThisThreadSpanState.get(); if (tr instanceof InstanceCountViolation) { this.numInstances = ((InstanceCountViolation) tr).mInstances; } synchronized (state) { int spanActiveCount = state.mActiveSize; if (spanActiveCount > MAX_SPAN_TAGS) { Loading Loading @@ -1867,6 +1958,7 @@ public final class StrictMode { violationNumThisLoop = in.readInt(); numAnimationsRunning = in.readInt(); violationUptimeMillis = in.readLong(); numInstances = in.readLong(); broadcastIntentAction = in.readString(); tags = in.readStringArray(); } Loading @@ -1881,6 +1973,7 @@ public final class StrictMode { dest.writeInt(violationNumThisLoop); dest.writeInt(numAnimationsRunning); dest.writeLong(violationUptimeMillis); dest.writeLong(numInstances); dest.writeString(broadcastIntentAction); dest.writeStringArray(tags); } Loading @@ -1895,6 +1988,9 @@ public final class StrictMode { if (durationMillis != -1) { pw.println(prefix + "durationMillis: " + durationMillis); } if (numInstances != -1) { pw.println(prefix + "numInstances: " + numInstances); } if (violationNumThisLoop != 0) { pw.println(prefix + "violationNumThisLoop: " + violationNumThisLoop); } Loading @@ -1914,4 +2010,29 @@ public final class StrictMode { } } // Dummy throwable, for now, since we don't know when or where the // leaked instances came from. We might in the future, but for // now we suppress the stack trace because it's useless and/or // misleading. private static class InstanceCountViolation extends Throwable { final Class mClass; 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); } public InstanceCountViolation(Class klass, long instances, int limit) { // Note: now including instances here, otherwise signatures would all be different. super(klass.toString() + "; limit=" + limit); setStackTrace(FAKE_STACK); mClass = klass; mInstances = instances; mLimit = limit; } } } services/java/com/android/server/am/ActivityManagerService.java +3 −0 Original line number Diff line number Diff line Loading @@ -6817,6 +6817,9 @@ public final class ActivityManagerService extends ActivityManagerNative if (info.durationMillis != -1) { sb.append("Duration-Millis: ").append(info.durationMillis).append("\n"); } if (info.numInstances != -1) { sb.append("Instance-Count: ").append(info.numInstances).append("\n"); } if (info.tags != null) { for (String tag : info.tags) { sb.append("Span-Tag: ").append(tag).append("\n"); Loading Loading
api/current.xml +11 −0 Original line number Diff line number Diff line Loading @@ -146705,6 +146705,17 @@ visibility="public" > </method> <method name="detectActivityLeaks" return="android.os.StrictMode.VmPolicy.Builder" abstract="false" native="false" synchronized="false" static="false" final="false" deprecated="not deprecated" visibility="public" > </method> <method name="detectAll" return="android.os.StrictMode.VmPolicy.Builder" abstract="false"
core/java/android/app/Activity.java +3 −0 Original line number Diff line number Diff line Loading @@ -4433,6 +4433,9 @@ public class Activity extends ContextThemeWrapper mStopped = true; } mResumed = false; // Check for Activity leaks, if enabled. StrictMode.conditionallyCheckInstanceCounts(); } final void performDestroy() { Loading
core/java/android/os/StrictMode.java +131 −10 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import com.android.internal.os.RuntimeInit; import dalvik.system.BlockGuard; import dalvik.system.CloseGuard; import dalvik.system.VMDebug; import java.io.PrintWriter; import java.io.StringWriter; Loading Loading @@ -181,6 +182,15 @@ public final class StrictMode { */ public static final int DETECT_VM_ACTIVITY_LEAKS = 0x800; // for VmPolicy /** * @hide */ private static final int DETECT_VM_INSTANCE_LEAKS = 0x1000; // for VmPolicy private static final int ALL_VM_DETECT_BITS = DETECT_VM_CURSOR_LEAKS | DETECT_VM_CLOSABLE_LEAKS | DETECT_VM_ACTIVITY_LEAKS | DETECT_VM_INSTANCE_LEAKS; /** * @hide */ Loading Loading @@ -573,11 +583,15 @@ public final class StrictMode { } else if (mClassInstanceLimit == null) { mClassInstanceLimit = new HashMap<Class, Integer>(); } mMask |= DETECT_VM_INSTANCE_LEAKS; mClassInstanceLimit.put(klass, instanceLimit); return this; } private Builder detectActivityLeaks() { /** * Detect leaks of {@link android.app.Activity} subclasses. */ public Builder detectActivityLeaks() { return enable(DETECT_VM_ACTIVITY_LEAKS); } Loading @@ -585,8 +599,8 @@ public final class StrictMode { * Detect everything that's potentially suspect. * * <p>In the Honeycomb release this includes leaks of * SQLite cursors and other closable objects but will * likely expand in future releases. * SQLite cursors, Activities, and other closable objects * but will likely expand in future releases. */ public Builder detectAll() { return enable(DETECT_VM_ACTIVITY_LEAKS | Loading Loading @@ -1346,6 +1360,41 @@ public final class StrictMode { gatheredViolations.set(null); } /** * @hide */ public static void conditionallyCheckInstanceCounts() { VmPolicy policy = getVmPolicy(); if (policy.classInstanceLimit.size() == 0) { return; } Runtime.getRuntime().gc(); // Note: classInstanceLimit is immutable, so this is lock-free for (Class klass : policy.classInstanceLimit.keySet()) { int limit = policy.classInstanceLimit.get(klass); long instances = VMDebug.countInstancesOfClass(klass, false); if (instances <= limit) { continue; } Throwable tr = new InstanceCountViolation(klass, instances, limit); onVmPolicyViolation(tr.getMessage(), tr); } } private static long sLastInstanceCountCheckMillis = 0; private static boolean sIsIdlerRegistered = false; // guarded by sProcessIdleHandler private static final MessageQueue.IdleHandler sProcessIdleHandler = new MessageQueue.IdleHandler() { public boolean queueIdle() { long now = SystemClock.uptimeMillis(); if (now - sLastInstanceCountCheckMillis > 30 * 1000) { sLastInstanceCountCheckMillis = now; conditionallyCheckInstanceCounts(); } return true; } }; /** * Sets the policy for what actions in the VM process (on any * thread) should be detected, as well as the penalty if such Loading @@ -1357,6 +1406,19 @@ public final class StrictMode { sVmPolicy = policy; sVmPolicyMask = policy.mask; setCloseGuardEnabled(vmClosableObjectLeaksEnabled()); Looper looper = Looper.getMainLooper(); if (looper != null) { MessageQueue mq = looper.mQueue; synchronized (sProcessIdleHandler) { if (policy.classInstanceLimit.size() == 0) { mq.removeIdleHandler(sProcessIdleHandler); } else if (!sIsIdlerRegistered) { mq.addIdleHandler(sProcessIdleHandler); sIsIdlerRegistered = true; } } } } /** Loading Loading @@ -1406,19 +1468,39 @@ public final class StrictMode { onVmPolicyViolation(message, originStack); } // Map from VM violation fingerprint to uptime millis. private static final HashMap<Integer, Long> sLastVmViolationTime = new HashMap<Integer, Long>(); /** * @hide */ public static void onVmPolicyViolation(String message, Throwable originStack) { if ((sVmPolicyMask & PENALTY_LOG) != 0) { Log.e(TAG, message, originStack); final boolean penaltyDropbox = (sVmPolicyMask & PENALTY_DROPBOX) != 0; final boolean penaltyDeath = (sVmPolicyMask & PENALTY_DEATH) != 0; final boolean penaltyLog = (sVmPolicyMask & PENALTY_LOG) != 0; final ViolationInfo info = new ViolationInfo(originStack, sVmPolicyMask); final Integer fingerprint = info.hashCode(); final long now = SystemClock.uptimeMillis(); long lastViolationTime = 0; long timeSinceLastViolationMillis = Long.MAX_VALUE; synchronized (sLastVmViolationTime) { if (sLastVmViolationTime.containsKey(fingerprint)) { lastViolationTime = sLastVmViolationTime.get(fingerprint); timeSinceLastViolationMillis = now - lastViolationTime; } if (timeSinceLastViolationMillis > MIN_LOG_INTERVAL_MS) { sLastVmViolationTime.put(fingerprint, now); } } boolean penaltyDropbox = (sVmPolicyMask & PENALTY_DROPBOX) != 0; boolean penaltyDeath = (sVmPolicyMask & PENALTY_DEATH) != 0; Log.d(TAG, "Time since last vm violation: " + timeSinceLastViolationMillis); if (penaltyLog && timeSinceLastViolationMillis > MIN_LOG_INTERVAL_MS) { Log.e(TAG, message, originStack); } int violationMaskSubset = PENALTY_DROPBOX | DETECT_VM_CURSOR_LEAKS; ViolationInfo info = new ViolationInfo(originStack, sVmPolicyMask); int violationMaskSubset = PENALTY_DROPBOX | (ALL_VM_DETECT_BITS & sVmPolicyMask); if (penaltyDropbox && !penaltyDeath) { // Common case for userdebug/eng builds. If no death and Loading @@ -1428,7 +1510,7 @@ public final class StrictMode { return; } if (penaltyDropbox) { if (penaltyDropbox && lastViolationTime == 0) { // The violationMask, passed to ActivityManager, is a // subset of the original StrictMode policy bitmask, with // only the bit violated and penalty bits to be executed Loading Loading @@ -1785,6 +1867,12 @@ public final class StrictMode { */ public String broadcastIntentAction; /** * If this is a instance count violation, the number of instances in memory, * else -1. */ public long numInstances = -1; /** * Create an uninitialized instance of ViolationInfo */ Loading @@ -1806,6 +1894,9 @@ public final class StrictMode { broadcastIntentAction = broadcastIntent.getAction(); } ThreadSpanState state = sThisThreadSpanState.get(); if (tr instanceof InstanceCountViolation) { this.numInstances = ((InstanceCountViolation) tr).mInstances; } synchronized (state) { int spanActiveCount = state.mActiveSize; if (spanActiveCount > MAX_SPAN_TAGS) { Loading Loading @@ -1867,6 +1958,7 @@ public final class StrictMode { violationNumThisLoop = in.readInt(); numAnimationsRunning = in.readInt(); violationUptimeMillis = in.readLong(); numInstances = in.readLong(); broadcastIntentAction = in.readString(); tags = in.readStringArray(); } Loading @@ -1881,6 +1973,7 @@ public final class StrictMode { dest.writeInt(violationNumThisLoop); dest.writeInt(numAnimationsRunning); dest.writeLong(violationUptimeMillis); dest.writeLong(numInstances); dest.writeString(broadcastIntentAction); dest.writeStringArray(tags); } Loading @@ -1895,6 +1988,9 @@ public final class StrictMode { if (durationMillis != -1) { pw.println(prefix + "durationMillis: " + durationMillis); } if (numInstances != -1) { pw.println(prefix + "numInstances: " + numInstances); } if (violationNumThisLoop != 0) { pw.println(prefix + "violationNumThisLoop: " + violationNumThisLoop); } Loading @@ -1914,4 +2010,29 @@ public final class StrictMode { } } // Dummy throwable, for now, since we don't know when or where the // leaked instances came from. We might in the future, but for // now we suppress the stack trace because it's useless and/or // misleading. private static class InstanceCountViolation extends Throwable { final Class mClass; 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); } public InstanceCountViolation(Class klass, long instances, int limit) { // Note: now including instances here, otherwise signatures would all be different. super(klass.toString() + "; limit=" + limit); setStackTrace(FAKE_STACK); mClass = klass; mInstances = instances; mLimit = limit; } } }
services/java/com/android/server/am/ActivityManagerService.java +3 −0 Original line number Diff line number Diff line Loading @@ -6817,6 +6817,9 @@ public final class ActivityManagerService extends ActivityManagerNative if (info.durationMillis != -1) { sb.append("Duration-Millis: ").append(info.durationMillis).append("\n"); } if (info.numInstances != -1) { sb.append("Instance-Count: ").append(info.numInstances).append("\n"); } if (info.tags != null) { for (String tag : info.tags) { sb.append("Span-Tag: ").append(tag).append("\n"); Loading