mirror of
https://github.com/ReVanced/revanced-patcher.git
synced 2024-11-10 09:08:04 +01:00
feat: properly manage ClassProxy
& add ProxyBackedClassList
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
This commit is contained in:
parent
7399450139
commit
6cb1fdf617
6 changed files with 71 additions and 46 deletions
|
@ -3,7 +3,6 @@ package app.revanced.patcher
|
|||
import app.revanced.patcher.patch.Patch
|
||||
import app.revanced.patcher.patch.PatchMetadata
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.proxy.ClassProxy
|
||||
import app.revanced.patcher.signature.MethodSignature
|
||||
import app.revanced.patcher.signature.resolver.SignatureResolver
|
||||
import app.revanced.patcher.util.ListBackedSet
|
||||
|
@ -49,18 +48,18 @@ class Patcher(
|
|||
for (file in files) {
|
||||
val dexFile = MultiDexIO.readDexFile(true, file, NAMER, null, null)
|
||||
for (classDef in dexFile.classes) {
|
||||
val e = patcherData.classes.findIndexed { it.type == classDef.type }
|
||||
val e = patcherData.classes.internalClasses.findIndexed { it.type == classDef.type }
|
||||
if (e != null) {
|
||||
if (throwOnDuplicates) {
|
||||
throw Exception("Class ${classDef.type} has already been added to the patcher.")
|
||||
}
|
||||
val (_, idx) = e
|
||||
if (allowedOverwrites.contains(classDef.type)) {
|
||||
patcherData.classes[idx] = classDef
|
||||
patcherData.classes.internalClasses[idx] = classDef
|
||||
}
|
||||
continue
|
||||
}
|
||||
patcherData.classes.add(classDef)
|
||||
patcherData.classes.internalClasses.add(classDef)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -70,28 +69,17 @@ class Patcher(
|
|||
*/
|
||||
fun save(): Map<String, MemoryDataStore> {
|
||||
val newDexFile = object : DexFile {
|
||||
private fun MutableList<ClassDef>.replaceWith(proxy: ClassProxy) {
|
||||
this[proxy.originalIndex] = proxy.mutatedClass
|
||||
}
|
||||
|
||||
override fun getClasses(): Set<ClassDef> {
|
||||
for (proxy in patcherData.classProxies) {
|
||||
val classes = patcherData.classes
|
||||
val internalClasses = classes.internalClasses
|
||||
for (proxy in classes.proxies) {
|
||||
if (!proxy.proxyUsed) continue
|
||||
|
||||
patcherData.classes.replaceWith(proxy)
|
||||
val index = internalClasses.indexOfFirst { it.type == proxy.immutableClass.type }
|
||||
internalClasses[index] = proxy.mutatedClass
|
||||
}
|
||||
for (patch in patcherData.patches) {
|
||||
for (signature in patch.signatures) {
|
||||
val result = signature.result
|
||||
result ?: continue
|
||||
|
||||
val proxy = result.definingClassProxy
|
||||
if (!proxy.proxyUsed) continue
|
||||
|
||||
patcherData.classes.replaceWith(proxy)
|
||||
}
|
||||
}
|
||||
return ListBackedSet(patcherData.classes)
|
||||
return ListBackedSet(internalClasses)
|
||||
}
|
||||
|
||||
override fun getOpcodes(): Opcodes {
|
||||
|
@ -129,7 +117,7 @@ class Patcher(
|
|||
if (signatures.isEmpty()) {
|
||||
throw IllegalStateException("No signatures found to resolve.")
|
||||
}
|
||||
SignatureResolver(patcherData.classes, signatures).resolve()
|
||||
SignatureResolver(patcherData.classes.internalClasses, signatures).resolve(patcherData)
|
||||
signaturesResolved = true
|
||||
return signatures
|
||||
}
|
||||
|
|
|
@ -4,14 +4,15 @@ import app.revanced.patcher.methodWalker.MethodWalker
|
|||
import app.revanced.patcher.patch.Patch
|
||||
import app.revanced.patcher.proxy.ClassProxy
|
||||
import app.revanced.patcher.signature.SignatureResolverResult
|
||||
import app.revanced.patcher.util.ProxyBackedClassList
|
||||
import org.jf.dexlib2.iface.ClassDef
|
||||
import org.jf.dexlib2.iface.Method
|
||||
|
||||
class PatcherData(
|
||||
internal val classes: MutableList<ClassDef>,
|
||||
internalClasses: MutableList<ClassDef>,
|
||||
) {
|
||||
internal val classProxies = mutableSetOf<ClassProxy>()
|
||||
internal val patches = mutableSetOf<Patch>()
|
||||
val classes = ProxyBackedClassList(internalClasses)
|
||||
internal val patches = mutableListOf<Patch>()
|
||||
|
||||
/**
|
||||
* Find a class by a given class name
|
||||
|
@ -30,19 +31,14 @@ class PatcherData(
|
|||
val result = signature.result
|
||||
result ?: continue
|
||||
|
||||
if (predicate(result.definingClassProxy.immutableClass))
|
||||
return result.definingClassProxy // ...then return that proxy
|
||||
if (predicate(result.definingClassProxy.immutableClass)) return result.definingClassProxy // ...then return that proxy
|
||||
}
|
||||
}
|
||||
|
||||
// else search the original class list
|
||||
val (foundClass, index) = classes.findIndexed(predicate) ?: return null
|
||||
// create a class proxy with the index of the class in the classes list
|
||||
val classProxy = ClassProxy(foundClass, index)
|
||||
// add it to the cache and
|
||||
this.classProxies.add(classProxy)
|
||||
// return the proxy class
|
||||
return classProxy
|
||||
// else resolve the class to a proxy and return it, if the predicate is matching a class
|
||||
return classes.find(predicate)?.let {
|
||||
proxy(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,3 +71,12 @@ internal inline fun <T> Iterable<T>.findIndexed(predicate: (T) -> Boolean): Pair
|
|||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun PatcherData.proxy(classProxy: ClassDef): ClassProxy {
|
||||
var proxy = this.classes.proxies.find { it.immutableClass.type == classProxy.type }
|
||||
if (proxy == null) {
|
||||
proxy = ClassProxy(classProxy)
|
||||
this.classes.proxies.add(proxy)
|
||||
}
|
||||
return proxy
|
||||
}
|
|
@ -9,11 +9,9 @@ import org.jf.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
|
||||
* @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
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package app.revanced.patcher.signature.resolver
|
||||
|
||||
import app.revanced.patcher.PatcherData
|
||||
import app.revanced.patcher.proxy
|
||||
import app.revanced.patcher.proxy.ClassProxy
|
||||
import app.revanced.patcher.signature.MethodSignature
|
||||
import app.revanced.patcher.signature.PatternScanMethod
|
||||
|
@ -13,14 +15,14 @@ internal class SignatureResolver(
|
|||
private val classes: List<ClassDef>,
|
||||
private val methodSignatures: Iterable<MethodSignature>
|
||||
) {
|
||||
fun resolve() {
|
||||
for ((index, classDef) in classes.withIndex()) {
|
||||
fun resolve(patcherData: PatcherData) {
|
||||
for (classDef in classes) {
|
||||
for (signature in methodSignatures) {
|
||||
for (method in classDef.methods) {
|
||||
val patternScanData = compareSignatureToMethod(signature, method) ?: continue
|
||||
|
||||
// create class proxy, in case a patch needs mutability
|
||||
val classProxy = ClassProxy(classDef, index)
|
||||
val classProxy = patcherData.proxy(classDef)
|
||||
signature.result = SignatureResolverResult(
|
||||
classProxy,
|
||||
patternScanData,
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
package app.revanced.patcher.util
|
||||
|
||||
import app.revanced.patcher.proxy.ClassProxy
|
||||
import org.jf.dexlib2.iface.ClassDef
|
||||
|
||||
class ProxyBackedClassList(internal val internalClasses: MutableList<ClassDef>) : List<ClassDef> {
|
||||
internal val proxies = mutableListOf<ClassProxy>()
|
||||
|
||||
fun add(classDef: ClassDef) {
|
||||
internalClasses.add(classDef)
|
||||
}
|
||||
|
||||
fun add(classProxy: ClassProxy) {
|
||||
proxies.add(classProxy)
|
||||
}
|
||||
|
||||
override val size get() = internalClasses.size
|
||||
override fun contains(element: ClassDef) = internalClasses.contains(element)
|
||||
override fun containsAll(elements: Collection<ClassDef>) = internalClasses.containsAll(elements)
|
||||
override fun get(index: Int) = internalClasses[index]
|
||||
override fun indexOf(element: ClassDef) = internalClasses.indexOf(element)
|
||||
override fun isEmpty() = internalClasses.isEmpty()
|
||||
override fun iterator() = internalClasses.iterator()
|
||||
override fun lastIndexOf(element: ClassDef) = internalClasses.lastIndexOf(element)
|
||||
override fun listIterator() = internalClasses.listIterator()
|
||||
override fun listIterator(index: Int) = internalClasses.listIterator(index)
|
||||
override fun subList(fromIndex: Int, toIndex: Int) = internalClasses.subList(fromIndex, toIndex)
|
||||
}
|
|
@ -3,10 +3,7 @@ package app.revanced.patcher.usage
|
|||
import app.revanced.patcher.PatcherData
|
||||
import app.revanced.patcher.extensions.addInstructions
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.patch.Patch
|
||||
import app.revanced.patcher.patch.PatchMetadata
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.*
|
||||
import app.revanced.patcher.proxy.mutableTypes.MutableField.Companion.toMutable
|
||||
import app.revanced.patcher.proxy.mutableTypes.MutableMethod.Companion.toMutable
|
||||
import app.revanced.patcher.signature.MethodMetadata
|
||||
|
@ -31,12 +28,19 @@ import org.jf.dexlib2.immutable.reference.ImmutableStringReference
|
|||
import org.jf.dexlib2.immutable.value.ImmutableFieldEncodedValue
|
||||
import org.jf.dexlib2.util.Preconditions
|
||||
|
||||
val packageMetadata = listOf(
|
||||
PackageMetadata(
|
||||
"com.example.examplePackage",
|
||||
listOf("0.0.1", "0.0.2")
|
||||
)
|
||||
)
|
||||
|
||||
class ExamplePatch : Patch(
|
||||
PatchMetadata(
|
||||
"example-patch",
|
||||
"ReVanced example patch",
|
||||
"A demonstrative patch to feature the core features of the ReVanced patcher",
|
||||
listOf("com.example.examplePackage"),
|
||||
packageMetadata,
|
||||
"0.0.1"
|
||||
),
|
||||
setOf(
|
||||
|
@ -48,7 +52,7 @@ class ExamplePatch : Patch(
|
|||
"main",
|
||||
),
|
||||
PatternScanMethod.Fuzzy(1),
|
||||
listOf("com.example.examplePackage"),
|
||||
packageMetadata,
|
||||
"The main method of TestClass",
|
||||
"1.0.0"
|
||||
),
|
||||
|
|
Loading…
Reference in a new issue