Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 6c0bee2

Browse files
committed
Merge pull request square#219 from square/py/perflib
Swiching to HAHA 2.0.2 / Perflib
2 parents f8bcc4e + 47b098e commit 6c0bee2

File tree

16 files changed

+847
-396
lines changed

16 files changed

+847
-396
lines changed

CHANGELOG.md

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,29 @@
11
# Change Log
22

3-
## Version 1.3.2-SNAPSHOT
3+
## Version 1.4-SNAPSHOT
44

5+
* Switched to HAHA 2.0.2 with uses Perflib instead of MAT under the hood [#219](https://github.com/square/leakcanary/pull/219). This should fix most crashes and improve speed a lot. We can now parse Android M heap dumps, although there are still memory issues (see [#223](https://github.com/square/leakcanary/issues/223)).
56
* A status bar notification is displayed when the trace analysis results in an excluded ref leak [#216](https://github.com/square/leakcanary/pull/216).
67
* Added ProGuard configuration for debug library [#132](https://github.com/square/leakcanary/issues/132).
78
* 2 new ignored Android SDK leaks: [#26](https://github.com/square/leakcanary/issues/26) [#62](https://github.com/square/leakcanary/issues/62).
89
* Added excluded leaks to text report [#119](https://github.com/square/leakcanary/issues/119).
910
* Added LeakCanary SHA to text report [#120](https://github.com/square/leakcanary/issues/120).
1011
* Renamed all resources to begin with `leak_canary_` instead of `__leak_canary`[#161](https://github.com/square/leakcanary/pull/161)
1112

13+
### Public API changes
14+
15+
* AnalysisResult.failure is now a `Throwable` instead of an `Exception`. Main goal is to catch and correctly report OOMs while parsing.
16+
* Added ARRAY_ENTRY to LeakTraceElement.Type for references through array entries.
17+
* Renamed `ExcludedRefs` fields.
18+
* Each `ExcludedRef` entry can now be ignored entirely or "kept only if no other path".
19+
* Added support for ignoring all fields (static and non static) for a given class.
20+
1221
### Dependencies
1322

1423
```gradle
1524
dependencies {
16-
debugCompile 'com.squareup.leakcanary:leakcanary-android:1.3.2-SNAPSHOT'
17-
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3.2-SNAPSHOT'
25+
debugCompile 'com.squareup.leakcanary:leakcanary-android:1.4-SNAPSHOT'
26+
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.4-SNAPSHOT'
1827
}
1928
```
2029

build.gradle

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ subprojects {
55
// maven {
66
// url 'https://oss.sonatype.org/content/repositories/snapshots/'
77
// }
8+
// mavenLocal()
89
}
910

1011
buildscript {
@@ -25,7 +26,7 @@ ext {
2526
javaVersion = JavaVersion.VERSION_1_7
2627

2728
GROUP = 'com.squareup.leakcanary'
28-
VERSION_NAME = "1.3.2-SNAPSHOT"
29+
VERSION_NAME = "1.4-SNAPSHOT"
2930
POM_PACKAGING = "pom"
3031
POM_DESCRIPTION= "Leak Canary"
3132

leakcanary-analyzer/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ repositories {
1414
}
1515

1616
dependencies {
17-
compile 'com.squareup.haha:haha:1.3'
17+
compile 'com.squareup.haha:haha:2.0.2'
1818
compile project(':leakcanary-watcher')
1919
testCompile 'junit:junit:4.12'
2020
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Copyright (C) 2015 Square, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.squareup.haha.perflib;
17+
18+
public final class HahaSpy {
19+
20+
public static Instance allocatingThread(Instance instance) {
21+
Snapshot snapshot = instance.mHeap.mSnapshot;
22+
int threadSerialNumber;
23+
if (instance instanceof RootObj) {
24+
threadSerialNumber = ((RootObj) instance).mThread;
25+
} else {
26+
threadSerialNumber = instance.mStack.mThreadSerialNumber;
27+
}
28+
ThreadObj thread = snapshot.getThread(threadSerialNumber);
29+
return snapshot.findInstance(thread.mId);
30+
}
31+
32+
private HahaSpy() {
33+
throw new AssertionError();
34+
}
35+
}

leakcanary-analyzer/src/main/java/com/squareup/leakcanary/AnalysisResult.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ public static AnalysisResult leakDetected(boolean excludedLeak, String className
2828
return new AnalysisResult(true, excludedLeak, className, leakTrace, null, analysisDurationMs);
2929
}
3030

31-
public static AnalysisResult failure(Exception exception, long analysisDurationMs) {
32-
return new AnalysisResult(false, false, null, null, exception, analysisDurationMs);
31+
public static AnalysisResult failure(Throwable failure, long analysisDurationMs) {
32+
return new AnalysisResult(false, false, null, null, failure, analysisDurationMs);
3333
}
3434

3535
/** True if a leak was found in the heap dump. */
@@ -54,13 +54,13 @@ public static AnalysisResult failure(Exception exception, long analysisDurationM
5454
public final LeakTrace leakTrace;
5555

5656
/** Null unless the analysis failed. */
57-
public final Exception failure;
57+
public final Throwable failure;
5858

5959
/** Total time spent analyzing the heap. */
6060
public final long analysisDurationMs;
6161

6262
private AnalysisResult(boolean leakFound, boolean excludedLeak, String className,
63-
LeakTrace leakTrace, Exception failure, long analysisDurationMs) {
63+
LeakTrace leakTrace, Throwable failure, long analysisDurationMs) {
6464
this.leakFound = leakFound;
6565
this.excludedLeak = excludedLeak;
6666
this.className = className;
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
/*
2+
* Copyright (C) 2015 Square, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.squareup.leakcanary;
17+
18+
import com.squareup.haha.perflib.ArrayInstance;
19+
import com.squareup.haha.perflib.ClassInstance;
20+
import com.squareup.haha.perflib.ClassObj;
21+
import com.squareup.haha.perflib.Field;
22+
import com.squareup.haha.perflib.Heap;
23+
import com.squareup.haha.perflib.Instance;
24+
import com.squareup.haha.perflib.Type;
25+
import java.util.HashSet;
26+
import java.util.List;
27+
import java.util.Map;
28+
import java.util.Set;
29+
30+
import static com.squareup.leakcanary.Preconditions.checkNotNull;
31+
import static java.util.Arrays.asList;
32+
33+
public final class HahaHelper {
34+
35+
private static final Set<String> WRAPPER_TYPES = new HashSet<>(
36+
asList(Boolean.class.getName(), Character.class.getName(), Float.class.getName(),
37+
Double.class.getName(), Byte.class.getName(), Short.class.getName(),
38+
Integer.class.getName(), Long.class.getName()));
39+
40+
static String fieldToString(Map.Entry<Field, Object> entry) {
41+
return fieldToString(entry.getKey(), entry.getValue());
42+
}
43+
44+
static String fieldToString(ClassInstance.FieldValue fieldValue) {
45+
return fieldToString(fieldValue.getField(), fieldValue.getValue());
46+
}
47+
48+
static String fieldToString(Field field, Object value) {
49+
return field.getName() + " = " + value;
50+
}
51+
52+
static String threadName(Instance holder) {
53+
List<ClassInstance.FieldValue> values = classInstanceValues(holder);
54+
Object nameField = fieldValue(values, "name");
55+
return asString(nameField);
56+
}
57+
58+
static boolean extendsThread(ClassObj clazz) {
59+
boolean extendsThread = false;
60+
ClassObj parentClass = clazz;
61+
while (parentClass.getSuperClassObj() != null) {
62+
if (clazz.getClassName().equals(Thread.class.getName())) {
63+
extendsThread = true;
64+
break;
65+
}
66+
parentClass = parentClass.getSuperClassObj();
67+
}
68+
return extendsThread;
69+
}
70+
71+
static String asString(Object stringObject) {
72+
Instance instance = (Instance) stringObject;
73+
List<ClassInstance.FieldValue> values = classInstanceValues(instance);
74+
75+
Integer count = fieldValue(values, "count");
76+
Object value = fieldValue(values, "value");
77+
Integer offset;
78+
ArrayInstance charArray;
79+
if (isCharArray(value)) {
80+
charArray = (ArrayInstance) value;
81+
offset = fieldValue(values, "offset");
82+
} else {
83+
// In M preview 2+, the underlying char buffer resides in the heap with ID equalling the
84+
// String's ID + 16.
85+
// https://android-review.googlesource.com/#/c/160380/2/android/src/com/android/tools/idea/
86+
// editors/hprof/descriptors/InstanceFieldDescriptorImpl.java
87+
Heap heap = instance.getHeap();
88+
Instance inlineInstance = heap.getInstance(instance.getId() + 16);
89+
if (isCharArray(inlineInstance)) {
90+
charArray = (ArrayInstance) inlineInstance;
91+
offset = 0;
92+
} else {
93+
throw new UnsupportedOperationException("Could not find char array in " + instance);
94+
}
95+
}
96+
checkNotNull(count, "count");
97+
checkNotNull(charArray, "charArray");
98+
checkNotNull(offset, "offset");
99+
100+
if (count == 0) {
101+
return "";
102+
}
103+
104+
char[] chars = charArray.asCharArray(offset, count);
105+
106+
return new String(chars);
107+
}
108+
109+
public static boolean isPrimitiveWrapper(Object value) {
110+
if (!(value instanceof ClassInstance)) {
111+
return false;
112+
}
113+
return WRAPPER_TYPES.contains(((ClassInstance) value).getClassObj().getClassName());
114+
}
115+
116+
public static boolean isPrimitiveOrWrapperArray(Object value) {
117+
if (!(value instanceof ArrayInstance)) {
118+
return false;
119+
}
120+
ArrayInstance arrayInstance = (ArrayInstance) value;
121+
if (arrayInstance.getArrayType() != Type.OBJECT) {
122+
return true;
123+
}
124+
return WRAPPER_TYPES.contains(arrayInstance.getClassObj().getClassName());
125+
}
126+
127+
private static boolean isCharArray(Object value) {
128+
return value instanceof ArrayInstance && ((ArrayInstance) value).getArrayType() == Type.CHAR;
129+
}
130+
131+
static List<ClassInstance.FieldValue> classInstanceValues(Instance instance) {
132+
ClassInstance classInstance = (ClassInstance) instance;
133+
return classInstance.getValues();
134+
}
135+
136+
static <T> T fieldValue(List<ClassInstance.FieldValue> values, String fieldName) {
137+
for (ClassInstance.FieldValue fieldValue : values) {
138+
if (fieldValue.getField().getName().equals(fieldName)) {
139+
//noinspection unchecked
140+
return (T) fieldValue.getValue();
141+
}
142+
}
143+
throw new IllegalArgumentException("Field " + fieldName + " does not exists");
144+
}
145+
146+
private HahaHelper() {
147+
throw new AssertionError();
148+
}
149+
}

0 commit comments

Comments
 (0)