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