-
-
Notifications
You must be signed in to change notification settings - Fork 31
/
WrappingInstrumentable.kt
111 lines (99 loc) · 4.44 KB
/
WrappingInstrumentable.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
@file:Suppress("UnstableApiUsage")
package io.sentry.android.gradle.instrumentation.wrap
import com.android.build.api.instrumentation.ClassContext
import com.android.build.api.instrumentation.ClassData
import io.sentry.android.gradle.SentryPlugin
import io.sentry.android.gradle.instrumentation.ClassInstrumentable
import io.sentry.android.gradle.instrumentation.CommonClassVisitor
import io.sentry.android.gradle.instrumentation.MethodContext
import io.sentry.android.gradle.instrumentation.MethodInstrumentable
import io.sentry.android.gradle.instrumentation.SpanAddingClassVisitorFactory
import io.sentry.android.gradle.instrumentation.util.AnalyzingVisitor
import io.sentry.android.gradle.instrumentation.util.findClassReader
import io.sentry.android.gradle.instrumentation.util.findClassWriter
import io.sentry.android.gradle.instrumentation.util.isMinifiedClass
import io.sentry.android.gradle.instrumentation.util.isSentryClass
import io.sentry.android.gradle.instrumentation.wrap.visitor.WrappingVisitor
import io.sentry.android.gradle.util.info
import org.objectweb.asm.ClassVisitor
import org.objectweb.asm.MethodVisitor
import org.objectweb.asm.tree.MethodNode
class WrappingInstrumentable : ClassInstrumentable {
override fun getVisitor(
instrumentableContext: ClassContext,
apiVersion: Int,
originalVisitor: ClassVisitor,
parameters: SpanAddingClassVisitorFactory.SpanAddingParameters
): ClassVisitor {
val simpleClassName =
instrumentableContext.currentClassData.className.substringAfterLast('.')
val classReader = originalVisitor.findClassWriter()?.findClassReader()
val isMinifiedClass = classReader?.isMinifiedClass() ?: false
if (isMinifiedClass) {
// We only check for minified classes for the WrappingInstrumentable, because it is the
// only one which runs over all classes
SentryPlugin.logger.info {
"$simpleClassName skipped from instrumentation because it's a minified class."
}
return originalVisitor
}
return AnalyzingVisitor(
apiVersion = apiVersion,
nextVisitor = { methods ->
CommonClassVisitor(
apiVersion = apiVersion,
classVisitor = originalVisitor,
className = simpleClassName,
methodInstrumentables = methods.map {
Wrap(instrumentableContext.currentClassData, it)
},
parameters = parameters
)
}
)
}
override fun isInstrumentable(data: ClassContext): Boolean = !data.isSentryClass()
}
class Wrap(
private val classContext: ClassData,
private val methodNode: MethodNode
) : MethodInstrumentable {
override val fqName: String = methodNode.name
companion object {
private val replacements = mapOf(
// FileInputStream to SentryFileInputStream
Replacement.FileInputStream.STRING,
Replacement.FileInputStream.FILE,
Replacement.FileInputStream.FILE_DESCRIPTOR,
// FileOutputStream to SentryFileOutputStream
Replacement.FileOutputStream.STRING,
Replacement.FileOutputStream.STRING_BOOLEAN,
Replacement.FileOutputStream.FILE,
Replacement.FileOutputStream.FILE_BOOLEAN,
Replacement.FileOutputStream.FILE_DESCRIPTOR
// TODO: enable, once https://github.com/getsentry/sentry-java/issues/1842 is resolved
// Context.openFileInput to SentryFileInputStream
// Replacement.Context.OPEN_FILE_INPUT,
// Context.openFileOutput to SentryFileOutputStream
// Replacement.Context.OPEN_FILE_OUTPUT
)
}
override fun getVisitor(
instrumentableContext: MethodContext,
apiVersion: Int,
originalVisitor: MethodVisitor,
parameters: SpanAddingClassVisitorFactory.SpanAddingParameters
): MethodVisitor =
WrappingVisitor(
api = apiVersion,
originalVisitor = originalVisitor,
firstPassVisitor = methodNode,
classContext = classContext,
context = instrumentableContext,
replacements = replacements
)
override fun isInstrumentable(data: MethodContext): Boolean =
data.name == fqName &&
data.descriptor == methodNode.desc &&
data.access == methodNode.access
}