diff --git a/embrace-bytecode-instrumentation-tests/src/test/java/io/embrace/gradle/plugin/instrumentation/InstrumentedBytecodeTestCases.kt b/embrace-bytecode-instrumentation-tests/src/test/java/io/embrace/gradle/plugin/instrumentation/InstrumentedBytecodeTestCases.kt index 029944cdd3..af9cd85657 100644 --- a/embrace-bytecode-instrumentation-tests/src/test/java/io/embrace/gradle/plugin/instrumentation/InstrumentedBytecodeTestCases.kt +++ b/embrace-bytecode-instrumentation-tests/src/test/java/io/embrace/gradle/plugin/instrumentation/InstrumentedBytecodeTestCases.kt @@ -32,19 +32,19 @@ import okhttp3.OkHttpClient import org.objectweb.asm.ClassVisitor private val onClickFactory: ClassVisitorFactory = { visitor -> - OnClickClassAdapter(ASM_API_VERSION, visitor) {} + OnClickClassAdapter(ASM_API_VERSION, visitor) } private val onLongClickFactory: ClassVisitorFactory = { visitor -> - OnLongClickClassAdapter(ASM_API_VERSION, visitor) {} + OnLongClickClassAdapter(ASM_API_VERSION, visitor) } private val webviewFactory: ClassVisitorFactory = { visitor -> - WebViewClientClassAdapter(ASM_API_VERSION, visitor) {} + WebViewClientClassAdapter(ASM_API_VERSION, visitor) } private val okHttpFactory: ClassVisitorFactory = { visitor -> - OkHttpClassAdapter(ASM_API_VERSION, visitor) {} + OkHttpClassAdapter(ASM_API_VERSION, visitor) } /** diff --git a/embrace-gradle-plugin/src/main/java/io/embrace/android/gradle/plugin/instrumentation/EmbraceClassVisitorFactory.kt b/embrace-gradle-plugin/src/main/java/io/embrace/android/gradle/plugin/instrumentation/EmbraceClassVisitorFactory.kt index 9821619c2c..77cf652f7b 100644 --- a/embrace-gradle-plugin/src/main/java/io/embrace/android/gradle/plugin/instrumentation/EmbraceClassVisitorFactory.kt +++ b/embrace-gradle-plugin/src/main/java/io/embrace/android/gradle/plugin/instrumentation/EmbraceClassVisitorFactory.kt @@ -3,7 +3,6 @@ package io.embrace.android.gradle.plugin.instrumentation import com.android.build.api.instrumentation.AsmClassVisitorFactory import com.android.build.api.instrumentation.ClassContext import com.android.build.api.instrumentation.ClassData -import io.embrace.android.gradle.plugin.Logger import org.objectweb.asm.ClassVisitor /** @@ -25,9 +24,7 @@ abstract class EmbraceClassVisitorFactory : AsmClassVisitorFactory, - logger: (() -> String) -> Unit, + parameters: Property ): ClassVisitor { val api = instrumentationContext.apiVersion.get() var visitor = nextClassVisitor @@ -34,25 +33,20 @@ internal fun createClassVisitorImpl( if (parameters.get().shouldInstrumentFirebaseMessaging.get() && FirebaseMessagingServiceClassAdapter.accept(classContext) ) { - visitor = FirebaseMessagingServiceClassAdapter(api, visitor, logger) - logger { "Added FirebaseMessagingServiceClassAdapter for $className." } + visitor = FirebaseMessagingServiceClassAdapter(api, visitor) } if (parameters.get().shouldInstrumentWebview.get() && WebViewClientClassAdapter.accept(classContext)) { - visitor = WebViewClientClassAdapter(api, visitor, logger) - logger { "Added WebViewClientClassAdapter for $className." } + visitor = WebViewClientClassAdapter(api, visitor) } if (parameters.get().shouldInstrumentOkHttp.get() && OkHttpClassAdapter.accept(classContext)) { - visitor = OkHttpClassAdapter(api, visitor, logger) - logger { "Added OkHttpClassAdapter for $className." } + visitor = OkHttpClassAdapter(api, visitor) } if (parameters.get().shouldInstrumentOnLongClick.get() && OnLongClickClassAdapter.accept(classContext)) { - visitor = OnLongClickClassAdapter(api, visitor, logger) - logger { "Added OnLongClickClassAdapter for $className." } + visitor = OnLongClickClassAdapter(api, visitor) } if (parameters.get().shouldInstrumentOnClick.get() && OnClickClassAdapter.accept(classContext)) { - visitor = OnClickClassAdapter(api, visitor, logger) - logger { "Added OnClickClassAdapter for $className." } + visitor = OnClickClassAdapter(api, visitor) } return visitor } diff --git a/embrace-gradle-plugin/src/main/java/io/embrace/android/gradle/plugin/instrumentation/visitor/BytecodeMethodInsertionParams.kt b/embrace-gradle-plugin/src/main/java/io/embrace/android/gradle/plugin/instrumentation/visitor/BytecodeMethodInsertionParams.kt new file mode 100644 index 0000000000..6b27680c2d --- /dev/null +++ b/embrace-gradle-plugin/src/main/java/io/embrace/android/gradle/plugin/instrumentation/visitor/BytecodeMethodInsertionParams.kt @@ -0,0 +1,33 @@ +package io.embrace.android.gradle.plugin.instrumentation.visitor + +/** + * The parameters that should be used to insert a function call into the body of a method. + */ +internal data class BytecodeMethodInsertionParams( + + /** + * The fully qualified class name containing the method to be instrumented. + */ + val owner: String, + + /** + * The function name that will be instrumented. + */ + val name: String, + + /** + * The type signature of the function to be instrumented. + */ + val descriptor: String, + + /** + * The starting index of the local variable on the operand stack. We assume that by default the bytecode + * entrypoint will take the current object as its first parameter, then all other parameters. + * + * For example, an instrumentation entrypoint for a View.OnClickListener would have the following + * signature: instrumentedMethodName(android.view.View.OnClickListener thiz, android.view.View view). + * + * In future we can revisit this decision, given that the current object is not usually used. + */ + val startVarIndex: Int = 0, +) diff --git a/embrace-gradle-plugin/src/main/java/io/embrace/android/gradle/plugin/instrumentation/visitor/FirebaseMessagingServiceClassAdapter.kt b/embrace-gradle-plugin/src/main/java/io/embrace/android/gradle/plugin/instrumentation/visitor/FirebaseMessagingServiceClassAdapter.kt index a5b7b47d63..3164deb591 100644 --- a/embrace-gradle-plugin/src/main/java/io/embrace/android/gradle/plugin/instrumentation/visitor/FirebaseMessagingServiceClassAdapter.kt +++ b/embrace-gradle-plugin/src/main/java/io/embrace/android/gradle/plugin/instrumentation/visitor/FirebaseMessagingServiceClassAdapter.kt @@ -11,7 +11,6 @@ import org.objectweb.asm.MethodVisitor class FirebaseMessagingServiceClassAdapter( api: Int, internal val nextClassVisitor: ClassVisitor?, - private val logger: (() -> String) -> Unit ) : ClassVisitor(api, nextClassVisitor) { companion object : ClassVisitFilter { @@ -19,26 +18,31 @@ class FirebaseMessagingServiceClassAdapter( private const val METHOD_NAME = "onMessageReceived" private const val METHOD_DESC = "(Lcom/google/firebase/messaging/RemoteMessage;)V" - @Suppress("UnstableApiUsage") override fun accept(classContext: ClassContext): Boolean { - if (classContext.currentClassData.superClasses.contains(CLASS_NAME)) { - return true - } - return false + return classContext.currentClassData.superClasses.contains(CLASS_NAME) } } + override fun visitMethod( access: Int, name: String, desc: String, signature: String?, - exceptions: Array? + exceptions: Array?, ): MethodVisitor? { val nextMethodVisitor = super.visitMethod(access, name, desc, signature, exceptions) return if (METHOD_NAME == name && METHOD_DESC == desc) { - logger { "FirebaseMessagingServiceClassAdapter: instrumented method $name $desc" } - FirebaseMessagingServiceMethodAdapter(api, nextMethodVisitor) + InstrumentationTargetMethodVisitor( + api = api, + methodVisitor = nextMethodVisitor, + params = BytecodeMethodInsertionParams( + owner = "io/embrace/android/embracesdk/fcm/swazzle/callback/com/android/fcm/FirebaseSwazzledHooks", + name = "_onMessageReceived", + descriptor = "(Lcom/google/firebase/messaging/RemoteMessage;)V", + startVarIndex = 1, + ) + ) } else { nextMethodVisitor } diff --git a/embrace-gradle-plugin/src/main/java/io/embrace/android/gradle/plugin/instrumentation/visitor/FirebaseMessagingServiceMethodAdapter.kt b/embrace-gradle-plugin/src/main/java/io/embrace/android/gradle/plugin/instrumentation/visitor/FirebaseMessagingServiceMethodAdapter.kt deleted file mode 100644 index fde43f804d..0000000000 --- a/embrace-gradle-plugin/src/main/java/io/embrace/android/gradle/plugin/instrumentation/visitor/FirebaseMessagingServiceMethodAdapter.kt +++ /dev/null @@ -1,29 +0,0 @@ -package io.embrace.android.gradle.plugin.instrumentation.visitor - -import org.objectweb.asm.MethodVisitor -import org.objectweb.asm.Opcodes - -/** - * Visits the onMessageReceived method and inserts a call to - * FirebaseSwazzledHooks._onMessageReceived at the very start of the method. - */ -class FirebaseMessagingServiceMethodAdapter( - api: Int, - methodVisitor: MethodVisitor? -) : MethodVisitor(api, methodVisitor) { - - override fun visitCode() { - // load local variable 'remoteMessage' and push it onto the operand stack - visitVarInsn(Opcodes.ALOAD, 1) - // invoke FirebaseSwazzledHooks._onMessageReceived() - visitMethodInsn( - Opcodes.INVOKESTATIC, - "io/embrace/android/embracesdk/fcm/swazzle/callback/com/android/fcm/FirebaseSwazzledHooks", - "_onMessageReceived", - "(Lcom/google/firebase/messaging/RemoteMessage;)V", - false - ) - // call super last to reduce chance of interference with other bytecode instrumentation - super.visitCode() - } -} diff --git a/embrace-gradle-plugin/src/main/java/io/embrace/android/gradle/plugin/instrumentation/visitor/InstrumentationTargetMethodVisitor.kt b/embrace-gradle-plugin/src/main/java/io/embrace/android/gradle/plugin/instrumentation/visitor/InstrumentationTargetMethodVisitor.kt new file mode 100644 index 0000000000..3b2682b600 --- /dev/null +++ b/embrace-gradle-plugin/src/main/java/io/embrace/android/gradle/plugin/instrumentation/visitor/InstrumentationTargetMethodVisitor.kt @@ -0,0 +1,38 @@ +package io.embrace.android.gradle.plugin.instrumentation.visitor + +import org.objectweb.asm.MethodVisitor +import org.objectweb.asm.Opcodes +import org.objectweb.asm.Type + +/** + * Visits a method that should be rewritten to include an API call to instrumentation + * and inserts a call to a static method at the very start. + */ +internal class InstrumentationTargetMethodVisitor( + api: Int, + methodVisitor: MethodVisitor?, + private val params: BytecodeMethodInsertionParams, +) : MethodVisitor(api, methodVisitor) { + + override fun visitCode() { + // count how many parameters are in the method descriptor + val paramCount = Type.getArgumentTypes(params.descriptor).size + + // load local variables and push onto the operand stack + repeat(paramCount) { + visitVarInsn(Opcodes.ALOAD, it + params.startVarIndex) + } + + // invoke the target method + visitMethodInsn( + Opcodes.INVOKESTATIC, + params.owner, + params.name, + params.descriptor, + false + ) + + // call super last to reduce chance of interference with other bytecode instrumentation + super.visitCode() + } +} diff --git a/embrace-gradle-plugin/src/main/java/io/embrace/android/gradle/plugin/instrumentation/visitor/OkHttpClassAdapter.kt b/embrace-gradle-plugin/src/main/java/io/embrace/android/gradle/plugin/instrumentation/visitor/OkHttpClassAdapter.kt index 4aac92acce..6b4fbd43eb 100644 --- a/embrace-gradle-plugin/src/main/java/io/embrace/android/gradle/plugin/instrumentation/visitor/OkHttpClassAdapter.kt +++ b/embrace-gradle-plugin/src/main/java/io/embrace/android/gradle/plugin/instrumentation/visitor/OkHttpClassAdapter.kt @@ -10,7 +10,6 @@ import org.objectweb.asm.MethodVisitor class OkHttpClassAdapter( api: Int, internal val nextClassVisitor: ClassVisitor?, - private val logger: (() -> String) -> Unit ) : ClassVisitor(api, nextClassVisitor) { companion object : ClassVisitFilter { @@ -28,13 +27,20 @@ class OkHttpClassAdapter( name: String, desc: String, signature: String?, - exceptions: Array? + exceptions: Array?, ): MethodVisitor? { val nextMethodVisitor = super.visitMethod(access, name, desc, signature, exceptions) return if (METHOD_NAME_BUILD == name && METHOD_DESC_BUILD == desc) { - logger { "OkHttpClassAdapter: instrumented method $name $desc" } - OkHttpMethodAdapter(api, nextMethodVisitor) + InstrumentationTargetMethodVisitor( + api = api, + methodVisitor = nextMethodVisitor, + params = BytecodeMethodInsertionParams( + owner = "io/embrace/android/embracesdk/okhttp3/swazzle/callback/okhttp3/OkHttpClient\$Builder", + name = "_preBuild", + descriptor = "(Lokhttp3/OkHttpClient\$Builder;)V", + ) + ) } else { nextMethodVisitor } diff --git a/embrace-gradle-plugin/src/main/java/io/embrace/android/gradle/plugin/instrumentation/visitor/OkHttpMethodAdapter.kt b/embrace-gradle-plugin/src/main/java/io/embrace/android/gradle/plugin/instrumentation/visitor/OkHttpMethodAdapter.kt deleted file mode 100644 index 698468d1b5..0000000000 --- a/embrace-gradle-plugin/src/main/java/io/embrace/android/gradle/plugin/instrumentation/visitor/OkHttpMethodAdapter.kt +++ /dev/null @@ -1,31 +0,0 @@ -package io.embrace.android.gradle.plugin.instrumentation.visitor - -import org.objectweb.asm.MethodVisitor -import org.objectweb.asm.Opcodes - -/** - * Visits OkHttp methods and inserts a call to OkHttpClient$Builder._preBuild at the very start - * of the method. - */ -class OkHttpMethodAdapter( - api: Int, - methodVisitor: MethodVisitor? -) : MethodVisitor(api, methodVisitor) { - - override fun visitCode() { - // load local variable 'this' and push it onto the operand stack - visitVarInsn(Opcodes.ALOAD, 0) - - // invoke Builder._preBuild(this) - visitMethodInsn( - Opcodes.INVOKESTATIC, - "io/embrace/android/embracesdk/okhttp3/swazzle/callback/okhttp3/OkHttpClient\$Builder", - "_preBuild", - "(Lokhttp3/OkHttpClient\$Builder;)V", - false - ) - - // call super last to reduce chance of interference with other bytecode instrumentation - super.visitCode() - } -} diff --git a/embrace-gradle-plugin/src/main/java/io/embrace/android/gradle/plugin/instrumentation/visitor/OnClickClassAdapter.kt b/embrace-gradle-plugin/src/main/java/io/embrace/android/gradle/plugin/instrumentation/visitor/OnClickClassAdapter.kt index 1b4ac8dec6..eda118b7dd 100644 --- a/embrace-gradle-plugin/src/main/java/io/embrace/android/gradle/plugin/instrumentation/visitor/OnClickClassAdapter.kt +++ b/embrace-gradle-plugin/src/main/java/io/embrace/android/gradle/plugin/instrumentation/visitor/OnClickClassAdapter.kt @@ -11,7 +11,6 @@ import org.objectweb.asm.MethodVisitor class OnClickClassAdapter( api: Int, internal val nextClassVisitor: ClassVisitor?, - private val logger: (() -> String) -> Unit ) : ClassVisitor(api, nextClassVisitor) { companion object : ClassVisitFilter { @@ -26,15 +25,21 @@ class OnClickClassAdapter( name: String, desc: String, signature: String?, - exceptions: Array? + exceptions: Array?, ): MethodVisitor? { val nextMethodVisitor = super.visitMethod(access, name, desc, signature, exceptions) return if (METHOD_NAME == name && METHOD_DESC == desc && !isStatic(access)) { - logger { "OnClickClassAdapter: instrumented method $name $desc" } - OnClickMethodAdapter(api, nextMethodVisitor) + InstrumentationTargetMethodVisitor( + api = api, + methodVisitor = nextMethodVisitor, + params = BytecodeMethodInsertionParams( + owner = "io/embrace/android/embracesdk/ViewSwazzledHooks\$OnClickListener", + name = "_preOnClick", + descriptor = "(Landroid/view/View\$OnClickListener;Landroid/view/View;)V", + ) + ) } else if (METHOD_DESC == desc && isStatic(access) && isSynthetic(access)) { - logger { "OnClickClassAdapter: instrumented synthetic method $name $desc" } OnClickStaticMethodAdapter(api, nextMethodVisitor) } else { nextMethodVisitor diff --git a/embrace-gradle-plugin/src/main/java/io/embrace/android/gradle/plugin/instrumentation/visitor/OnClickMethodAdapter.kt b/embrace-gradle-plugin/src/main/java/io/embrace/android/gradle/plugin/instrumentation/visitor/OnClickMethodAdapter.kt deleted file mode 100644 index 63d220c91d..0000000000 --- a/embrace-gradle-plugin/src/main/java/io/embrace/android/gradle/plugin/instrumentation/visitor/OnClickMethodAdapter.kt +++ /dev/null @@ -1,34 +0,0 @@ -package io.embrace.android.gradle.plugin.instrumentation.visitor - -import org.objectweb.asm.MethodVisitor -import org.objectweb.asm.Opcodes - -/** - * Visits an onClick method and inserts a call to ViewSwazzledHooks._preOnClick at the very start - * of the method. - */ -class OnClickMethodAdapter( - api: Int, - methodVisitor: MethodVisitor? -) : MethodVisitor(api, methodVisitor) { - - override fun visitCode() { - // load local variable 'this' and push it onto the operand stack - visitVarInsn(Opcodes.ALOAD, 0) - - // load local variable 'view' and push it onto the operand stack - visitVarInsn(Opcodes.ALOAD, 1) - - // invoke ViewSwazzledHooks$OnClickListener._preOnClick() - visitMethodInsn( - Opcodes.INVOKESTATIC, - "io/embrace/android/embracesdk/ViewSwazzledHooks\$OnClickListener", - "_preOnClick", - "(Landroid/view/View\$OnClickListener;Landroid/view/View;)V", - false - ) - - // call super last to reduce chance of interference with other bytecode instrumentation - super.visitCode() - } -} diff --git a/embrace-gradle-plugin/src/main/java/io/embrace/android/gradle/plugin/instrumentation/visitor/OnLongClickClassAdapter.kt b/embrace-gradle-plugin/src/main/java/io/embrace/android/gradle/plugin/instrumentation/visitor/OnLongClickClassAdapter.kt index 69a494e9c7..8d564c10f8 100644 --- a/embrace-gradle-plugin/src/main/java/io/embrace/android/gradle/plugin/instrumentation/visitor/OnLongClickClassAdapter.kt +++ b/embrace-gradle-plugin/src/main/java/io/embrace/android/gradle/plugin/instrumentation/visitor/OnLongClickClassAdapter.kt @@ -11,7 +11,6 @@ import org.objectweb.asm.MethodVisitor class OnLongClickClassAdapter( api: Int, internal val nextClassVisitor: ClassVisitor?, - private val logger: (() -> String) -> Unit ) : ClassVisitor(api, nextClassVisitor) { companion object : ClassVisitFilter { @@ -26,15 +25,21 @@ class OnLongClickClassAdapter( name: String, desc: String, signature: String?, - exceptions: Array? + exceptions: Array?, ): MethodVisitor? { val nextMethodVisitor = super.visitMethod(access, name, desc, signature, exceptions) return if (METHOD_NAME == name && METHOD_DESC == desc && !isStatic(access)) { - logger { "OnLongClickClassAdapter: instrumented method $name $desc" } - OnLongClickMethodAdapter(api, nextMethodVisitor) + InstrumentationTargetMethodVisitor( + api = api, + methodVisitor = nextMethodVisitor, + params = BytecodeMethodInsertionParams( + owner = "io/embrace/android/embracesdk/ViewSwazzledHooks\$OnLongClickListener", + name = "_preOnLongClick", + descriptor = "(Landroid/view/View\$OnLongClickListener;Landroid/view/View;)V", + ) + ) } else if (METHOD_DESC == desc && isStatic(access) && isSynthetic(access)) { - logger { "OnLongClickClassAdapter: instrumented synthetic method $name $desc" } OnLongClickStaticMethodAdapter(api, nextMethodVisitor) } else { nextMethodVisitor diff --git a/embrace-gradle-plugin/src/main/java/io/embrace/android/gradle/plugin/instrumentation/visitor/OnLongClickMethodAdapter.kt b/embrace-gradle-plugin/src/main/java/io/embrace/android/gradle/plugin/instrumentation/visitor/OnLongClickMethodAdapter.kt deleted file mode 100644 index 48197e79cb..0000000000 --- a/embrace-gradle-plugin/src/main/java/io/embrace/android/gradle/plugin/instrumentation/visitor/OnLongClickMethodAdapter.kt +++ /dev/null @@ -1,34 +0,0 @@ -package io.embrace.android.gradle.plugin.instrumentation.visitor - -import org.objectweb.asm.MethodVisitor -import org.objectweb.asm.Opcodes - -/** - * Visits an onLongClick method and inserts a call to ViewSwazzledHooks._preOnLongClick at - * the very start of the method. - */ -class OnLongClickMethodAdapter( - api: Int, - methodVisitor: MethodVisitor? -) : MethodVisitor(api, methodVisitor) { - - override fun visitCode() { - // load local variable 'this' and push it onto the operand stack - visitVarInsn(Opcodes.ALOAD, 0) - - // load local variable 'view' and push it onto the operand stack - visitVarInsn(Opcodes.ALOAD, 1) - - // invoke ViewSwazzledHooks$OnLongClickListener._preOnLongClick() - visitMethodInsn( - Opcodes.INVOKESTATIC, - "io/embrace/android/embracesdk/ViewSwazzledHooks\$OnLongClickListener", - "_preOnLongClick", - "(Landroid/view/View\$OnLongClickListener;Landroid/view/View;)V", - false - ) - - // call super last to reduce chance of interference with other bytecode instrumentation - super.visitCode() - } -} diff --git a/embrace-gradle-plugin/src/main/java/io/embrace/android/gradle/plugin/instrumentation/visitor/WebViewClientClassAdapter.kt b/embrace-gradle-plugin/src/main/java/io/embrace/android/gradle/plugin/instrumentation/visitor/WebViewClientClassAdapter.kt index 1ed5cbab67..5a7126cb0c 100644 --- a/embrace-gradle-plugin/src/main/java/io/embrace/android/gradle/plugin/instrumentation/visitor/WebViewClientClassAdapter.kt +++ b/embrace-gradle-plugin/src/main/java/io/embrace/android/gradle/plugin/instrumentation/visitor/WebViewClientClassAdapter.kt @@ -12,7 +12,6 @@ import org.objectweb.asm.Opcodes class WebViewClientClassAdapter( api: Int, internal val nextClassVisitor: ClassVisitor?, - private val logger: (() -> String) -> Unit ) : ClassVisitor(api, nextClassVisitor) { companion object : ClassVisitFilter { @@ -22,28 +21,33 @@ class WebViewClientClassAdapter( "(Landroid/webkit/WebView;Ljava/lang/String;Landroid/graphics/Bitmap;)V" override fun accept(classContext: ClassContext): Boolean { - if (classContext.currentClassData.superClasses.contains(CLASS_NAME)) { - return true - } - return false + return classContext.currentClassData.superClasses.contains(CLASS_NAME) } } - var hasOverride = false + private var hasOverride = false override fun visitMethod( access: Int, name: String, desc: String, signature: String?, - exceptions: Array? + exceptions: Array?, ): MethodVisitor? { val nextMethodVisitor = super.visitMethod(access, name, desc, signature, exceptions) return if (METHOD_NAME == name && METHOD_DESC == desc) { - logger { "WebViewClientClassAdapter: instrumented method $name $desc" } hasOverride = true - WebViewClientMethodAdapter(api, nextMethodVisitor) + InstrumentationTargetMethodVisitor( + api = api, + methodVisitor = nextMethodVisitor, + params = BytecodeMethodInsertionParams( + owner = "io/embrace/android/embracesdk/WebViewClientSwazzledHooks", + name = "_preOnPageStarted", + descriptor = "(Landroid/webkit/WebView;Ljava/lang/String;Landroid/graphics/Bitmap;)V", + startVarIndex = 1, + ) + ) } else { nextMethodVisitor } @@ -52,8 +56,6 @@ class WebViewClientClassAdapter( override fun visitEnd() { // add an override of onPageStarted if the class does not have one already. if (!hasOverride) { - logger { "WebViewClientClassAdapter: instrumented method $METHOD_NAME $METHOD_DESC (added override)" } - val nextMethodVisitor = super.visitMethod( Opcodes.ACC_PUBLIC, METHOD_NAME, diff --git a/embrace-gradle-plugin/src/main/java/io/embrace/android/gradle/plugin/instrumentation/visitor/WebViewClientMethodAdapter.kt b/embrace-gradle-plugin/src/main/java/io/embrace/android/gradle/plugin/instrumentation/visitor/WebViewClientMethodAdapter.kt deleted file mode 100644 index 6bc13b6ec2..0000000000 --- a/embrace-gradle-plugin/src/main/java/io/embrace/android/gradle/plugin/instrumentation/visitor/WebViewClientMethodAdapter.kt +++ /dev/null @@ -1,40 +0,0 @@ -package io.embrace.android.gradle.plugin.instrumentation.visitor - -import org.objectweb.asm.MethodVisitor -import org.objectweb.asm.Opcodes - -/** - * Visits the onPageStarted method and inserts a call to ViewSwazzledHooks._preOnPageStarted - * at the very start of the method. - */ -open class WebViewClientMethodAdapter( - api: Int, - methodVisitor: MethodVisitor? -) : MethodVisitor(api, methodVisitor) { - - override fun visitCode() { - instrumentOnPageStarted() - // call super last to reduce chance of interference with other bytecode instrumentation - super.visitCode() - } - - internal fun instrumentOnPageStarted() { - // load local variable 'view' and push it onto the operand stack - visitVarInsn(Opcodes.ALOAD, 1) - - // load local variable 'url' and push it onto the operand stack - visitVarInsn(Opcodes.ALOAD, 2) - - // load local variable 'favicon' and push it onto the operand stack - visitVarInsn(Opcodes.ALOAD, 3) - - // invoke WebViewClientSwazzledHooks._preOnPageStarted() - visitMethodInsn( - Opcodes.INVOKESTATIC, - "io/embrace/android/embracesdk/WebViewClientSwazzledHooks", - "_preOnPageStarted", - "(Landroid/webkit/WebView;Ljava/lang/String;Landroid/graphics/Bitmap;)V", - false - ) - } -} diff --git a/embrace-gradle-plugin/src/main/java/io/embrace/android/gradle/plugin/instrumentation/visitor/WebViewClientOverrideMethodAdapter.kt b/embrace-gradle-plugin/src/main/java/io/embrace/android/gradle/plugin/instrumentation/visitor/WebViewClientOverrideMethodAdapter.kt index be929c63fe..cf72cfc6a5 100644 --- a/embrace-gradle-plugin/src/main/java/io/embrace/android/gradle/plugin/instrumentation/visitor/WebViewClientOverrideMethodAdapter.kt +++ b/embrace-gradle-plugin/src/main/java/io/embrace/android/gradle/plugin/instrumentation/visitor/WebViewClientOverrideMethodAdapter.kt @@ -10,10 +10,23 @@ import org.objectweb.asm.Opcodes class WebViewClientOverrideMethodAdapter( api: Int, methodVisitor: MethodVisitor? -) : WebViewClientMethodAdapter(api, methodVisitor) { +) : MethodVisitor(api, methodVisitor) { override fun visitEnd() { - instrumentOnPageStarted() + // load local variable 'view' and push it onto the operand stack + visitVarInsn(Opcodes.ALOAD, 1) + // load local variable 'url' and push it onto the operand stack + visitVarInsn(Opcodes.ALOAD, 2) + // load local variable 'favicon' and push it onto the operand stack + visitVarInsn(Opcodes.ALOAD, 3) + // invoke WebViewClientSwazzledHooks._preOnPageStarted() + visitMethodInsn( + Opcodes.INVOKESTATIC, + "io/embrace/android/embracesdk/WebViewClientSwazzledHooks", + "_preOnPageStarted", + "(Landroid/webkit/WebView;Ljava/lang/String;Landroid/graphics/Bitmap;)V", + false + ) addSuperCall() super.visitEnd() visitInsn(Opcodes.RETURN) diff --git a/embrace-gradle-plugin/src/test/java/io/embrace/android/gradle/plugin/instrumentation/config/arch/InstrumentedConfigClassTest.kt b/embrace-gradle-plugin/src/test/java/io/embrace/android/gradle/plugin/instrumentation/config/arch/InstrumentedConfigClassTest.kt index ee782dc179..1f9ef7b26d 100644 --- a/embrace-gradle-plugin/src/test/java/io/embrace/android/gradle/plugin/instrumentation/config/arch/InstrumentedConfigClassTest.kt +++ b/embrace-gradle-plugin/src/test/java/io/embrace/android/gradle/plugin/instrumentation/config/arch/InstrumentedConfigClassTest.kt @@ -5,7 +5,6 @@ import io.embrace.android.gradle.plugin.instrumentation.config.BooleanReturnValu import io.embrace.android.gradle.plugin.instrumentation.config.IntReturnValueMethodVisitor import io.embrace.android.gradle.plugin.instrumentation.config.LongReturnValueMethodVisitor import io.embrace.android.gradle.plugin.instrumentation.config.MapReturnValueMethodVisitor -import io.embrace.android.gradle.plugin.instrumentation.config.StringListReturnValueMethodVisitor import io.embrace.android.gradle.plugin.instrumentation.config.StringReturnValueMethodVisitor import io.mockk.mockk import org.junit.Assert.assertEquals diff --git a/embrace-gradle-plugin/src/test/java/io/embrace/android/gradle/plugin/instrumentation/visitor/OkHttpClassAdapterTest.kt b/embrace-gradle-plugin/src/test/java/io/embrace/android/gradle/plugin/instrumentation/visitor/OkHttpClassAdapterTest.kt deleted file mode 100644 index 2dca27dd4e..0000000000 --- a/embrace-gradle-plugin/src/test/java/io/embrace/android/gradle/plugin/instrumentation/visitor/OkHttpClassAdapterTest.kt +++ /dev/null @@ -1,51 +0,0 @@ -package io.embrace.android.gradle.plugin.instrumentation.visitor - -import io.embrace.android.gradle.plugin.instrumentation.ASM_API_VERSION -import org.junit.Assert.assertFalse -import org.junit.Assert.assertTrue -import org.junit.Test -import org.objectweb.asm.Opcodes - -class OkHttpClassAdapterTest { - - private val adapter = OkHttpClassAdapter(ASM_API_VERSION, null) {} - - @Test - fun testCtorVisited() { - val visitor = adapter.visitMethod(Opcodes.ACC_PUBLIC, "", "()V", null, emptyArray()) - assertFalse(visitor is OkHttpMethodAdapter) - } - - @Test - fun testBuildVisited() { - val visitor = adapter.visitMethod( - Opcodes.ACC_PUBLIC, - "build", - "()Lokhttp3/OkHttpClient;", - null, - emptyArray() - ) - assertTrue(visitor is OkHttpMethodAdapter) - } - - @Test - fun testMethodNotVisited() { - var visitor = adapter.visitMethod( - Opcodes.ACC_PUBLIC, - "foo", - "()Lokhttp3/OkHttpClient;", - null, - emptyArray() - ) - assertFalse(visitor is OkHttpMethodAdapter) - - visitor = adapter.visitMethod( - Opcodes.ACC_PUBLIC, - "build", - "()Lokhttp3/OkHttpClient\$Builder;", - null, - emptyArray() - ) - assertFalse(visitor is OkHttpMethodAdapter) - } -} diff --git a/embrace-gradle-plugin/src/test/java/io/embrace/android/gradle/plugin/instrumentation/visitor/OkHttpConfigMethodAdapterTest.kt b/embrace-gradle-plugin/src/test/java/io/embrace/android/gradle/plugin/instrumentation/visitor/OkHttpConfigMethodAdapterTest.kt deleted file mode 100644 index 1476a14a59..0000000000 --- a/embrace-gradle-plugin/src/test/java/io/embrace/android/gradle/plugin/instrumentation/visitor/OkHttpConfigMethodAdapterTest.kt +++ /dev/null @@ -1,29 +0,0 @@ -package io.embrace.android.gradle.plugin.instrumentation.visitor - -import io.mockk.mockk -import io.mockk.verify -import org.junit.Test -import org.objectweb.asm.MethodVisitor -import org.objectweb.asm.Opcodes - -class OkHttpConfigMethodAdapterTest { - - @Test - fun visitCode() { - val visitor = mockk(relaxed = true) - OkHttpMethodAdapter(Opcodes.ASM6, visitor).visitCode() - verify(exactly = 1) { - with(visitor) { - visitVarInsn(Opcodes.ALOAD, 0) - visitMethodInsn( - Opcodes.INVOKESTATIC, - "io/embrace/android/embracesdk/okhttp3/swazzle/callback/okhttp3/OkHttpClient\$Builder", - "_preBuild", - "(Lokhttp3/OkHttpClient\$Builder;)V", - false - ) - visitCode() - } - } - } -} diff --git a/embrace-gradle-plugin/src/test/java/io/embrace/android/gradle/plugin/instrumentation/visitor/OnClickClassAdapterTest.kt b/embrace-gradle-plugin/src/test/java/io/embrace/android/gradle/plugin/instrumentation/visitor/OnClickClassAdapterTest.kt deleted file mode 100644 index 0104a2b9e6..0000000000 --- a/embrace-gradle-plugin/src/test/java/io/embrace/android/gradle/plugin/instrumentation/visitor/OnClickClassAdapterTest.kt +++ /dev/null @@ -1,47 +0,0 @@ -package io.embrace.android.gradle.plugin.instrumentation.visitor - -import io.embrace.android.gradle.plugin.instrumentation.ASM_API_VERSION -import org.junit.Assert.assertFalse -import org.junit.Assert.assertTrue -import org.junit.Test -import org.objectweb.asm.Opcodes - -class OnClickClassAdapterTest { - - private val adapter = OnClickClassAdapter(ASM_API_VERSION, null) {} - - @Test - fun testOnClickVisited() { - val visitor = adapter.visitMethod( - Opcodes.ACC_PUBLIC, - "onClick", - "(Landroid/view/View;)V", - null, - emptyArray() - ) - assertTrue(visitor is OnClickMethodAdapter) - } - - @Test - fun testStaticOnClickVisited() { - val access = Opcodes.ACC_STATIC.plus(Opcodes.ACC_SYNTHETIC) - val visitor = - adapter.visitMethod(access, "onClick", "(Landroid/view/View;)V", null, emptyArray()) - assertTrue(visitor is OnClickStaticMethodAdapter) - } - - @Test - fun testMethodNotVisited() { - var visitor = adapter.visitMethod(Opcodes.ACC_PUBLIC, "onClick", "()V", null, emptyArray()) - assertFalse(visitor is OnClickMethodAdapter) - - visitor = adapter.visitMethod( - Opcodes.ACC_PUBLIC, - "foo", - "(Landroid/view/View;)V", - null, - emptyArray() - ) - assertFalse(visitor is OnClickMethodAdapter) - } -} diff --git a/embrace-gradle-plugin/src/test/java/io/embrace/android/gradle/plugin/instrumentation/visitor/OnClickConfigMethodAdapterTest.kt b/embrace-gradle-plugin/src/test/java/io/embrace/android/gradle/plugin/instrumentation/visitor/OnClickConfigMethodAdapterTest.kt deleted file mode 100644 index 9dd6a7608e..0000000000 --- a/embrace-gradle-plugin/src/test/java/io/embrace/android/gradle/plugin/instrumentation/visitor/OnClickConfigMethodAdapterTest.kt +++ /dev/null @@ -1,30 +0,0 @@ -package io.embrace.android.gradle.plugin.instrumentation.visitor - -import io.mockk.mockk -import io.mockk.verify -import org.junit.Test -import org.objectweb.asm.MethodVisitor -import org.objectweb.asm.Opcodes - -class OnClickConfigMethodAdapterTest { - - @Test - fun visitCode() { - val visitor = mockk(relaxed = true) - OnClickMethodAdapter(Opcodes.ASM6, visitor).visitCode() - verify(exactly = 1) { - with(visitor) { - visitVarInsn(Opcodes.ALOAD, 0) - visitVarInsn(Opcodes.ALOAD, 1) - visitMethodInsn( - Opcodes.INVOKESTATIC, - "io/embrace/android/embracesdk/ViewSwazzledHooks\$OnClickListener", - "_preOnClick", - "(Landroid/view/View\$OnClickListener;Landroid/view/View;)V", - false - ) - visitCode() - } - } - } -} diff --git a/embrace-gradle-plugin/src/test/java/io/embrace/android/gradle/plugin/instrumentation/visitor/OnClickStaticConfigMethodAdapterTest.kt b/embrace-gradle-plugin/src/test/java/io/embrace/android/gradle/plugin/instrumentation/visitor/OnClickStaticConfigMethodAdapterTest.kt deleted file mode 100644 index 35163cec65..0000000000 --- a/embrace-gradle-plugin/src/test/java/io/embrace/android/gradle/plugin/instrumentation/visitor/OnClickStaticConfigMethodAdapterTest.kt +++ /dev/null @@ -1,30 +0,0 @@ -package io.embrace.android.gradle.plugin.instrumentation.visitor - -import io.mockk.mockk -import io.mockk.verify -import org.junit.Test -import org.objectweb.asm.MethodVisitor -import org.objectweb.asm.Opcodes - -class OnClickStaticConfigMethodAdapterTest { - - @Test - fun visitCode() { - val visitor = mockk(relaxed = true) - OnClickStaticMethodAdapter(Opcodes.ASM6, visitor).visitCode() - verify(exactly = 1) { - with(visitor) { - visitInsn(Opcodes.ACONST_NULL) - visitVarInsn(Opcodes.ALOAD, 0) - visitMethodInsn( - Opcodes.INVOKESTATIC, - "io/embrace/android/embracesdk/ViewSwazzledHooks\$OnClickListener", - "_preOnClick", - "(Landroid/view/View\$OnClickListener;Landroid/view/View;)V", - false - ) - visitCode() - } - } - } -} diff --git a/embrace-gradle-plugin/src/test/java/io/embrace/android/gradle/plugin/instrumentation/visitor/OnLongClickClassAdapterTest.kt b/embrace-gradle-plugin/src/test/java/io/embrace/android/gradle/plugin/instrumentation/visitor/OnLongClickClassAdapterTest.kt deleted file mode 100644 index e77d961808..0000000000 --- a/embrace-gradle-plugin/src/test/java/io/embrace/android/gradle/plugin/instrumentation/visitor/OnLongClickClassAdapterTest.kt +++ /dev/null @@ -1,48 +0,0 @@ -package io.embrace.android.gradle.plugin.instrumentation.visitor - -import io.embrace.android.gradle.plugin.instrumentation.ASM_API_VERSION -import org.junit.Assert.assertFalse -import org.junit.Assert.assertTrue -import org.junit.Test -import org.objectweb.asm.Opcodes - -class OnLongClickClassAdapterTest { - - private val adapter = OnLongClickClassAdapter(ASM_API_VERSION, null) {} - - @Test - fun testOnLongClickVisited() { - val visitor = adapter.visitMethod( - Opcodes.ACC_PUBLIC, - "onLongClick", - "(Landroid/view/View;)Z", - null, - emptyArray() - ) - assertTrue(visitor is OnLongClickMethodAdapter) - } - - @Test - fun testStaticOnLongClickVisited() { - val access = Opcodes.ACC_STATIC.plus(Opcodes.ACC_SYNTHETIC) - val visitor = - adapter.visitMethod(access, "onLongClick", "(Landroid/view/View;)Z", null, emptyArray()) - assertTrue(visitor is OnLongClickStaticMethodAdapter) - } - - @Test - fun testMethodNotVisited() { - var visitor = - adapter.visitMethod(Opcodes.ACC_PUBLIC, "onLongClick", "()V", null, emptyArray()) - assertFalse(visitor is OnLongClickMethodAdapter) - - visitor = adapter.visitMethod( - Opcodes.ACC_PUBLIC, - "foo", - "(Landroid/view/View;)Z", - null, - emptyArray() - ) - assertFalse(visitor is OnLongClickMethodAdapter) - } -} diff --git a/embrace-gradle-plugin/src/test/java/io/embrace/android/gradle/plugin/instrumentation/visitor/OnLongClickConfigMethodAdapterTest.kt b/embrace-gradle-plugin/src/test/java/io/embrace/android/gradle/plugin/instrumentation/visitor/OnLongClickConfigMethodAdapterTest.kt deleted file mode 100644 index 1392360173..0000000000 --- a/embrace-gradle-plugin/src/test/java/io/embrace/android/gradle/plugin/instrumentation/visitor/OnLongClickConfigMethodAdapterTest.kt +++ /dev/null @@ -1,30 +0,0 @@ -package io.embrace.android.gradle.plugin.instrumentation.visitor - -import io.mockk.mockk -import io.mockk.verify -import org.junit.Test -import org.objectweb.asm.MethodVisitor -import org.objectweb.asm.Opcodes - -class OnLongClickConfigMethodAdapterTest { - - @Test - fun visitCode() { - val visitor = mockk(relaxed = true) - OnLongClickMethodAdapter(Opcodes.ASM6, visitor).visitCode() - verify(exactly = 1) { - with(visitor) { - visitVarInsn(Opcodes.ALOAD, 0) - visitVarInsn(Opcodes.ALOAD, 1) - visitMethodInsn( - Opcodes.INVOKESTATIC, - "io/embrace/android/embracesdk/ViewSwazzledHooks\$OnLongClickListener", - "_preOnLongClick", - "(Landroid/view/View\$OnLongClickListener;Landroid/view/View;)V", - false - ) - visitCode() - } - } - } -} diff --git a/embrace-gradle-plugin/src/test/java/io/embrace/android/gradle/plugin/instrumentation/visitor/OnLongClickStaticConfigMethodAdapterTest.kt b/embrace-gradle-plugin/src/test/java/io/embrace/android/gradle/plugin/instrumentation/visitor/OnLongClickStaticConfigMethodAdapterTest.kt deleted file mode 100644 index 75d814367c..0000000000 --- a/embrace-gradle-plugin/src/test/java/io/embrace/android/gradle/plugin/instrumentation/visitor/OnLongClickStaticConfigMethodAdapterTest.kt +++ /dev/null @@ -1,30 +0,0 @@ -package io.embrace.android.gradle.plugin.instrumentation.visitor - -import io.mockk.mockk -import io.mockk.verify -import org.junit.Test -import org.objectweb.asm.MethodVisitor -import org.objectweb.asm.Opcodes - -class OnLongClickStaticConfigMethodAdapterTest { - - @Test - fun visitCode() { - val visitor = mockk(relaxed = true) - OnLongClickStaticMethodAdapter(Opcodes.ASM6, visitor).visitCode() - verify(exactly = 1) { - with(visitor) { - visitInsn(Opcodes.ACONST_NULL) - visitVarInsn(Opcodes.ALOAD, 0) - visitMethodInsn( - Opcodes.INVOKESTATIC, - "io/embrace/android/embracesdk/ViewSwazzledHooks\$OnLongClickListener", - "_preOnLongClick", - "(Landroid/view/View\$OnLongClickListener;Landroid/view/View;)V", - false - ) - visitCode() - } - } - } -} diff --git a/embrace-gradle-plugin/src/test/java/io/embrace/android/gradle/plugin/instrumentation/visitor/WebViewClientClassAdapterTest.kt b/embrace-gradle-plugin/src/test/java/io/embrace/android/gradle/plugin/instrumentation/visitor/WebViewClientClassAdapterTest.kt deleted file mode 100644 index 4d4a2a6996..0000000000 --- a/embrace-gradle-plugin/src/test/java/io/embrace/android/gradle/plugin/instrumentation/visitor/WebViewClientClassAdapterTest.kt +++ /dev/null @@ -1,45 +0,0 @@ -package io.embrace.android.gradle.plugin.instrumentation.visitor - -import io.embrace.android.gradle.plugin.instrumentation.ASM_API_VERSION -import org.junit.Assert.assertFalse -import org.junit.Assert.assertTrue -import org.junit.Test -import org.objectweb.asm.Opcodes - -class WebViewClientClassAdapterTest { - - private val adapter = WebViewClientClassAdapter(ASM_API_VERSION, null) {} - - @Test - fun testOnPageStartedVisited() { - val visitor = adapter.visitMethod( - Opcodes.ACC_PUBLIC, - "onPageStarted", - "(Landroid/webkit/WebView;Ljava/lang/String;Landroid/graphics/Bitmap;)V", - null, - emptyArray() - ) - assertTrue(visitor is WebViewClientMethodAdapter) - } - - @Test - fun testMethodNotVisited() { - var visitor = adapter.visitMethod( - Opcodes.ACC_PUBLIC, - "onPageStarted", - "(Landroid/webkit/WebView;Ljava/lang/Boolean;Landroid/graphics/Bitmap;)V", - null, - emptyArray() - ) - assertFalse(visitor is WebViewClientMethodAdapter) - - visitor = adapter.visitMethod( - Opcodes.ACC_PUBLIC, - "onPageStart", - "(Landroid/webkit/WebView;Ljava/lang/String;Landroid/graphics/Bitmap;)V", - null, - emptyArray() - ) - assertFalse(visitor is WebViewClientMethodAdapter) - } -} diff --git a/embrace-gradle-plugin/src/test/java/io/embrace/android/gradle/plugin/instrumentation/visitor/WebViewClientMethodAdapterTest.kt b/embrace-gradle-plugin/src/test/java/io/embrace/android/gradle/plugin/instrumentation/visitor/WebViewClientMethodAdapterTest.kt deleted file mode 100644 index c532d0ddc8..0000000000 --- a/embrace-gradle-plugin/src/test/java/io/embrace/android/gradle/plugin/instrumentation/visitor/WebViewClientMethodAdapterTest.kt +++ /dev/null @@ -1,30 +0,0 @@ -package io.embrace.android.gradle.plugin.instrumentation.visitor - -import io.mockk.mockk -import io.mockk.verify -import org.junit.Test -import org.objectweb.asm.MethodVisitor -import org.objectweb.asm.Opcodes - -class WebViewClientMethodAdapterTest { - - @Test - fun visitCode() { - val visitor = mockk(relaxed = true) - WebViewClientMethodAdapter(Opcodes.ASM6, visitor).visitCode() - verify(exactly = 1) { - with(visitor) { - visitVarInsn(Opcodes.ALOAD, 1) - visitVarInsn(Opcodes.ALOAD, 2) - visitVarInsn(Opcodes.ALOAD, 3) - visitMethodInsn( - Opcodes.INVOKESTATIC, - "io/embrace/android/embracesdk/WebViewClientSwazzledHooks", - "_preOnPageStarted", - "(Landroid/webkit/WebView;Ljava/lang/String;Landroid/graphics/Bitmap;)V", - false - ) - } - } - } -} diff --git a/embrace-gradle-plugin/src/test/java/io/embrace/android/gradle/plugin/instrumentation/visitor/WebViewClientOverrideConfigMethodAdapterTest.kt b/embrace-gradle-plugin/src/test/java/io/embrace/android/gradle/plugin/instrumentation/visitor/WebViewClientOverrideConfigMethodAdapterTest.kt deleted file mode 100644 index 78abae800c..0000000000 --- a/embrace-gradle-plugin/src/test/java/io/embrace/android/gradle/plugin/instrumentation/visitor/WebViewClientOverrideConfigMethodAdapterTest.kt +++ /dev/null @@ -1,30 +0,0 @@ -package io.embrace.android.gradle.plugin.instrumentation.visitor - -import io.mockk.mockk -import io.mockk.verify -import org.junit.Test -import org.objectweb.asm.MethodVisitor -import org.objectweb.asm.Opcodes - -class WebViewClientOverrideConfigMethodAdapterTest { - - @Test - fun visitCode() { - val visitor = mockk(relaxed = true) - WebViewClientOverrideMethodAdapter(Opcodes.ASM6, visitor).visitCode() - verify(exactly = 1) { - with(visitor) { - visitVarInsn(Opcodes.ALOAD, 1) - visitVarInsn(Opcodes.ALOAD, 2) - visitVarInsn(Opcodes.ALOAD, 3) - visitMethodInsn( - Opcodes.INVOKESTATIC, - "io/embrace/android/embracesdk/WebViewClientSwazzledHooks", - "_preOnPageStarted", - "(Landroid/webkit/WebView;Ljava/lang/String;Landroid/graphics/Bitmap;)V", - false - ) - } - } - } -}