/* * This file is part of LSPosed. * * LSPosed is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * LSPosed is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with LSPosed. If not, see . * * Copyright (C) 2021 - 2022 LSPosed Contributors */ import com.android.build.api.instrumentation.AsmClassVisitorFactory import com.android.build.api.instrumentation.ClassContext import com.android.build.api.instrumentation.ClassData import com.android.build.api.instrumentation.InstrumentationParameters import com.android.build.api.instrumentation.InstrumentationScope import com.android.build.api.instrumentation.FramesComputationMode import org.objectweb.asm.ClassVisitor import org.objectweb.asm.MethodVisitor import org.objectweb.asm.Opcodes import org.objectweb.asm.Type val apiCode: Int by rootProject.extra val verName: String by rootProject.extra val verCode: Int by rootProject.extra plugins { id("com.android.library") } android { namespace = "org.lsposed.lspd.core" buildFeatures { androidResources = false } defaultConfig { consumerProguardFiles("proguard-rules.pro") buildConfigField("int", "API_CODE", "$apiCode") } buildTypes { release { isMinifyEnabled = true proguardFiles("proguard-rules.pro") } } } copy { from("src/main/jni/template/") { expand("VERSION_CODE" to "$verCode", "VERSION_NAME" to verName) } into("src/main/jni/src/") } abstract class ExampleClassVisitorFactory : AsmClassVisitorFactory { override fun createClassVisitor( classContext: ClassContext, nextClassVisitor: ClassVisitor ): ClassVisitor { return object : ClassVisitor(Opcodes.ASM9, nextClassVisitor) { override fun visit( version: Int, access: Int, name: String?, signature: String?, superName: String?, interfaces: Array? ) { val newSuperName = "xposed/dummy/X${superName?.substringAfterLast('/')}SuperClass" println("replace super class of $name to $newSuperName") super.visit( version, access, name, signature, newSuperName, interfaces ) } override fun visitMethod( access: Int, name: String?, descriptor: String?, signature: String?, exceptions: Array? ): MethodVisitor { return object : MethodVisitor( Opcodes.ASM9, super.visitMethod( access, name, descriptor, signature, exceptions ) ) { override fun visitVarInsn(opcode: Int, `var`: Int) { } override fun visitInsn(opcode: Int) { if (opcode != Opcodes.ACONST_NULL) { super.visitInsn(opcode) } } override fun visitMaxs(maxStack: Int, maxLocals: Int) { super.visitMaxs( if (maxLocals > maxStack) maxLocals else maxStack, maxLocals ) } override fun visitMethodInsn( opcode: Int, owner: String?, name: String?, instDescriptor: String?, isInterface: Boolean ) { if (opcode == Opcodes.INVOKESPECIAL) { for (i in 0 .. Type.getMethodType(descriptor).argumentTypes.size) { println("load param $i") super.visitVarInsn(Opcodes.ALOAD, i) } val newOwner = "xposed/dummy/X${owner?.substringAfterLast('/')}SuperClass" println("replace method call of $owner.$name$instDescriptor to $newOwner.$name$descriptor") super.visitMethodInsn( opcode, newOwner, name, descriptor, isInterface ) } else { super.visitMethodInsn( opcode, owner, name, instDescriptor, isInterface ) } } } } } } override fun isInstrumentable(classData: ClassData): Boolean { return classData.className.startsWith("android.content.res.Xposed") } } androidComponents.onVariants { variant -> variant.instrumentation.transformClassesWith( ExampleClassVisitorFactory::class.java, InstrumentationScope.PROJECT ) {} variant.instrumentation.setAsmFramesComputationMode(FramesComputationMode.COPY_FRAMES) } dependencies { implementation("org.apache.commons:commons-lang3:3.12.0") implementation("de.upb.cs.swt:axml:2.1.3") compileOnly("androidx.annotation:annotation:1.5.0") compileOnly(projects.hiddenapi.stubs) implementation(projects.hiddenapi.bridge) implementation(projects.services.daemonService) implementation(projects.services.managerService) }