From 85c83e0d34cf3853d8c4507ed0292ea47e9522ef Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Sun, 28 Apr 2024 02:45:48 +0200 Subject: [PATCH] fix: Modernize some APIs --- api/revanced-patcher.api | 52 ++++++++----- .../kotlin/app/revanced/patcher/Patcher.kt | 16 ++-- .../app/revanced/patcher/PatcherContext.kt | 8 +- .../patcher/fingerprint/MethodFingerprint.kt | 10 ++- .../patcher/patch/BytecodePatchContext.kt | 40 ++++------ .../app/revanced/patcher/patch/Patch.kt | 14 ++-- .../patcher/patch/ResourcePatchContext.kt | 2 +- .../app/revanced/patcher/util/ClassMerger.kt | 2 +- .../revanced/patcher/util/MethodNavigator.kt | 78 +++++++++++++++++++ .../revanced/patcher/util/ProxyClassList.kt | 13 +--- .../patcher/util/method/MethodWalker.kt | 60 -------------- .../revanced/patcher/util/proxy/ClassProxy.kt | 1 + .../app/revanced/patcher/PatcherTest.kt | 8 +- 13 files changed, 165 insertions(+), 139 deletions(-) create mode 100644 src/main/kotlin/app/revanced/patcher/util/MethodNavigator.kt delete mode 100644 src/main/kotlin/app/revanced/patcher/util/method/MethodWalker.kt diff --git a/api/revanced-patcher.api b/api/revanced-patcher.api index 88c2eda4..65d10e97 100644 --- a/api/revanced-patcher.api +++ b/api/revanced-patcher.api @@ -102,19 +102,15 @@ public final class app/revanced/patcher/extensions/InstructionExtensions { public final fun replaceInstructions (Lcom/android/tools/smali/dexlib2/builder/MutableMethodImplementation;ILjava/util/List;)V } -public abstract interface annotation class app/revanced/patcher/fingerprint/FuzzyPatternScanMethod : java/lang/annotation/Annotation { - public abstract fun threshold ()I -} - public final class app/revanced/patcher/fingerprint/MethodFingerprint { public fun ()V - public final fun getFuzzyPatternScanMethod ()Lapp/revanced/patcher/fingerprint/FuzzyPatternScanMethod; public final fun getResult ()Lapp/revanced/patcher/fingerprint/MethodFingerprintResult; public final fun resolve (Lapp/revanced/patcher/patch/BytecodePatchContext;Lcom/android/tools/smali/dexlib2/iface/ClassDef;)Z public final fun resolve (Lapp/revanced/patcher/patch/BytecodePatchContext;Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/iface/ClassDef;)Z } public final class app/revanced/patcher/fingerprint/MethodFingerprintBuilder { + public fun ()V public final fun accessFlags (I)V public final fun accessFlags (Lcom/android/tools/smali/dexlib2/AccessFlags;)V public final fun custom (Lkotlin/jvm/functions/Function2;)V @@ -126,8 +122,10 @@ public final class app/revanced/patcher/fingerprint/MethodFingerprintBuilder { } public final class app/revanced/patcher/fingerprint/MethodFingerprintKt { - public static final fun methodFingerprint (Lapp/revanced/patcher/patch/BytecodePatchBuilder;Lkotlin/jvm/functions/Function1;)Lapp/revanced/patcher/fingerprint/MethodFingerprint; - public static final fun methodFingerprint (Lkotlin/jvm/functions/Function1;)Lapp/revanced/patcher/fingerprint/MethodFingerprint; + public static final fun methodFingerprint (ILkotlin/jvm/functions/Function1;)Lapp/revanced/patcher/fingerprint/MethodFingerprint; + public static final fun methodFingerprint (Lapp/revanced/patcher/patch/BytecodePatchBuilder;ILkotlin/jvm/functions/Function1;)Lapp/revanced/patcher/fingerprint/MethodFingerprint; + public static synthetic fun methodFingerprint$default (ILkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lapp/revanced/patcher/fingerprint/MethodFingerprint; + public static synthetic fun methodFingerprint$default (Lapp/revanced/patcher/patch/BytecodePatchBuilder;ILkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lapp/revanced/patcher/fingerprint/MethodFingerprint; public static final fun resolve (Ljava/lang/Iterable;Lapp/revanced/patcher/patch/BytecodePatchContext;Ljava/lang/Iterable;)V } @@ -173,13 +171,13 @@ public final class app/revanced/patcher/patch/BytecodePatchBuilder : app/revance } public final class app/revanced/patcher/patch/BytecodePatchContext : app/revanced/patcher/patch/PatchContext { - public final fun findClass (Ljava/lang/String;)Lapp/revanced/patcher/util/proxy/ClassProxy; - public final fun findClass (Lkotlin/jvm/functions/Function1;)Lapp/revanced/patcher/util/proxy/ClassProxy; + public final fun classBy (Lkotlin/jvm/functions/Function1;)Lapp/revanced/patcher/util/proxy/ClassProxy; + public final fun classByType (Ljava/lang/String;)Lapp/revanced/patcher/util/proxy/ClassProxy; public synthetic fun get ()Ljava/lang/Object; public fun get ()Ljava/util/Set; public final fun getClasses ()Lapp/revanced/patcher/util/ProxyClassList; + public final fun navigate (Lcom/android/tools/smali/dexlib2/iface/Method;)Lapp/revanced/patcher/util/MethodNavigator; public final fun proxy (Lcom/android/tools/smali/dexlib2/iface/ClassDef;)Lapp/revanced/patcher/util/proxy/ClassProxy; - public final fun toMethodWalker (Lcom/android/tools/smali/dexlib2/iface/Method;)Lapp/revanced/patcher/util/method/MethodWalker; } public final class app/revanced/patcher/patch/Option { @@ -486,33 +484,51 @@ public final class app/revanced/patcher/util/Document : java/io/Closeable, org/w public fun setXmlVersion (Ljava/lang/String;)V } -public final class app/revanced/patcher/util/ProxyClassList : java/util/Set, kotlin/jvm/internal/markers/KMutableSet { - public final fun add (Lapp/revanced/patcher/util/proxy/ClassProxy;)Z +public final class app/revanced/patcher/util/MethodNavigator { + public final fun at ([I)Lapp/revanced/patcher/util/MethodNavigator; + public final fun getReference ()Lcom/android/tools/smali/dexlib2/iface/reference/MethodReference; + public final fun immutable ()Lcom/android/tools/smali/dexlib2/iface/Method; + public final fun mutable ()Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod; + public final fun setReference (Lcom/android/tools/smali/dexlib2/iface/reference/MethodReference;)V +} + +public final class app/revanced/patcher/util/ProxyClassList : java/util/List, kotlin/jvm/internal/markers/KMutableList { + public fun add (ILcom/android/tools/smali/dexlib2/iface/ClassDef;)V + public synthetic fun add (ILjava/lang/Object;)V public fun add (Lcom/android/tools/smali/dexlib2/iface/ClassDef;)Z public synthetic fun add (Ljava/lang/Object;)Z + public fun addAll (ILjava/util/Collection;)Z public fun addAll (Ljava/util/Collection;)Z public fun clear ()V public fun contains (Lcom/android/tools/smali/dexlib2/iface/ClassDef;)Z public final fun contains (Ljava/lang/Object;)Z public fun containsAll (Ljava/util/Collection;)Z + public fun get (I)Lcom/android/tools/smali/dexlib2/iface/ClassDef; + public synthetic fun get (I)Ljava/lang/Object; public fun getSize ()I + public fun indexOf (Lcom/android/tools/smali/dexlib2/iface/ClassDef;)I + public final fun indexOf (Ljava/lang/Object;)I public fun isEmpty ()Z public fun iterator ()Ljava/util/Iterator; + public fun lastIndexOf (Lcom/android/tools/smali/dexlib2/iface/ClassDef;)I + public final fun lastIndexOf (Ljava/lang/Object;)I + public fun listIterator ()Ljava/util/ListIterator; + public fun listIterator (I)Ljava/util/ListIterator; + public final fun remove (I)Lcom/android/tools/smali/dexlib2/iface/ClassDef; + public synthetic fun remove (I)Ljava/lang/Object; public fun remove (Lcom/android/tools/smali/dexlib2/iface/ClassDef;)Z public final fun remove (Ljava/lang/Object;)Z public fun removeAll (Ljava/util/Collection;)Z + public fun removeAt (I)Lcom/android/tools/smali/dexlib2/iface/ClassDef; public fun retainAll (Ljava/util/Collection;)Z + public fun set (ILcom/android/tools/smali/dexlib2/iface/ClassDef;)Lcom/android/tools/smali/dexlib2/iface/ClassDef; + public synthetic fun set (ILjava/lang/Object;)Ljava/lang/Object; public final fun size ()I + public fun subList (II)Ljava/util/List; public fun toArray ()[Ljava/lang/Object; public fun toArray ([Ljava/lang/Object;)[Ljava/lang/Object; } -public final class app/revanced/patcher/util/method/MethodWalker { - public final fun getMethod ()Lcom/android/tools/smali/dexlib2/iface/Method; - public final fun nextMethod (IZ)Lapp/revanced/patcher/util/method/MethodWalker; - public static synthetic fun nextMethod$default (Lapp/revanced/patcher/util/method/MethodWalker;IZILjava/lang/Object;)Lapp/revanced/patcher/util/method/MethodWalker; -} - public final class app/revanced/patcher/util/proxy/ClassProxy { public final fun getImmutableClass ()Lcom/android/tools/smali/dexlib2/iface/ClassDef; public final fun getMutableClass ()Lapp/revanced/patcher/util/proxy/mutableTypes/MutableClass; diff --git a/src/main/kotlin/app/revanced/patcher/Patcher.kt b/src/main/kotlin/app/revanced/patcher/Patcher.kt index 5368f09a..581b5f51 100644 --- a/src/main/kotlin/app/revanced/patcher/Patcher.kt +++ b/src/main/kotlin/app/revanced/patcher/Patcher.kt @@ -38,7 +38,7 @@ class Patcher( val context = PatcherContext(config) init { - context.resourceContext.decodeResources(ResourcePatchContext.ResourceMode.NONE) + context.resourcePatchContext.decodeResources(ResourcePatchContext.ResourceMode.NONE) } /** @@ -85,7 +85,7 @@ class Patcher( // Check, if integrations need to be merged. for (patch in patches) if (patch.anyRecursively { it.requiresIntegrations }) { - context.bytecodeContext.integrations.merge = true + context.bytecodePatchContext.integrations.merge = true break } } @@ -94,7 +94,7 @@ class Patcher( // region Add integrations - context.bytecodeContext.integrations.addAll(integrations) + context.bytecodePatchContext.integrations.addAll(integrations) // endregion } @@ -140,13 +140,13 @@ class Patcher( }.also { executedPatches[this] = it } } - if (context.bytecodeContext.integrations.merge) context.bytecodeContext.integrations.flush() + if (context.bytecodePatchContext.integrations.merge) context.bytecodePatchContext.integrations.flush() - LookupMap.initializeLookupMaps(context.bytecodeContext) + LookupMap.initializeLookupMaps(context.bytecodePatchContext) // Prevent from decoding the app manifest twice if it is not needed. if (config.resourceMode != ResourcePatchContext.ResourceMode.NONE) { - context.resourceContext.decodeResources(config.resourceMode) + context.resourcePatchContext.decodeResources(config.resourceMode) } logger.info("Executing patches") @@ -212,8 +212,8 @@ class Patcher( @OptIn(InternalApi::class) override fun get() = PatcherResult( - context.bytecodeContext.get(), - context.resourceContext.get(), + context.bytecodePatchContext.get(), + context.resourcePatchContext.get(), ) } diff --git a/src/main/kotlin/app/revanced/patcher/PatcherContext.kt b/src/main/kotlin/app/revanced/patcher/PatcherContext.kt index 3934d29d..f6fbf89f 100644 --- a/src/main/kotlin/app/revanced/patcher/PatcherContext.kt +++ b/src/main/kotlin/app/revanced/patcher/PatcherContext.kt @@ -29,12 +29,12 @@ class PatcherContext internal constructor(config: PatcherConfig) { internal val allPatches = mutableSetOf>() /** - * A context for the patcher containing the current state of the resources. + * A context for patches containing the current state of the resources. */ - internal val resourceContext = ResourcePatchContext(packageMetadata, config) + internal val resourcePatchContext = ResourcePatchContext(packageMetadata, config) /** - * A context for the patcher containing the current state of the bytecode. + * A context for patches containing the current state of the bytecode. */ - internal val bytecodeContext = BytecodePatchContext(config) + internal val bytecodePatchContext = BytecodePatchContext(config) } diff --git a/src/main/kotlin/app/revanced/patcher/fingerprint/MethodFingerprint.kt b/src/main/kotlin/app/revanced/patcher/fingerprint/MethodFingerprint.kt index 9b95d057..c36ac202 100644 --- a/src/main/kotlin/app/revanced/patcher/fingerprint/MethodFingerprint.kt +++ b/src/main/kotlin/app/revanced/patcher/fingerprint/MethodFingerprint.kt @@ -1,3 +1,5 @@ +@file:Suppress("unused", "MemberVisibilityCanBePrivate") + package app.revanced.patcher.fingerprint import app.revanced.patcher.fingerprint.LookupMap.Maps.appendParameters @@ -326,7 +328,6 @@ fun Iterable.resolve( * @param context The [BytecodePatchContext] this [MethodFingerprintResult] is attached to, to create proxies. */ -@Suppress("MemberVisibilityCanBePrivate") class MethodFingerprintResult( val method: Method, val classDef: ClassDef, @@ -339,8 +340,11 @@ class MethodFingerprintResult( * Please note, this method allocates a [ClassProxy]. * Use [classDef] where possible. */ - @Suppress("MemberVisibilityCanBePrivate") - val mutableClass by lazy { context.proxy(classDef).mutableClass } + val mutableClass by lazy { + with(context) { + classDef.proxy().mutableClass + } + } /** * Returns a mutable clone of [method] diff --git a/src/main/kotlin/app/revanced/patcher/patch/BytecodePatchContext.kt b/src/main/kotlin/app/revanced/patcher/patch/BytecodePatchContext.kt index 7e5c084c..88ed0b04 100644 --- a/src/main/kotlin/app/revanced/patcher/patch/BytecodePatchContext.kt +++ b/src/main/kotlin/app/revanced/patcher/patch/BytecodePatchContext.kt @@ -5,8 +5,8 @@ import app.revanced.patcher.PatcherConfig import app.revanced.patcher.PatcherContext import app.revanced.patcher.PatcherResult import app.revanced.patcher.util.ClassMerger.merge +import app.revanced.patcher.util.MethodNavigator import app.revanced.patcher.util.ProxyClassList -import app.revanced.patcher.util.method.MethodWalker import app.revanced.patcher.util.proxy.ClassProxy import com.android.tools.smali.dexlib2.Opcodes import com.android.tools.smali.dexlib2.iface.ClassDef @@ -46,7 +46,7 @@ class BytecodePatchContext internal constructor(private val config: PatcherConfi BasicDexFileNamer(), null, null, - ).also { opcodes = it.opcodes }.classes.toMutableSet(), + ).also { opcodes = it.opcodes }.classes.toMutableList(), ) } @@ -56,44 +56,36 @@ class BytecodePatchContext internal constructor(private val config: PatcherConfi internal val integrations = Integrations() /** - * Find a class by a given class name. + * Find a class by its type using a contains check. * - * @param className The name of the class. - * @return A proxy for the first class that matches the class name. + * @param type The type of the class. + * @return A proxy for the first class that matches the type. */ - fun findClass(className: String) = findClass { it.type.contains(className) } + fun classByType(type: String) = classBy { type in it.type } /** - * Find a class by a given predicate. + * Find a class with a predicate. * * @param predicate A predicate to match the class. * @return A proxy for the first class that matches the predicate. */ - fun findClass(predicate: (ClassDef) -> Boolean) = - // if we already proxied the class matching the predicate... - classes.proxies.firstOrNull { predicate(it.immutableClass) } - ?: // else resolve the class to a proxy and return it, if the predicate is matching a class - classes.find(predicate)?.let { proxy(it) } + fun classBy(predicate: (ClassDef) -> Boolean) = + classes.proxyPool.find { predicate(it.immutableClass) } ?: classes.find(predicate)?.proxy() /** - * Proxy a class. - * This will allow the class to be modified. + * Proxy the class to allow mutation. * - * @param classDef The class to proxy. * @return A proxy for the class. */ - fun proxy(classDef: ClassDef) = - this.classes.proxies.find { it.immutableClass.type == classDef.type } ?: let { - ClassProxy(classDef).also { this.classes.add(it) } - } + fun ClassDef.proxy() = this@BytecodePatchContext.classes.proxyPool.find { it.immutableClass.type == type } + ?: ClassProxy(this).also { this@BytecodePatchContext.classes.proxyPool.add(it) } /** - * Create a [MethodWalker] instance for the current [BytecodePatchContext]. + * Navigate a method. * - * @param startMethod The method to start at. - * @return A [MethodWalker] instance. + * @return A [MethodNavigator] for the method. */ - fun toMethodWalker(startMethod: Method) = MethodWalker(this, startMethod) + fun Method.navigate() = MethodNavigator(this@BytecodePatchContext, this) /** * Compile bytecode from the [BytecodePatchContext]. @@ -116,7 +108,7 @@ class BytecodePatchContext internal constructor(private val config: PatcherConfi BasicDexFileNamer(), object : DexFile { override fun getClasses() = - this@BytecodePatchContext.classes.also(ProxyClassList::replaceClasses) + this@BytecodePatchContext.classes.also(ProxyClassList::replaceClasses).toSet() override fun getOpcodes() = this@BytecodePatchContext.opcodes }, diff --git a/src/main/kotlin/app/revanced/patcher/patch/Patch.kt b/src/main/kotlin/app/revanced/patcher/patch/Patch.kt index ee043466..e4248829 100644 --- a/src/main/kotlin/app/revanced/patcher/patch/Patch.kt +++ b/src/main/kotlin/app/revanced/patcher/patch/Patch.kt @@ -130,12 +130,12 @@ class BytecodePatch internal constructor( finalizeBlock, ) { override fun execute(context: PatcherContext) { - fingerprints.resolveUsingLookupMap(context.bytecodeContext) + fingerprints.resolveUsingLookupMap(context.bytecodePatchContext) - execute(context.bytecodeContext) + execute(context.bytecodePatchContext) } - override fun finalize(context: PatcherContext) = finalize(context.bytecodeContext) + override fun finalize(context: PatcherContext) = finalize(context.bytecodePatchContext) } /** @@ -177,8 +177,8 @@ class RawResourcePatch internal constructor( executeBlock, finalizeBlock, ) { - override fun execute(context: PatcherContext) = execute(context.resourceContext) - override fun finalize(context: PatcherContext) = finalize(context.resourceContext) + override fun execute(context: PatcherContext) = execute(context.resourcePatchContext) + override fun finalize(context: PatcherContext) = finalize(context.resourcePatchContext) } /** @@ -220,8 +220,8 @@ class ResourcePatch internal constructor( executeBlock, finalizeBlock, ) { - override fun execute(context: PatcherContext) = execute(context.resourceContext) - override fun finalize(context: PatcherContext) = finalize(context.resourceContext) + override fun execute(context: PatcherContext) = execute(context.resourcePatchContext) + override fun finalize(context: PatcherContext) = finalize(context.resourcePatchContext) } /** diff --git a/src/main/kotlin/app/revanced/patcher/patch/ResourcePatchContext.kt b/src/main/kotlin/app/revanced/patcher/patch/ResourcePatchContext.kt index 9431067d..5f9edfdb 100644 --- a/src/main/kotlin/app/revanced/patcher/patch/ResourcePatchContext.kt +++ b/src/main/kotlin/app/revanced/patcher/patch/ResourcePatchContext.kt @@ -149,7 +149,7 @@ class ResourcePatchContext internal constructor( // Excluded because present in resources.other. // TODO: We are reusing config.apkFiles as a temporarily directory for extracting resources. // This is not ideal as it could conflict with files such as the ones that we filter here. - // The problem is that ResourceContext#get returns a File relative to config.apkFiles, + // The problem is that ResourcePatchContext#get returns a File relative to config.apkFiles, // and we need to extract files to that directory. // A solution would be to use config.apkFiles as the working directory for the patching process. // Once all patches have been executed, we can move the decoded resources to a new directory. diff --git a/src/main/kotlin/app/revanced/patcher/util/ClassMerger.kt b/src/main/kotlin/app/revanced/patcher/util/ClassMerger.kt index 184fa328..a613d1b3 100644 --- a/src/main/kotlin/app/revanced/patcher/util/ClassMerger.kt +++ b/src/main/kotlin/app/revanced/patcher/util/ClassMerger.kt @@ -180,7 +180,7 @@ internal object ClassMerger { callback: MutableClass.() -> Unit, ) { callback(targetClass) - this.findClass(targetClass.superclass ?: return)?.mutableClass?.let { + this.classByType(targetClass.superclass ?: return)?.mutableClass?.let { traverseClassHierarchy(it, callback) } } diff --git a/src/main/kotlin/app/revanced/patcher/util/MethodNavigator.kt b/src/main/kotlin/app/revanced/patcher/util/MethodNavigator.kt new file mode 100644 index 00000000..6c04c8f2 --- /dev/null +++ b/src/main/kotlin/app/revanced/patcher/util/MethodNavigator.kt @@ -0,0 +1,78 @@ +@file:Suppress("unused") + +package app.revanced.patcher.util + +import app.revanced.patcher.patch.BytecodePatchContext +import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod +import com.android.tools.smali.dexlib2.iface.ClassDef +import com.android.tools.smali.dexlib2.iface.Method +import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction +import com.android.tools.smali.dexlib2.iface.reference.MethodReference +import com.android.tools.smali.dexlib2.util.MethodUtil + +/** + * A navigator for methods. + * + * @param context The [BytecodePatchContext] to use. + * @param method The [Method] to navigate. + * + * @constructor Creates a new [MethodNavigator]. + * + * @throws NavigateException If the method does not have an implementation. + * @throws NavigateException If the instruction at the specified index is not a method reference. + */ +class MethodNavigator internal constructor(private val context: BytecodePatchContext, private var method: Method) { + var reference: MethodReference = method + + /** + * Navigate to the method at the specified index. + * + * @param index The index of the method to navigate to. + * + * @return This [MethodNavigator]. + */ + fun at(vararg index: Int): MethodNavigator { + index.forEach { + val currentMethod = immutable() + val instructions = currentMethod.implementation?.instructions + ?: throw NavigateException( + "Method ${currentMethod.definingClass}.${currentMethod.name} does not have an implementation.", + ) + + val instruction = instructions.elementAt(it) as? ReferenceInstruction + val newMethod = instruction?.reference as? MethodReference + ?: throw NavigateException("Instruction at index $it is not a method reference.") + + reference = newMethod + } + + return this + } + + /** + * Get the last navigated method mutably. + * + * @return The last navigated method mutably. + */ + fun mutable() = context.classBy { classDef -> + classDef.type == reference.definingClass + }!!.mutableClass.methodBySignature() as MutableMethod + + /** + * Get the last navigated method immutably. + * + * @return The last navigated method immutably. + */ + fun immutable() = context.classes.first { classDef -> + classDef.type == reference.definingClass + }.methodBySignature() + + private fun ClassDef.methodBySignature() = methods.first { MethodUtil.methodSignaturesMatch(it, method) } + + /** + * An exception thrown when navigating fails. + * + * @param message The message of the exception. + */ + internal class NavigateException internal constructor(message: String) : Exception(message) +} diff --git a/src/main/kotlin/app/revanced/patcher/util/ProxyClassList.kt b/src/main/kotlin/app/revanced/patcher/util/ProxyClassList.kt index a05b7b84..cdc334f8 100644 --- a/src/main/kotlin/app/revanced/patcher/util/ProxyClassList.kt +++ b/src/main/kotlin/app/revanced/patcher/util/ProxyClassList.kt @@ -4,23 +4,18 @@ import app.revanced.patcher.util.proxy.ClassProxy import com.android.tools.smali.dexlib2.iface.ClassDef /** - * A class that represents a set of classes and proxies. + * A list of classes and proxies. * * @param classes The classes to be backed by proxies. */ -class ProxyClassList internal constructor(classes: MutableSet) : MutableSet by classes { - internal val proxies = mutableListOf() - - /** - * Add a [ClassProxy]. - */ - fun add(classProxy: ClassProxy) = proxies.add(classProxy) +class ProxyClassList internal constructor(classes: MutableList) : MutableList by classes { + internal val proxyPool = mutableListOf() /** * Replace all classes with their mutated versions. */ internal fun replaceClasses() = - proxies.removeIf { proxy -> + proxyPool.removeIf { proxy -> // If the proxy is unused, return false to keep it in the proxies list. if (!proxy.resolved) return@removeIf false diff --git a/src/main/kotlin/app/revanced/patcher/util/method/MethodWalker.kt b/src/main/kotlin/app/revanced/patcher/util/method/MethodWalker.kt deleted file mode 100644 index 56f635b8..00000000 --- a/src/main/kotlin/app/revanced/patcher/util/method/MethodWalker.kt +++ /dev/null @@ -1,60 +0,0 @@ -package app.revanced.patcher.util.method - -import app.revanced.patcher.patch.BytecodePatchContext -import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod -import com.android.tools.smali.dexlib2.iface.Method -import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction -import com.android.tools.smali.dexlib2.iface.reference.MethodReference -import com.android.tools.smali.dexlib2.util.MethodUtil - -/** - * Find a method from another method via instruction offsets. - * @param bytecodeContext The context to use when resolving the next method reference. - * @param currentMethod The method to start from. - */ -class MethodWalker internal constructor( - private val bytecodeContext: BytecodePatchContext, - private var currentMethod: Method, -) { - /** - * Get the method which was walked last. - * - * It is possible to cast this method to a [MutableMethod], if the method has been walked mutably. - * - * @return The method which was walked last. - */ - fun getMethod(): Method { - return currentMethod - } - - /** - * Walk to a method defined at the offset in the instruction list of the current method. - * - * The current method will be mutable. - * - * @param offset The offset of the instruction. This instruction must be of format 35c. - * @param walkMutable If this is true, the class of the method will be resolved mutably. - * @return The same [MethodWalker] instance with the method at [offset]. - */ - fun nextMethod( - offset: Int, - walkMutable: Boolean = false, - ): MethodWalker { - currentMethod.implementation?.instructions?.let { instructions -> - val instruction = instructions.elementAt(offset) - - val newMethod = (instruction as ReferenceInstruction).reference as MethodReference - val proxy = bytecodeContext.findClass(newMethod.definingClass)!! - - val methods = if (walkMutable) proxy.mutableClass.methods else proxy.immutableClass.methods - currentMethod = - methods.first { - return@first MethodUtil.methodSignaturesMatch(it, newMethod) - } - return this - } - throw MethodNotFoundException("This method can not be walked at offset $offset inside the method ${currentMethod.name}") - } - - internal class MethodNotFoundException(exception: String) : Exception(exception) -} diff --git a/src/main/kotlin/app/revanced/patcher/util/proxy/ClassProxy.kt b/src/main/kotlin/app/revanced/patcher/util/proxy/ClassProxy.kt index b20c0b70..ccd8abd1 100644 --- a/src/main/kotlin/app/revanced/patcher/util/proxy/ClassProxy.kt +++ b/src/main/kotlin/app/revanced/patcher/util/proxy/ClassProxy.kt @@ -8,6 +8,7 @@ import com.android.tools.smali.dexlib2.iface.ClassDef * * A class proxy simply holds a reference to the original class * and allocates a mutable clone for the original class if needed. + * * @param immutableClass The class to proxy. */ class ClassProxy internal constructor( diff --git a/src/test/kotlin/app/revanced/patcher/PatcherTest.kt b/src/test/kotlin/app/revanced/patcher/PatcherTest.kt index b5a343de..a245c2ab 100644 --- a/src/test/kotlin/app/revanced/patcher/PatcherTest.kt +++ b/src/test/kotlin/app/revanced/patcher/PatcherTest.kt @@ -35,8 +35,8 @@ internal object PatcherTest { Logger.getAnonymousLogger(), ) - every { context.bytecodeContext.classes } returns mockk(relaxed = true) - every { context.bytecodeContext.integrations } returns mockk(relaxed = true) + every { context.bytecodePatchContext.classes } returns mockk(relaxed = true) + every { context.bytecodePatchContext.integrations } returns mockk(relaxed = true) every { apply(false) } answers { callOriginal() } } } @@ -134,8 +134,8 @@ internal object PatcherTest { } private fun mockClassWithMethod() { - every { patcher.context.bytecodeContext.classes } returns ProxyClassList( - mutableSetOf( + every { patcher.context.bytecodePatchContext.classes } returns ProxyClassList( + mutableListOf( ImmutableClassDef( "class", 0,