docs: Document important parts of the code

This commit is contained in:
oSumAtrIX 2022-03-31 19:25:46 +02:00
parent 1dd3394ea3
commit 650bf71124
No known key found for this signature in database
GPG Key ID: A9B3094ACDB604B4
5 changed files with 49 additions and 2 deletions

View File

@ -5,17 +5,24 @@ import app.revanced.patcher.patch.Patch
import app.revanced.patcher.resolver.SignatureResolver import app.revanced.patcher.resolver.SignatureResolver
import app.revanced.patcher.signature.MethodSignature import app.revanced.patcher.signature.MethodSignature
import lanchon.multidexlib2.BasicDexFileNamer import lanchon.multidexlib2.BasicDexFileNamer
import lanchon.multidexlib2.DexIO
import lanchon.multidexlib2.MultiDexIO import lanchon.multidexlib2.MultiDexIO
import org.jf.dexlib2.Opcodes import org.jf.dexlib2.Opcodes
import org.jf.dexlib2.iface.ClassDef import org.jf.dexlib2.iface.ClassDef
import org.jf.dexlib2.iface.DexFile import org.jf.dexlib2.iface.DexFile
import java.io.File 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( class Patcher(
input: File, input: File,
private val output: File, private val output: File,
signatures: Array<MethodSignature>, signatures: Array<MethodSignature>,
) { ) {
private val cache: Cache private val cache: Cache
private val patches = mutableSetOf<Patch>() private val patches = mutableSetOf<Patch>()
@ -25,6 +32,9 @@ class Patcher(
cache = Cache(dexFile.classes, SignatureResolver(dexFile.classes, signatures).resolve()) cache = Cache(dexFile.classes, SignatureResolver(dexFile.classes, signatures).resolve())
} }
/**
* Save the patched dex file.
*/
fun save() { fun save() {
val newDexFile = object : DexFile { val newDexFile = object : DexFile {
override fun getClasses(): Set<ClassDef> { override fun getClasses(): Set<ClassDef> {
@ -45,13 +55,21 @@ class Patcher(
} }
// TODO: we should use the multithreading capable overload for writeDexFile // 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) { fun addPatches(vararg patches: Patch) {
this.patches.addAll(patches) 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<String, Result<Nothing?>> { fun applyPatches(stopOnError: Boolean = false): Map<String, Result<Nothing?>> {
return buildMap { return buildMap {
// TODO: after each patch execution we could clear left overs like proxied classes to safe memory // TODO: after each patch execution we could clear left overs like proxied classes to safe memory

View File

@ -13,6 +13,10 @@ class Cache(
// if the class proxy already exists in the cached proxy list below // if the class proxy already exists in the cached proxy list below
internal val classProxy = mutableSetOf<ClassProxy>() internal val classProxy = mutableSetOf<ClassProxy>()
/**
* Find a class by a given predicate
* @return A proxy for the first class that matches the predicate
*/
fun findClass(predicate: (ClassDef) -> Boolean): ClassProxy? { fun findClass(predicate: (ClassDef) -> Boolean): ClassProxy? {
// if we already proxied the class matching the predicate, // if we already proxied the class matching the predicate,
val proxiedClass = classProxy.singleOrNull { classProxy -> predicate(classProxy.immutableClass) } val proxiedClass = classProxy.singleOrNull { classProxy -> predicate(classProxy.immutableClass) }

View File

@ -3,6 +3,13 @@ package app.revanced.patcher.proxy
import app.revanced.patcher.proxy.mutableTypes.MutableClass import app.revanced.patcher.proxy.mutableTypes.MutableClass
import org.jf.dexlib2.iface.ClassDef 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( class ClassProxy(
val immutableClass: ClassDef, val immutableClass: ClassDef,
val originalIndex: Int, val originalIndex: Int,
@ -10,6 +17,10 @@ class ClassProxy(
internal var proxyUsed = false internal var proxyUsed = false
internal lateinit var mutatedClass: MutableClass 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 { fun resolve(): MutableClass {
if (!proxyUsed) { if (!proxyUsed) {
proxyUsed = true proxyUsed = true

View File

@ -2,6 +2,14 @@ package app.revanced.patcher.signature
import org.jf.dexlib2.Opcode 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") @Suppress("ArrayInDataClass")
data class MethodSignature( data class MethodSignature(
val name: String, val name: String,

View File

@ -3,6 +3,12 @@ package app.revanced.patcher.signature
import app.revanced.patcher.proxy.ClassProxy import app.revanced.patcher.proxy.ClassProxy
import app.revanced.patcher.resolver.SignatureResolver 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( data class SignatureResolverResult(
val definingClassProxy: ClassProxy, val definingClassProxy: ClassProxy,
val resolvedMethodName: String, val resolvedMethodName: String,