Skip to content

Commit

Permalink
docs: Document important parts of the code
Browse files Browse the repository at this point in the history
  • Loading branch information
oSumAtrIX committed Jun 5, 2022
1 parent 1dd3394 commit 650bf71
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 2 deletions.
22 changes: 20 additions & 2 deletions src/main/kotlin/app/revanced/patcher/Patcher.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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<MethodSignature>,

) {
private val cache: Cache
private val patches = mutableSetOf<Patch>()
Expand All @@ -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<ClassDef> {
Expand All @@ -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<String, Result<Nothing?>> {
return buildMap {
// TODO: after each patch execution we could clear left overs like proxied classes to safe memory
Expand Down
4 changes: 4 additions & 0 deletions src/main/kotlin/app/revanced/patcher/cache/Cache.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ class Cache(
// if the class proxy already exists in the cached proxy list below
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? {
// if we already proxied the class matching the predicate,
val proxiedClass = classProxy.singleOrNull { classProxy -> predicate(classProxy.immutableClass) }
Expand Down
11 changes: 11 additions & 0 deletions src/main/kotlin/app/revanced/patcher/proxy/ClassProxy.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,24 @@ 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,
) {
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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down

0 comments on commit 650bf71

Please sign in to comment.