Skip to content

Commit

Permalink
Merge branch 'refs/heads/feat/separate-bundle-in-loader' into feat/ds…
Browse files Browse the repository at this point in the history
…l-api
  • Loading branch information
oSumAtrIX committed Jun 18, 2024
2 parents 4affb65 + 3776599 commit e473e59
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 40 deletions.
17 changes: 14 additions & 3 deletions api/revanced-patcher.api
Original file line number Diff line number Diff line change
Expand Up @@ -367,16 +367,17 @@ 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;
public static synthetic fun resourcePatch$default (Ljava/lang/String;Ljava/lang/String;ZZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lapp/revanced/patcher/patch/ResourcePatch;
}

public abstract class app/revanced/patcher/patch/PatchLoader : java/util/Set, kotlin/jvm/internal/markers/KMappedMarker {
public synthetic fun <init> (Ljava/util/Map;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
public synthetic fun <init> (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
Expand All @@ -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;
Expand All @@ -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 <init> (Ljava/util/Set;Ljava/io/File;)V
public synthetic fun <init> (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 <init> (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;
Expand Down
85 changes: 52 additions & 33 deletions src/main/kotlin/app/revanced/patcher/patch/Patch.kt
Original file line number Diff line number Diff line change
Expand Up @@ -523,28 +523,35 @@ 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<File>,
private val getBinaryClassNames: (patchesFile: File) -> List<String>,
private val classLoader: ClassLoader,
) : Set<Patch<*>> by classLoader.loadPatches(patchesFiles.flatMap(getBinaryClassNames)) {
val byPatchesFile: Map<File, Set<Patch<*>>>,
) : Set<Patch<*>> 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<File>,
getBinaryClassNames: (patchesFile: File) -> List<String>,
classLoader: ClassLoader,
) : this(classLoader.loadPatches(patchesFiles.associateWith { getBinaryClassNames(it).toSet() }))

/**
* A [PatchLoader] for JAR files.
*
* @param patchesFiles The JAR files to load the patches from.
*
* @constructor Create a new [PatchLoader] for JAR files.
*/
internal class Jar(patchesFiles: Set<File>) :
class Jar(patchesFiles: Set<File>) :
PatchLoader(
patchesFiles,
{ file ->
Expand All @@ -563,7 +570,7 @@ sealed class PatchLoader private constructor(
*
* @constructor Create a new [PatchLoader] for [Dex] files.
*/
internal class Dex(patchesFiles: Set<File>, optimizedDexDirectory: File? = null) :
class Dex(patchesFiles: Set<File>, optimizedDexDirectory: File? = null) :
PatchLoader(
patchesFiles,
{ patchBundle ->
Expand All @@ -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<String>) = 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<File, Set<String>>) =
binaryClassNamesByPatchesFile.mapValues { (_, binaryClassNames) ->
binaryClassNames.asSequence().map {
loadClass(it)
}.flatMap {
it.patchFields + it.patchMethods
}.filter {
it.name != null
}.toSet()
}
}
}

Expand All @@ -623,7 +642,7 @@ sealed class PatchLoader private constructor(
*
* @return The loaded patches.
*/
fun loadPatchesFromJar(patchesFiles: Set<File>): Set<Patch<*>> =
fun loadPatchesFromJar(patchesFiles: Set<File>) =
PatchLoader.Jar(patchesFiles)

/**
Expand All @@ -635,5 +654,5 @@ fun loadPatchesFromJar(patchesFiles: Set<File>): Set<Patch<*>> =
*
* @return The loaded patches.
*/
fun loadPatchesFromDex(patchesFiles: Set<File>, optimizedDexDirectory: File? = null): Set<Patch<*>> =
fun loadPatchesFromDex(patchesFiles: Set<File>, optimizedDexDirectory: File? = null) =
PatchLoader.Dex(patchesFiles, optimizedDexDirectory)
10 changes: 6 additions & 4 deletions src/test/kotlin/app/revanced/patcher/patch/PatchLoaderTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -62,14 +64,14 @@ internal object PatchLoaderTest {
val loadPatchesFunction = getPrivateFunctionByName(
patchLoaderCompanionObject,
LOAD_PATCHES_FUNCTION_NAME,
) as KFunction<Set<Patch<*>>>
) as KFunction<Map<File, Set<Patch<*>>>>

// 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,
Expand Down

0 comments on commit e473e59

Please sign in to comment.