resolved conflicts for merge of 9240f16d
to honeycomb-plus-aosp
Change-Id: I6e595bb11a5a692ccd730b9d1d2aa367063a61f5
This commit is contained in:
@ -148168,6 +148168,17 @@
|
|||||||
visibility="public"
|
visibility="public"
|
||||||
>
|
>
|
||||||
</method>
|
</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"
|
<method name="detectAll"
|
||||||
return="android.os.StrictMode.VmPolicy.Builder"
|
return="android.os.StrictMode.VmPolicy.Builder"
|
||||||
abstract="false"
|
abstract="false"
|
||||||
|
@ -4431,6 +4431,10 @@ public class Activity extends ContextThemeWrapper
|
|||||||
|
|
||||||
mStopped = true;
|
mStopped = true;
|
||||||
}
|
}
|
||||||
|
mResumed = false;
|
||||||
|
|
||||||
|
// Check for Activity leaks, if enabled.
|
||||||
|
StrictMode.conditionallyCheckInstanceCounts();
|
||||||
}
|
}
|
||||||
|
|
||||||
final void performDestroy() {
|
final void performDestroy() {
|
||||||
|
@ -30,6 +30,7 @@ import com.android.internal.os.RuntimeInit;
|
|||||||
|
|
||||||
import dalvik.system.BlockGuard;
|
import dalvik.system.BlockGuard;
|
||||||
import dalvik.system.CloseGuard;
|
import dalvik.system.CloseGuard;
|
||||||
|
import dalvik.system.VMDebug;
|
||||||
|
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
@ -181,6 +182,15 @@ public final class StrictMode {
|
|||||||
*/
|
*/
|
||||||
public static final int DETECT_VM_ACTIVITY_LEAKS = 0x800; // for VmPolicy
|
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
|
* @hide
|
||||||
*/
|
*/
|
||||||
@ -573,11 +583,15 @@ public final class StrictMode {
|
|||||||
} else if (mClassInstanceLimit == null) {
|
} else if (mClassInstanceLimit == null) {
|
||||||
mClassInstanceLimit = new HashMap<Class, Integer>();
|
mClassInstanceLimit = new HashMap<Class, Integer>();
|
||||||
}
|
}
|
||||||
|
mMask |= DETECT_VM_INSTANCE_LEAKS;
|
||||||
mClassInstanceLimit.put(klass, instanceLimit);
|
mClassInstanceLimit.put(klass, instanceLimit);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Builder detectActivityLeaks() {
|
/**
|
||||||
|
* Detect leaks of {@link android.app.Activity} subclasses.
|
||||||
|
*/
|
||||||
|
public Builder detectActivityLeaks() {
|
||||||
return enable(DETECT_VM_ACTIVITY_LEAKS);
|
return enable(DETECT_VM_ACTIVITY_LEAKS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -585,8 +599,8 @@ public final class StrictMode {
|
|||||||
* Detect everything that's potentially suspect.
|
* Detect everything that's potentially suspect.
|
||||||
*
|
*
|
||||||
* <p>In the Honeycomb release this includes leaks of
|
* <p>In the Honeycomb release this includes leaks of
|
||||||
* SQLite cursors and other closable objects but will
|
* SQLite cursors, Activities, and other closable objects
|
||||||
* likely expand in future releases.
|
* but will likely expand in future releases.
|
||||||
*/
|
*/
|
||||||
public Builder detectAll() {
|
public Builder detectAll() {
|
||||||
return enable(DETECT_VM_ACTIVITY_LEAKS |
|
return enable(DETECT_VM_ACTIVITY_LEAKS |
|
||||||
@ -1346,6 +1360,41 @@ public final class StrictMode {
|
|||||||
gatheredViolations.set(null);
|
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
|
* Sets the policy for what actions in the VM process (on any
|
||||||
* thread) should be detected, as well as the penalty if such
|
* thread) should be detected, as well as the penalty if such
|
||||||
@ -1357,6 +1406,19 @@ public final class StrictMode {
|
|||||||
sVmPolicy = policy;
|
sVmPolicy = policy;
|
||||||
sVmPolicyMask = policy.mask;
|
sVmPolicyMask = policy.mask;
|
||||||
setCloseGuardEnabled(vmClosableObjectLeaksEnabled());
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1406,19 +1468,39 @@ public final class StrictMode {
|
|||||||
onVmPolicyViolation(message, originStack);
|
onVmPolicyViolation(message, originStack);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Map from VM violation fingerprint to uptime millis.
|
||||||
|
private static final HashMap<Integer, Long> sLastVmViolationTime = new HashMap<Integer, Long>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
public static void onVmPolicyViolation(String message, Throwable originStack) {
|
public static void onVmPolicyViolation(String message, Throwable originStack) {
|
||||||
if ((sVmPolicyMask & PENALTY_LOG) != 0) {
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.d(TAG, "Time since last vm violation: " + timeSinceLastViolationMillis);
|
||||||
|
|
||||||
|
if (penaltyLog && timeSinceLastViolationMillis > MIN_LOG_INTERVAL_MS) {
|
||||||
Log.e(TAG, message, originStack);
|
Log.e(TAG, message, originStack);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean penaltyDropbox = (sVmPolicyMask & PENALTY_DROPBOX) != 0;
|
int violationMaskSubset = PENALTY_DROPBOX | (ALL_VM_DETECT_BITS & sVmPolicyMask);
|
||||||
boolean penaltyDeath = (sVmPolicyMask & PENALTY_DEATH) != 0;
|
|
||||||
|
|
||||||
int violationMaskSubset = PENALTY_DROPBOX | DETECT_VM_CURSOR_LEAKS;
|
|
||||||
ViolationInfo info = new ViolationInfo(originStack, sVmPolicyMask);
|
|
||||||
|
|
||||||
if (penaltyDropbox && !penaltyDeath) {
|
if (penaltyDropbox && !penaltyDeath) {
|
||||||
// Common case for userdebug/eng builds. If no death and
|
// Common case for userdebug/eng builds. If no death and
|
||||||
@ -1428,7 +1510,7 @@ public final class StrictMode {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (penaltyDropbox) {
|
if (penaltyDropbox && lastViolationTime == 0) {
|
||||||
// The violationMask, passed to ActivityManager, is a
|
// The violationMask, passed to ActivityManager, is a
|
||||||
// subset of the original StrictMode policy bitmask, with
|
// subset of the original StrictMode policy bitmask, with
|
||||||
// only the bit violated and penalty bits to be executed
|
// only the bit violated and penalty bits to be executed
|
||||||
@ -1785,6 +1867,12 @@ public final class StrictMode {
|
|||||||
*/
|
*/
|
||||||
public String broadcastIntentAction;
|
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
|
* Create an uninitialized instance of ViolationInfo
|
||||||
*/
|
*/
|
||||||
@ -1806,6 +1894,9 @@ public final class StrictMode {
|
|||||||
broadcastIntentAction = broadcastIntent.getAction();
|
broadcastIntentAction = broadcastIntent.getAction();
|
||||||
}
|
}
|
||||||
ThreadSpanState state = sThisThreadSpanState.get();
|
ThreadSpanState state = sThisThreadSpanState.get();
|
||||||
|
if (tr instanceof InstanceCountViolation) {
|
||||||
|
this.numInstances = ((InstanceCountViolation) tr).mInstances;
|
||||||
|
}
|
||||||
synchronized (state) {
|
synchronized (state) {
|
||||||
int spanActiveCount = state.mActiveSize;
|
int spanActiveCount = state.mActiveSize;
|
||||||
if (spanActiveCount > MAX_SPAN_TAGS) {
|
if (spanActiveCount > MAX_SPAN_TAGS) {
|
||||||
@ -1867,6 +1958,7 @@ public final class StrictMode {
|
|||||||
violationNumThisLoop = in.readInt();
|
violationNumThisLoop = in.readInt();
|
||||||
numAnimationsRunning = in.readInt();
|
numAnimationsRunning = in.readInt();
|
||||||
violationUptimeMillis = in.readLong();
|
violationUptimeMillis = in.readLong();
|
||||||
|
numInstances = in.readLong();
|
||||||
broadcastIntentAction = in.readString();
|
broadcastIntentAction = in.readString();
|
||||||
tags = in.readStringArray();
|
tags = in.readStringArray();
|
||||||
}
|
}
|
||||||
@ -1881,6 +1973,7 @@ public final class StrictMode {
|
|||||||
dest.writeInt(violationNumThisLoop);
|
dest.writeInt(violationNumThisLoop);
|
||||||
dest.writeInt(numAnimationsRunning);
|
dest.writeInt(numAnimationsRunning);
|
||||||
dest.writeLong(violationUptimeMillis);
|
dest.writeLong(violationUptimeMillis);
|
||||||
|
dest.writeLong(numInstances);
|
||||||
dest.writeString(broadcastIntentAction);
|
dest.writeString(broadcastIntentAction);
|
||||||
dest.writeStringArray(tags);
|
dest.writeStringArray(tags);
|
||||||
}
|
}
|
||||||
@ -1895,6 +1988,9 @@ public final class StrictMode {
|
|||||||
if (durationMillis != -1) {
|
if (durationMillis != -1) {
|
||||||
pw.println(prefix + "durationMillis: " + durationMillis);
|
pw.println(prefix + "durationMillis: " + durationMillis);
|
||||||
}
|
}
|
||||||
|
if (numInstances != -1) {
|
||||||
|
pw.println(prefix + "numInstances: " + numInstances);
|
||||||
|
}
|
||||||
if (violationNumThisLoop != 0) {
|
if (violationNumThisLoop != 0) {
|
||||||
pw.println(prefix + "violationNumThisLoop: " + violationNumThisLoop);
|
pw.println(prefix + "violationNumThisLoop: " + violationNumThisLoop);
|
||||||
}
|
}
|
||||||
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -6817,6 +6817,9 @@ public final class ActivityManagerService extends ActivityManagerNative
|
|||||||
if (info.durationMillis != -1) {
|
if (info.durationMillis != -1) {
|
||||||
sb.append("Duration-Millis: ").append(info.durationMillis).append("\n");
|
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) {
|
if (info.tags != null) {
|
||||||
for (String tag : info.tags) {
|
for (String tag : info.tags) {
|
||||||
sb.append("Span-Tag: ").append(tag).append("\n");
|
sb.append("Span-Tag: ").append(tag).append("\n");
|
||||||
|
Reference in New Issue
Block a user