383 lines
16 KiB
Java
383 lines
16 KiB
Java
package com.squareup.leakcanary;
|
|
|
|
import com.squareup.haha.perflib.ArrayInstance;
|
|
import com.squareup.haha.perflib.ClassInstance;
|
|
import com.squareup.haha.perflib.ClassObj;
|
|
import com.squareup.haha.perflib.Field;
|
|
import com.squareup.haha.perflib.HahaSpy;
|
|
import com.squareup.haha.perflib.Instance;
|
|
import com.squareup.haha.perflib.RootObj;
|
|
import com.squareup.haha.perflib.RootType;
|
|
import com.squareup.haha.perflib.Snapshot;
|
|
import com.squareup.haha.perflib.Type;
|
|
import com.squareup.leakcanary.LeakTraceElement;
|
|
import java.util.ArrayDeque;
|
|
import java.util.Deque;
|
|
import java.util.LinkedHashMap;
|
|
import java.util.LinkedHashSet;
|
|
import java.util.Map;
|
|
|
|
/* loaded from: classes.dex */
|
|
final class ShortestPathFinder {
|
|
private boolean canIgnoreStrings;
|
|
private final ExcludedRefs excludedRefs;
|
|
private final Deque<LeakNode> toVisitQueue = new ArrayDeque();
|
|
private final Deque<LeakNode> toVisitIfNoPathQueue = new ArrayDeque();
|
|
private final LinkedHashSet<Instance> toVisitSet = new LinkedHashSet<>();
|
|
private final LinkedHashSet<Instance> toVisitIfNoPathSet = new LinkedHashSet<>();
|
|
private final LinkedHashSet<Instance> visitedSet = new LinkedHashSet<>();
|
|
|
|
/* renamed from: com.squareup.leakcanary.ShortestPathFinder$1, reason: invalid class name */
|
|
static /* synthetic */ class AnonymousClass1 {
|
|
static final /* synthetic */ int[] $SwitchMap$com$squareup$haha$perflib$RootType = new int[RootType.values().length];
|
|
|
|
static {
|
|
try {
|
|
$SwitchMap$com$squareup$haha$perflib$RootType[RootType.JAVA_LOCAL.ordinal()] = 1;
|
|
} catch (NoSuchFieldError unused) {
|
|
}
|
|
try {
|
|
$SwitchMap$com$squareup$haha$perflib$RootType[RootType.INTERNED_STRING.ordinal()] = 2;
|
|
} catch (NoSuchFieldError unused2) {
|
|
}
|
|
try {
|
|
$SwitchMap$com$squareup$haha$perflib$RootType[RootType.DEBUGGER.ordinal()] = 3;
|
|
} catch (NoSuchFieldError unused3) {
|
|
}
|
|
try {
|
|
$SwitchMap$com$squareup$haha$perflib$RootType[RootType.INVALID_TYPE.ordinal()] = 4;
|
|
} catch (NoSuchFieldError unused4) {
|
|
}
|
|
try {
|
|
$SwitchMap$com$squareup$haha$perflib$RootType[RootType.UNREACHABLE.ordinal()] = 5;
|
|
} catch (NoSuchFieldError unused5) {
|
|
}
|
|
try {
|
|
$SwitchMap$com$squareup$haha$perflib$RootType[RootType.UNKNOWN.ordinal()] = 6;
|
|
} catch (NoSuchFieldError unused6) {
|
|
}
|
|
try {
|
|
$SwitchMap$com$squareup$haha$perflib$RootType[RootType.FINALIZING.ordinal()] = 7;
|
|
} catch (NoSuchFieldError unused7) {
|
|
}
|
|
try {
|
|
$SwitchMap$com$squareup$haha$perflib$RootType[RootType.SYSTEM_CLASS.ordinal()] = 8;
|
|
} catch (NoSuchFieldError unused8) {
|
|
}
|
|
try {
|
|
$SwitchMap$com$squareup$haha$perflib$RootType[RootType.VM_INTERNAL.ordinal()] = 9;
|
|
} catch (NoSuchFieldError unused9) {
|
|
}
|
|
try {
|
|
$SwitchMap$com$squareup$haha$perflib$RootType[RootType.NATIVE_LOCAL.ordinal()] = 10;
|
|
} catch (NoSuchFieldError unused10) {
|
|
}
|
|
try {
|
|
$SwitchMap$com$squareup$haha$perflib$RootType[RootType.NATIVE_STATIC.ordinal()] = 11;
|
|
} catch (NoSuchFieldError unused11) {
|
|
}
|
|
try {
|
|
$SwitchMap$com$squareup$haha$perflib$RootType[RootType.THREAD_BLOCK.ordinal()] = 12;
|
|
} catch (NoSuchFieldError unused12) {
|
|
}
|
|
try {
|
|
$SwitchMap$com$squareup$haha$perflib$RootType[RootType.BUSY_MONITOR.ordinal()] = 13;
|
|
} catch (NoSuchFieldError unused13) {
|
|
}
|
|
try {
|
|
$SwitchMap$com$squareup$haha$perflib$RootType[RootType.NATIVE_MONITOR.ordinal()] = 14;
|
|
} catch (NoSuchFieldError unused14) {
|
|
}
|
|
try {
|
|
$SwitchMap$com$squareup$haha$perflib$RootType[RootType.REFERENCE_CLEANUP.ordinal()] = 15;
|
|
} catch (NoSuchFieldError unused15) {
|
|
}
|
|
try {
|
|
$SwitchMap$com$squareup$haha$perflib$RootType[RootType.NATIVE_STACK.ordinal()] = 16;
|
|
} catch (NoSuchFieldError unused16) {
|
|
}
|
|
try {
|
|
$SwitchMap$com$squareup$haha$perflib$RootType[RootType.JAVA_STATIC.ordinal()] = 17;
|
|
} catch (NoSuchFieldError unused17) {
|
|
}
|
|
}
|
|
}
|
|
|
|
static final class Result {
|
|
final boolean excludingKnownLeaks;
|
|
final LeakNode leakingNode;
|
|
|
|
Result(LeakNode leakNode, boolean z) {
|
|
this.leakingNode = leakNode;
|
|
this.excludingKnownLeaks = z;
|
|
}
|
|
}
|
|
|
|
ShortestPathFinder(ExcludedRefs excludedRefs) {
|
|
this.excludedRefs = excludedRefs;
|
|
}
|
|
|
|
private boolean checkSeen(LeakNode leakNode) {
|
|
return !this.visitedSet.add(leakNode.instance);
|
|
}
|
|
|
|
private void clearState() {
|
|
this.toVisitQueue.clear();
|
|
this.toVisitIfNoPathQueue.clear();
|
|
this.toVisitSet.clear();
|
|
this.toVisitIfNoPathSet.clear();
|
|
this.visitedSet.clear();
|
|
}
|
|
|
|
private void enqueue(Exclusion exclusion, LeakNode leakNode, Instance instance, LeakReference leakReference) {
|
|
if (instance == null || HahaHelper.isPrimitiveOrWrapperArray(instance) || HahaHelper.isPrimitiveWrapper(instance) || this.toVisitSet.contains(instance)) {
|
|
return;
|
|
}
|
|
boolean z = exclusion == null;
|
|
if (z || !this.toVisitIfNoPathSet.contains(instance)) {
|
|
if ((this.canIgnoreStrings && isString(instance)) || this.visitedSet.contains(instance)) {
|
|
return;
|
|
}
|
|
LeakNode leakNode2 = new LeakNode(exclusion, instance, leakNode, leakReference);
|
|
if (z) {
|
|
this.toVisitSet.add(instance);
|
|
this.toVisitQueue.add(leakNode2);
|
|
} else {
|
|
this.toVisitIfNoPathSet.add(instance);
|
|
this.toVisitIfNoPathQueue.add(leakNode2);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void enqueueGcRoots(Snapshot snapshot) {
|
|
for (RootObj rootObj : HahaSpy.allGcRoots(snapshot)) {
|
|
switch (AnonymousClass1.$SwitchMap$com$squareup$haha$perflib$RootType[rootObj.getRootType().ordinal()]) {
|
|
case 1:
|
|
Exclusion exclusion = this.excludedRefs.threadNames.get(HahaHelper.threadName(HahaSpy.allocatingThread(rootObj)));
|
|
if (exclusion == null || !exclusion.alwaysExclude) {
|
|
enqueue(exclusion, null, rootObj, null);
|
|
break;
|
|
} else {
|
|
break;
|
|
}
|
|
break;
|
|
case 2:
|
|
case 3:
|
|
case 4:
|
|
case 5:
|
|
case 6:
|
|
case 7:
|
|
break;
|
|
case 8:
|
|
case 9:
|
|
case 10:
|
|
case 11:
|
|
case 12:
|
|
case 13:
|
|
case 14:
|
|
case 15:
|
|
case 16:
|
|
case 17:
|
|
enqueue(null, null, rootObj, null);
|
|
break;
|
|
default:
|
|
throw new UnsupportedOperationException("Unknown root type:" + rootObj.getRootType());
|
|
}
|
|
}
|
|
}
|
|
|
|
private boolean isString(Instance instance) {
|
|
return instance.getClassObj() != null && instance.getClassObj().getClassName().equals(String.class.getName());
|
|
}
|
|
|
|
private void visitArrayInstance(LeakNode leakNode) {
|
|
ArrayInstance arrayInstance = (ArrayInstance) leakNode.instance;
|
|
if (arrayInstance.getArrayType() == Type.OBJECT) {
|
|
Object[] values = arrayInstance.getValues();
|
|
for (int i = 0; i < values.length; i++) {
|
|
Instance instance = (Instance) values[i];
|
|
enqueue(null, leakNode, instance, new LeakReference(LeakTraceElement.Type.ARRAY_ENTRY, Integer.toString(i), instance == null ? "null" : instance.toString()));
|
|
}
|
|
}
|
|
}
|
|
|
|
private void visitClassInstance(LeakNode leakNode) {
|
|
ClassInstance classInstance = (ClassInstance) leakNode.instance;
|
|
LinkedHashMap linkedHashMap = new LinkedHashMap();
|
|
Exclusion exclusion = null;
|
|
for (ClassObj classObj = classInstance.getClassObj(); classObj != null; classObj = classObj.getSuperClassObj()) {
|
|
Exclusion exclusion2 = this.excludedRefs.classNames.get(classObj.getClassName());
|
|
if (exclusion2 != null && (exclusion == null || !exclusion.alwaysExclude)) {
|
|
exclusion = exclusion2;
|
|
}
|
|
Map<String, Exclusion> map = this.excludedRefs.fieldNameByClassName.get(classObj.getClassName());
|
|
if (map != null) {
|
|
linkedHashMap.putAll(map);
|
|
}
|
|
}
|
|
if (exclusion == null || !exclusion.alwaysExclude) {
|
|
for (ClassInstance.FieldValue fieldValue : classInstance.getValues()) {
|
|
Field field = fieldValue.getField();
|
|
if (field.getType() == Type.OBJECT) {
|
|
Instance instance = (Instance) fieldValue.getValue();
|
|
String name = field.getName();
|
|
Exclusion exclusion3 = (Exclusion) linkedHashMap.get(name);
|
|
if (exclusion3 == null || (exclusion != null && (!exclusion3.alwaysExclude || exclusion.alwaysExclude))) {
|
|
exclusion3 = exclusion;
|
|
}
|
|
enqueue(exclusion3, leakNode, instance, new LeakReference(LeakTraceElement.Type.INSTANCE_FIELD, name, fieldValue.getValue() == null ? "null" : fieldValue.getValue().toString()));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void visitClassObj(LeakNode leakNode) {
|
|
Exclusion exclusion;
|
|
ClassObj classObj = (ClassObj) leakNode.instance;
|
|
Map<String, Exclusion> map = this.excludedRefs.staticFieldNameByClassName.get(classObj.getClassName());
|
|
for (Map.Entry<Field, Object> entry : classObj.getStaticFieldValues().entrySet()) {
|
|
Field key = entry.getKey();
|
|
if (key.getType() == Type.OBJECT) {
|
|
String name = key.getName();
|
|
if (!name.equals("$staticOverhead")) {
|
|
Instance instance = (Instance) entry.getValue();
|
|
boolean z = true;
|
|
LeakReference leakReference = new LeakReference(LeakTraceElement.Type.STATIC_FIELD, name, entry.getValue() == null ? "null" : entry.getValue().toString());
|
|
if (map != null && (exclusion = map.get(name)) != null) {
|
|
z = false;
|
|
if (!exclusion.alwaysExclude) {
|
|
enqueue(exclusion, leakNode, instance, leakReference);
|
|
}
|
|
}
|
|
if (z) {
|
|
enqueue(null, leakNode, instance, leakReference);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void visitRootObj(LeakNode leakNode) {
|
|
RootObj rootObj = (RootObj) leakNode.instance;
|
|
Instance referredInstance = rootObj.getReferredInstance();
|
|
if (rootObj.getRootType() != RootType.JAVA_LOCAL) {
|
|
enqueue(null, leakNode, referredInstance, null);
|
|
return;
|
|
}
|
|
Instance allocatingThread = HahaSpy.allocatingThread(rootObj);
|
|
Exclusion exclusion = leakNode.exclusion;
|
|
if (exclusion == null) {
|
|
exclusion = null;
|
|
}
|
|
enqueue(exclusion, new LeakNode(null, allocatingThread, null, null), referredInstance, new LeakReference(LeakTraceElement.Type.LOCAL, null, null));
|
|
}
|
|
|
|
/* JADX WARN: Code restructure failed: missing block: B:9:0x004e, code lost:
|
|
|
|
return new com.squareup.leakcanary.ShortestPathFinder.Result(r7, r2);
|
|
*/
|
|
/*
|
|
Code decompiled incorrectly, please refer to instructions dump.
|
|
To view partially-correct code enable 'Show inconsistent code' option in preferences
|
|
*/
|
|
com.squareup.leakcanary.ShortestPathFinder.Result findPath(com.squareup.haha.perflib.Snapshot r7, com.squareup.haha.perflib.Instance r8) {
|
|
/*
|
|
r6 = this;
|
|
r6.clearState()
|
|
boolean r0 = r6.isString(r8)
|
|
r1 = 1
|
|
r0 = r0 ^ r1
|
|
r6.canIgnoreStrings = r0
|
|
r6.enqueueGcRoots(r7)
|
|
r7 = 0
|
|
r0 = 0
|
|
L10:
|
|
java.util.Deque<com.squareup.leakcanary.LeakNode> r2 = r6.toVisitQueue
|
|
boolean r2 = r2.isEmpty()
|
|
if (r2 == 0) goto L24
|
|
java.util.Deque<com.squareup.leakcanary.LeakNode> r2 = r6.toVisitIfNoPathQueue
|
|
boolean r2 = r2.isEmpty()
|
|
if (r2 != 0) goto L21
|
|
goto L24
|
|
L21:
|
|
r2 = r7
|
|
r7 = r0
|
|
goto L49
|
|
L24:
|
|
java.util.Deque<com.squareup.leakcanary.LeakNode> r2 = r6.toVisitQueue
|
|
boolean r2 = r2.isEmpty()
|
|
if (r2 != 0) goto L38
|
|
java.util.Deque<com.squareup.leakcanary.LeakNode> r2 = r6.toVisitQueue
|
|
java.lang.Object r2 = r2.poll()
|
|
com.squareup.leakcanary.LeakNode r2 = (com.squareup.leakcanary.LeakNode) r2
|
|
r5 = r2
|
|
r2 = r7
|
|
r7 = r5
|
|
goto L45
|
|
L38:
|
|
java.util.Deque<com.squareup.leakcanary.LeakNode> r7 = r6.toVisitIfNoPathQueue
|
|
java.lang.Object r7 = r7.poll()
|
|
com.squareup.leakcanary.LeakNode r7 = (com.squareup.leakcanary.LeakNode) r7
|
|
com.squareup.leakcanary.Exclusion r2 = r7.exclusion
|
|
if (r2 == 0) goto L92
|
|
r2 = 1
|
|
L45:
|
|
com.squareup.haha.perflib.Instance r3 = r7.instance
|
|
if (r3 != r8) goto L4f
|
|
L49:
|
|
com.squareup.leakcanary.ShortestPathFinder$Result r8 = new com.squareup.leakcanary.ShortestPathFinder$Result
|
|
r8.<init>(r7, r2)
|
|
return r8
|
|
L4f:
|
|
boolean r3 = r6.checkSeen(r7)
|
|
if (r3 == 0) goto L56
|
|
goto L77
|
|
L56:
|
|
com.squareup.haha.perflib.Instance r3 = r7.instance
|
|
boolean r4 = r3 instanceof com.squareup.haha.perflib.RootObj
|
|
if (r4 == 0) goto L60
|
|
r6.visitRootObj(r7)
|
|
goto L77
|
|
L60:
|
|
boolean r4 = r3 instanceof com.squareup.haha.perflib.ClassObj
|
|
if (r4 == 0) goto L68
|
|
r6.visitClassObj(r7)
|
|
goto L77
|
|
L68:
|
|
boolean r4 = r3 instanceof com.squareup.haha.perflib.ClassInstance
|
|
if (r4 == 0) goto L70
|
|
r6.visitClassInstance(r7)
|
|
goto L77
|
|
L70:
|
|
boolean r3 = r3 instanceof com.squareup.haha.perflib.ArrayInstance
|
|
if (r3 == 0) goto L79
|
|
r6.visitArrayInstance(r7)
|
|
L77:
|
|
r7 = r2
|
|
goto L10
|
|
L79:
|
|
java.lang.IllegalStateException r8 = new java.lang.IllegalStateException
|
|
java.lang.StringBuilder r0 = new java.lang.StringBuilder
|
|
r0.<init>()
|
|
java.lang.String r1 = "Unexpected type for "
|
|
r0.append(r1)
|
|
com.squareup.haha.perflib.Instance r7 = r7.instance
|
|
r0.append(r7)
|
|
java.lang.String r7 = r0.toString()
|
|
r8.<init>(r7)
|
|
throw r8
|
|
L92:
|
|
java.lang.IllegalStateException r8 = new java.lang.IllegalStateException
|
|
java.lang.StringBuilder r0 = new java.lang.StringBuilder
|
|
r0.<init>()
|
|
java.lang.String r1 = "Expected node to have an exclusion "
|
|
r0.append(r1)
|
|
r0.append(r7)
|
|
java.lang.String r7 = r0.toString()
|
|
r8.<init>(r7)
|
|
throw r8
|
|
*/
|
|
throw new UnsupportedOperationException("Method not decompiled: com.squareup.leakcanary.ShortestPathFinder.findPath(com.squareup.haha.perflib.Snapshot, com.squareup.haha.perflib.Instance):com.squareup.leakcanary.ShortestPathFinder$Result");
|
|
}
|
|
}
|