From 37765992a611931e5f0ba383d031d40b8ce40efe Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Tue, 18 Jun 2024 02:43:38 +0200 Subject: [PATCH] add field to patch loader to get patches by bundle --- api/revanced-patcher.api | 17 +++- .../app/revanced/patcher/patch/Patch.kt | 85 ++++++++++++------- .../revanced/patcher/patch/PatchLoaderTest.kt | 10 ++- 3 files changed, 72 insertions(+), 40 deletions(-) diff --git a/api/revanced-patcher.api b/api/revanced-patcher.api index 2901751b..f3cf4776 100644 --- a/api/revanced-patcher.api +++ b/api/revanced-patcher.api @@ -367,9 +367,9 @@ public final class app/revanced/patcher/patch/PatchException : java/lang/Excepti public final class app/revanced/patcher/patch/PatchKt { public static final fun bytecodePatch (Ljava/lang/String;Ljava/lang/String;ZZLkotlin/jvm/functions/Function1;)Lapp/revanced/patcher/patch/BytecodePatch; public static synthetic fun bytecodePatch$default (Ljava/lang/String;Ljava/lang/String;ZZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lapp/revanced/patcher/patch/BytecodePatch; - public static final fun loadPatchesFromDex (Ljava/util/Set;Ljava/io/File;)Ljava/util/Set; - public static synthetic fun loadPatchesFromDex$default (Ljava/util/Set;Ljava/io/File;ILjava/lang/Object;)Ljava/util/Set; - public static final fun loadPatchesFromJar (Ljava/util/Set;)Ljava/util/Set; + public static final fun loadPatchesFromDex (Ljava/util/Set;Ljava/io/File;)Lapp/revanced/patcher/patch/PatchLoader$Dex; + public static synthetic fun loadPatchesFromDex$default (Ljava/util/Set;Ljava/io/File;ILjava/lang/Object;)Lapp/revanced/patcher/patch/PatchLoader$Dex; + public static final fun loadPatchesFromJar (Ljava/util/Set;)Lapp/revanced/patcher/patch/PatchLoader$Jar; public static final fun rawResourcePatch (Ljava/lang/String;Ljava/lang/String;ZZLkotlin/jvm/functions/Function1;)Lapp/revanced/patcher/patch/RawResourcePatch; public static synthetic fun rawResourcePatch$default (Ljava/lang/String;Ljava/lang/String;ZZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lapp/revanced/patcher/patch/RawResourcePatch; public static final fun resourcePatch (Ljava/lang/String;Ljava/lang/String;ZZLkotlin/jvm/functions/Function1;)Lapp/revanced/patcher/patch/ResourcePatch; @@ -377,6 +377,7 @@ public final class app/revanced/patcher/patch/PatchKt { } public abstract class app/revanced/patcher/patch/PatchLoader : java/util/Set, kotlin/jvm/internal/markers/KMappedMarker { + public synthetic fun (Ljava/util/Map;Lkotlin/jvm/internal/DefaultConstructorMarker;)V public synthetic fun (Ljava/util/Set;Lkotlin/jvm/functions/Function1;Ljava/lang/ClassLoader;Lkotlin/jvm/internal/DefaultConstructorMarker;)V public fun add (Lapp/revanced/patcher/patch/Patch;)Z public synthetic fun add (Ljava/lang/Object;)Z @@ -385,6 +386,7 @@ public abstract class app/revanced/patcher/patch/PatchLoader : java/util/Set, ko public fun contains (Lapp/revanced/patcher/patch/Patch;)Z public final fun contains (Ljava/lang/Object;)Z public fun containsAll (Ljava/util/Collection;)Z + public final fun getByPatchesFile ()Ljava/util/Map; public fun getSize ()I public fun isEmpty ()Z public fun iterator ()Ljava/util/Iterator; @@ -396,6 +398,15 @@ public abstract class app/revanced/patcher/patch/PatchLoader : java/util/Set, ko public fun toArray ([Ljava/lang/Object;)[Ljava/lang/Object; } +public final class app/revanced/patcher/patch/PatchLoader$Dex : app/revanced/patcher/patch/PatchLoader { + public fun (Ljava/util/Set;Ljava/io/File;)V + public synthetic fun (Ljava/util/Set;Ljava/io/File;ILkotlin/jvm/internal/DefaultConstructorMarker;)V +} + +public final class app/revanced/patcher/patch/PatchLoader$Jar : app/revanced/patcher/patch/PatchLoader { + public fun (Ljava/util/Set;)V +} + public final class app/revanced/patcher/patch/PatchResult { public final fun getException ()Lapp/revanced/patcher/patch/PatchException; public final fun getPatch ()Lapp/revanced/patcher/patch/Patch; diff --git a/src/main/kotlin/app/revanced/patcher/patch/Patch.kt b/src/main/kotlin/app/revanced/patcher/patch/Patch.kt index 12a7442a..779b1046 100644 --- a/src/main/kotlin/app/revanced/patcher/patch/Patch.kt +++ b/src/main/kotlin/app/revanced/patcher/patch/Patch.kt @@ -523,20 +523,27 @@ class PatchException(errorMessage: String?, cause: Throwable?) : Exception(error class PatchResult internal constructor(val patch: Patch<*>, val exception: PatchException? = null) /** - * A loader for [Patch]. - * Loads patches from JAR or DEX files declared as public static fields + * A loader for patches. + * + * Loads unnamed patches from JAR or DEX files declared as public static fields * or returned by public static and non-parametrized methods. - * Patches with no name are not loaded. * - * @param patchesFiles A set of JAR or DEX files to load the patches from. - * @param getBinaryClassNames A function that returns the binary names of all classes accessible by the class loader. - * @param classLoader The [ClassLoader] to use for loading the classes. + * @param byPatchesFile The patches associated by the patches file they were loaded from. */ sealed class PatchLoader private constructor( - patchesFiles: Set, - private val getBinaryClassNames: (patchesFile: File) -> List, - private val classLoader: ClassLoader, -) : Set> by classLoader.loadPatches(patchesFiles.flatMap(getBinaryClassNames)) { + val byPatchesFile: Map>>, +) : Set> by byPatchesFile.values.flatten().toSet() { + /** + * @param patchesFiles A set of JAR or DEX files to load the patches from. + * @param getBinaryClassNames A function that returns the binary names of all classes accessible by the class loader. + * @param classLoader The [ClassLoader] to use for loading the classes. + */ + private constructor( + patchesFiles: Set, + getBinaryClassNames: (patchesFile: File) -> List, + classLoader: ClassLoader, + ) : this(classLoader.loadPatches(patchesFiles.associateWith { getBinaryClassNames(it).toSet() })) + /** * A [PatchLoader] for JAR files. * @@ -544,7 +551,7 @@ sealed class PatchLoader private constructor( * * @constructor Create a new [PatchLoader] for JAR files. */ - internal class Jar(patchesFiles: Set) : + class Jar(patchesFiles: Set) : PatchLoader( patchesFiles, { file -> @@ -563,7 +570,7 @@ sealed class PatchLoader private constructor( * * @constructor Create a new [PatchLoader] for [Dex] files. */ - internal class Dex(patchesFiles: Set, optimizedDexDirectory: File? = null) : + class Dex(patchesFiles: Set, optimizedDexDirectory: File? = null) : PatchLoader( patchesFiles, { patchBundle -> @@ -582,35 +589,47 @@ sealed class PatchLoader private constructor( // Companion object required for unit tests. private companion object { + val Class<*>.isPatch get() = Patch::class.java.isAssignableFrom(this) + /** - * Loads named patches declared as public static fields - * or returned by public static and non-parametrized methods. - * - * @param binaryClassNames The binary class name of the classes to load the patches from. - * - * @return The loaded patches. + * Public static fields that are patches. */ - private fun ClassLoader.loadPatches(binaryClassNames: List) = binaryClassNames.asSequence().map { - loadClass(it) - }.flatMap { - val isPatch = { cls: Class<*> -> Patch::class.java.isAssignableFrom(cls) } - - val patchesFromFields = it.fields.filter { field -> - isPatch(field.type) && field.canAccess(null) + private val Class<*>.patchFields + get() = fields.filter { field -> + field.type.isPatch && field.canAccess(null) }.map { field -> field.get(null) as Patch<*> } - val patchesFromMethods = it.methods.filter { method -> - isPatch(method.returnType) && method.parameterCount == 0 && method.canAccess(null) + /** + * Public static and non-parametrized methods that return patches. + */ + private val Class<*>.patchMethods + get() = methods.filter { method -> + method.returnType.isPatch && method.parameterCount == 0 && method.canAccess(null) }.map { method -> method.invoke(null) as Patch<*> } - patchesFromFields + patchesFromMethods - }.filter { - it.name != null - }.toSet() + /** + * Loads unnamed patches declared as public static fields + * or returned by public static and non-parametrized methods. + * + * @param binaryClassNamesByPatchesFile The binary class name of the classes to load the patches from + * associated by the patches file. + * + * @return The loaded patches associated by the patches file. + */ + private fun ClassLoader.loadPatches(binaryClassNamesByPatchesFile: Map>) = + binaryClassNamesByPatchesFile.mapValues { (_, binaryClassNames) -> + binaryClassNames.asSequence().map { + loadClass(it) + }.flatMap { + it.patchFields + it.patchMethods + }.filter { + it.name != null + }.toSet() + } } } @@ -623,7 +642,7 @@ sealed class PatchLoader private constructor( * * @return The loaded patches. */ -fun loadPatchesFromJar(patchesFiles: Set): Set> = +fun loadPatchesFromJar(patchesFiles: Set) = PatchLoader.Jar(patchesFiles) /** @@ -635,5 +654,5 @@ fun loadPatchesFromJar(patchesFiles: Set): Set> = * * @return The loaded patches. */ -fun loadPatchesFromDex(patchesFiles: Set, optimizedDexDirectory: File? = null): Set> = +fun loadPatchesFromDex(patchesFiles: Set, optimizedDexDirectory: File? = null) = PatchLoader.Dex(patchesFiles, optimizedDexDirectory) diff --git a/src/test/kotlin/app/revanced/patcher/patch/PatchLoaderTest.kt b/src/test/kotlin/app/revanced/patcher/patch/PatchLoaderTest.kt index fda0fc03..8f90fef3 100644 --- a/src/test/kotlin/app/revanced/patcher/patch/PatchLoaderTest.kt +++ b/src/test/kotlin/app/revanced/patcher/patch/PatchLoaderTest.kt @@ -3,8 +3,10 @@ package app.revanced.patcher.patch import org.junit.jupiter.api.Test +import java.io.File import kotlin.reflect.KFunction -import kotlin.reflect.full.* +import kotlin.reflect.full.companionObject +import kotlin.reflect.full.declaredFunctions import kotlin.reflect.jvm.isAccessible import kotlin.reflect.jvm.javaField import kotlin.test.assertEquals @@ -62,14 +64,14 @@ internal object PatchLoaderTest { val loadPatchesFunction = getPrivateFunctionByName( patchLoaderCompanionObject, LOAD_PATCHES_FUNCTION_NAME, - ) as KFunction>> + ) as KFunction>>> // Call private PatchLoader.Companion.loadPatches function. val patches = loadPatchesFunction.call( patchLoaderCompanionObject, TEST_PATCHES_CLASS_LOADER, - listOf(TEST_PATCHES_CLASS), - ) + mapOf(File("patchesFile") to setOf(TEST_PATCHES_CLASS)), + ).values.first() assertEquals( 2,