<lambda>null1 package shark.internal
2
3 import shark.HeapGraph
4 import shark.internal.ChainingInstanceReferenceReader.VirtualInstanceReferenceReader
5 import shark.HeapObject.HeapInstance
6 import shark.IgnoredReferenceMatcher
7 import shark.LibraryLeakReferenceMatcher
8 import shark.internal.Reference.LazyDetails
9 import shark.internal.ReferenceLocationType.LOCAL
10 import shark.ReferenceMatcher
11 import shark.ReferencePattern.JavaLocalPattern
12 import shark.filterFor
13
14 internal class JavaLocalReferenceReader(
15 val graph: HeapGraph,
16 referenceMatchers: List<ReferenceMatcher>
17 ) : VirtualInstanceReferenceReader {
18
19 private val threadClassObjectIds: Set<Long> =
20 graph.findClassByName(Thread::class.java.name)?.let { threadClass ->
21 setOf(threadClass.objectId) + (threadClass.subclasses
22 .map { it.objectId }
23 .toSet())
24 }?: emptySet()
25
26 private val threadNameReferenceMatchers: Map<String, ReferenceMatcher>
27
28 init {
29 val threadNames = mutableMapOf<String, ReferenceMatcher>()
30 referenceMatchers.filterFor(graph).forEach { referenceMatcher ->
31 when (val pattern = referenceMatcher.pattern) {
32 is JavaLocalPattern -> {
33 threadNames[pattern.threadName] = referenceMatcher
34 }
35 }
36 }
37 this.threadNameReferenceMatchers = threadNames
38 }
39
40 override fun matches(instance: HeapInstance): Boolean {
41 return instance.instanceClassId in threadClassObjectIds &&
42 ThreadObjects.getByThreadObjectId(graph, instance.objectId) != null
43 }
44
45 override fun read(source: HeapInstance): Sequence<Reference> {
46 val referenceMatcher = source[Thread::class, "name"]?.value?.readAsJavaString()?.let { threadName ->
47 threadNameReferenceMatchers[threadName]
48 }
49
50 if (referenceMatcher is IgnoredReferenceMatcher) {
51 return emptySequence()
52 }
53 val threadClassId = source.instanceClassId
54 return JavaFrames.getByThreadObjectId(graph, source.objectId)?.let { frames ->
55 frames.asSequence().map { frame ->
56 Reference(
57 valueObjectId = frame.id,
58 // Java Frames always have low priority because their path is harder to understand
59 // for developers
60 isLowPriority = true,
61 lazyDetailsResolver = {
62 LazyDetails(
63 // Unfortunately Android heap dumps do not include stack trace data, so
64 // JavaFrame.frameNumber is always -1 and we cannot know which method is causing the
65 // reference to be held.
66 name = "",
67 locationClassObjectId = threadClassId,
68 locationType = LOCAL,
69 matchedLibraryLeak = referenceMatcher as LibraryLeakReferenceMatcher?,
70 isVirtual = true
71 )
72 }
73 )
74 }
75 } ?: emptySequence()
76 }
77 }
78