diff --git a/src/main/kotlin/app/revanced/patcher/Patcher.kt b/src/main/kotlin/app/revanced/patcher/Patcher.kt index 7abee14..7f54d8f 100644 --- a/src/main/kotlin/app/revanced/patcher/Patcher.kt +++ b/src/main/kotlin/app/revanced/patcher/Patcher.kt @@ -5,17 +5,24 @@ import app.revanced.patcher.patch.Patch import app.revanced.patcher.resolver.SignatureResolver import app.revanced.patcher.signature.MethodSignature import lanchon.multidexlib2.BasicDexFileNamer +import lanchon.multidexlib2.DexIO import lanchon.multidexlib2.MultiDexIO import org.jf.dexlib2.Opcodes import org.jf.dexlib2.iface.ClassDef import org.jf.dexlib2.iface.DexFile import java.io.File +/** + * ReVanced Patcher. + * @param input The input file (an apk or any other multi dex container). + * @param output The output folder. + * @param signatures An array of method signatures for the patches + * + */ class Patcher( input: File, private val output: File, signatures: Array, - ) { private val cache: Cache private val patches = mutableSetOf() @@ -25,6 +32,9 @@ class Patcher( cache = Cache(dexFile.classes, SignatureResolver(dexFile.classes, signatures).resolve()) } + /** + * Save the patched dex file. + */ fun save() { val newDexFile = object : DexFile { override fun getClasses(): Set { @@ -45,13 +55,21 @@ class Patcher( } // TODO: we should use the multithreading capable overload for writeDexFile - MultiDexIO.writeDexFile(true, output, BasicDexFileNamer(), newDexFile, 50000, null) + MultiDexIO.writeDexFile(true, output, BasicDexFileNamer(), newDexFile, DexIO.DEFAULT_MAX_DEX_POOL_SIZE, null) } + /** + * Add a patch to the patcher. + * @param patches The patches to add. + */ fun addPatches(vararg patches: Patch) { this.patches.addAll(patches) } + /** + * Apply patches loaded into the patcher. + * @param stopOnError If true, the patches will stop on the first error. + */ fun applyPatches(stopOnError: Boolean = false): Map> { return buildMap { // TODO: after each patch execution we could clear left overs like proxied classes to safe memory diff --git a/src/main/kotlin/app/revanced/patcher/cache/Cache.kt b/src/main/kotlin/app/revanced/patcher/cache/Cache.kt index 217da04..d907cb3 100644 --- a/src/main/kotlin/app/revanced/patcher/cache/Cache.kt +++ b/src/main/kotlin/app/revanced/patcher/cache/Cache.kt @@ -13,6 +13,10 @@ class Cache( // if the class proxy already exists in the cached proxy list below internal val classProxy = mutableSetOf() + /** + * Find a class by a given predicate + * @return A proxy for the first class that matches the predicate + */ fun findClass(predicate: (ClassDef) -> Boolean): ClassProxy? { // if we already proxied the class matching the predicate, val proxiedClass = classProxy.singleOrNull { classProxy -> predicate(classProxy.immutableClass) } diff --git a/src/main/kotlin/app/revanced/patcher/proxy/ClassProxy.kt b/src/main/kotlin/app/revanced/patcher/proxy/ClassProxy.kt index afb5727..1765fb9 100644 --- a/src/main/kotlin/app/revanced/patcher/proxy/ClassProxy.kt +++ b/src/main/kotlin/app/revanced/patcher/proxy/ClassProxy.kt @@ -3,6 +3,13 @@ package app.revanced.patcher.proxy import app.revanced.patcher.proxy.mutableTypes.MutableClass import org.jf.dexlib2.iface.ClassDef +/** + * A proxy class for a [ClassDef] + * A class proxy simply holds a reference to the original class + * and creates a mutable clone for the original class if needed. + * @param immutableClass The class to proxy + * @param originalIndex The original index of the class in the list of classes + */ class ClassProxy( val immutableClass: ClassDef, val originalIndex: Int, @@ -10,6 +17,10 @@ class ClassProxy( internal var proxyUsed = false internal lateinit var mutatedClass: MutableClass + /** + * Creates and returns a mutable clone of the original class + * A patch should always use the original immutable class reference to avoid unnucessary allocations for the mutable class + */ fun resolve(): MutableClass { if (!proxyUsed) { proxyUsed = true diff --git a/src/main/kotlin/app/revanced/patcher/signature/MethodSignature.kt b/src/main/kotlin/app/revanced/patcher/signature/MethodSignature.kt index 6b870dc..f72ec73 100644 --- a/src/main/kotlin/app/revanced/patcher/signature/MethodSignature.kt +++ b/src/main/kotlin/app/revanced/patcher/signature/MethodSignature.kt @@ -2,6 +2,14 @@ package app.revanced.patcher.signature import org.jf.dexlib2.Opcode +/** + * Represents a method signature. + * @param name A suggestive name for the method which the signature was created for. + * @param returnType The return type of the method. + * @param methodParameters The parameters of the method. + * @param opcodes A list of opcodes of the method. + * @param accessFlags The access flags of the method. + */ @Suppress("ArrayInDataClass") data class MethodSignature( val name: String, diff --git a/src/main/kotlin/app/revanced/patcher/signature/SignatureResolverResult.kt b/src/main/kotlin/app/revanced/patcher/signature/SignatureResolverResult.kt index af85afc..a8a8dee 100644 --- a/src/main/kotlin/app/revanced/patcher/signature/SignatureResolverResult.kt +++ b/src/main/kotlin/app/revanced/patcher/signature/SignatureResolverResult.kt @@ -3,6 +3,12 @@ package app.revanced.patcher.signature import app.revanced.patcher.proxy.ClassProxy import app.revanced.patcher.resolver.SignatureResolver +/** + * Represents the result of a [SignatureResolver]. + * @param definingClassProxy The [ClassProxy] that the matching method was found in. + * @param resolvedMethodName The name of the actual matching method. + * @param scanData OpCodes pattern scan result. + */ data class SignatureResolverResult( val definingClassProxy: ClassProxy, val resolvedMethodName: String,