Skip to content

Commit

Permalink
feat!: Remove patch annotations
Browse files Browse the repository at this point in the history
Annotations required reflection and working with them turned out to be rather cumbersome. The annotations have been replaced with properties for the most part.

BREAKING CHANGE: Patch annotations have been removed. PatcherException is now thrown in various places. PatchBundleLoader is now a map of patches associated by their name. Patches are now instances.
  • Loading branch information
oSumAtrIX committed Sep 4, 2023
1 parent c4a7117 commit 3b4db3d
Show file tree
Hide file tree
Showing 16 changed files with 381 additions and 347 deletions.
153 changes: 77 additions & 76 deletions api/revanced-patcher.api
Original file line number Diff line number Diff line change
Expand Up @@ -7,54 +7,56 @@ public final class app/revanced/patcher/PackageMetadata {
public final fun getPackageVersion ()Ljava/lang/String;
}

public abstract class app/revanced/patcher/PatchBundleLoader : java/util/List, kotlin/jvm/internal/markers/KMutableList {
public synthetic fun <init> (Ljava/lang/Iterable;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun add (ILjava/lang/Class;)V
public synthetic fun add (ILjava/lang/Object;)V
public fun add (Ljava/lang/Class;)Z
public synthetic fun add (Ljava/lang/Object;)Z
public fun addAll (ILjava/util/Collection;)Z
public fun addAll (Ljava/util/Collection;)Z
public abstract class app/revanced/patcher/PatchBundleLoader : java/util/Map, kotlin/jvm/internal/markers/KMappedMarker {
public synthetic fun <init> (Ljava/lang/ClassLoader;[Ljava/io/File;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun clear ()V
public fun contains (Ljava/lang/Class;)Z
public final fun contains (Ljava/lang/Object;)Z
public fun containsAll (Ljava/util/Collection;)Z
public fun get (I)Ljava/lang/Class;
public synthetic fun get (I)Ljava/lang/Object;
public synthetic fun compute (Ljava/lang/Object;Ljava/util/function/BiFunction;)Ljava/lang/Object;
public fun compute (Ljava/lang/String;Ljava/util/function/BiFunction;)Lapp/revanced/patcher/patch/Patch;
public synthetic fun computeIfAbsent (Ljava/lang/Object;Ljava/util/function/Function;)Ljava/lang/Object;
public fun computeIfAbsent (Ljava/lang/String;Ljava/util/function/Function;)Lapp/revanced/patcher/patch/Patch;
public synthetic fun computeIfPresent (Ljava/lang/Object;Ljava/util/function/BiFunction;)Ljava/lang/Object;
public fun computeIfPresent (Ljava/lang/String;Ljava/util/function/BiFunction;)Lapp/revanced/patcher/patch/Patch;
public final fun containsKey (Ljava/lang/Object;)Z
public fun containsKey (Ljava/lang/String;)Z
public fun containsValue (Lapp/revanced/patcher/patch/Patch;)Z
public final fun containsValue (Ljava/lang/Object;)Z
public final fun entrySet ()Ljava/util/Set;
public final fun get (Ljava/lang/Object;)Lapp/revanced/patcher/patch/Patch;
public final synthetic fun get (Ljava/lang/Object;)Ljava/lang/Object;
public fun get (Ljava/lang/String;)Lapp/revanced/patcher/patch/Patch;
public fun getEntries ()Ljava/util/Set;
public fun getKeys ()Ljava/util/Set;
public fun getSize ()I
public fun indexOf (Ljava/lang/Class;)I
public final fun indexOf (Ljava/lang/Object;)I
public fun getValues ()Ljava/util/Collection;
public fun isEmpty ()Z
public fun iterator ()Ljava/util/Iterator;
public fun lastIndexOf (Ljava/lang/Class;)I
public final fun lastIndexOf (Ljava/lang/Object;)I
public fun listIterator ()Ljava/util/ListIterator;
public fun listIterator (I)Ljava/util/ListIterator;
public final fun remove (I)Ljava/lang/Class;
public synthetic fun remove (I)Ljava/lang/Object;
public fun remove (Ljava/lang/Class;)Z
public final fun remove (Ljava/lang/Object;)Z
public fun removeAll (Ljava/util/Collection;)Z
public fun removeAt (I)Ljava/lang/Class;
public fun retainAll (Ljava/util/Collection;)Z
public fun set (ILjava/lang/Class;)Ljava/lang/Class;
public synthetic fun set (ILjava/lang/Object;)Ljava/lang/Object;
public final fun keySet ()Ljava/util/Set;
public synthetic fun merge (Ljava/lang/Object;Ljava/lang/Object;Ljava/util/function/BiFunction;)Ljava/lang/Object;
public fun merge (Ljava/lang/String;Lapp/revanced/patcher/patch/Patch;Ljava/util/function/BiFunction;)Lapp/revanced/patcher/patch/Patch;
public synthetic fun put (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
public fun put (Ljava/lang/String;Lapp/revanced/patcher/patch/Patch;)Lapp/revanced/patcher/patch/Patch;
public fun putAll (Ljava/util/Map;)V
public synthetic fun putIfAbsent (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
public fun putIfAbsent (Ljava/lang/String;Lapp/revanced/patcher/patch/Patch;)Lapp/revanced/patcher/patch/Patch;
public fun remove (Ljava/lang/Object;)Lapp/revanced/patcher/patch/Patch;
public synthetic fun remove (Ljava/lang/Object;)Ljava/lang/Object;
public fun remove (Ljava/lang/Object;Ljava/lang/Object;)Z
public synthetic fun replace (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
public synthetic fun replace (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Z
public fun replace (Ljava/lang/String;Lapp/revanced/patcher/patch/Patch;)Lapp/revanced/patcher/patch/Patch;
public fun replace (Ljava/lang/String;Lapp/revanced/patcher/patch/Patch;Lapp/revanced/patcher/patch/Patch;)Z
public fun replaceAll (Ljava/util/function/BiFunction;)V
public final fun size ()I
public fun subList (II)Ljava/util/List;
public fun toArray ()[Ljava/lang/Object;
public fun toArray ([Ljava/lang/Object;)[Ljava/lang/Object;
public final fun values ()Ljava/util/Collection;
}

public final class app/revanced/patcher/PatchBundleLoader$Dex : app/revanced/patcher/PatchBundleLoader {
public fun <init> ([Ljava/io/File;)V
public fun <init> ([Ljava/io/File;Ljava/io/File;)V
public synthetic fun <init> ([Ljava/io/File;Ljava/io/File;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public synthetic fun remove (I)Ljava/lang/Object;
}

public final class app/revanced/patcher/PatchBundleLoader$Jar : app/revanced/patcher/PatchBundleLoader {
public fun <init> ([Ljava/io/File;)V
public synthetic fun remove (I)Ljava/lang/Object;
}

public abstract interface class app/revanced/patcher/PatchExecutorFunction : java/util/function/Function {
Expand All @@ -76,6 +78,14 @@ public final class app/revanced/patcher/PatcherContext {
public final fun getPackageMetadata ()Lapp/revanced/patcher/PackageMetadata;
}

public abstract class app/revanced/patcher/PatcherException : java/lang/Exception {
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/Throwable;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
public synthetic fun <init> (Ljava/lang/String;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
}

public final class app/revanced/patcher/PatcherException$CircularDependencyException : app/revanced/patcher/PatcherException {
}

public final class app/revanced/patcher/PatcherOptions {
public fun <init> (Ljava/io/File;Ljava/io/File;Ljava/lang/String;Ljava/lang/String;)V
public synthetic fun <init> (Ljava/io/File;Ljava/io/File;Ljava/lang/String;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
Expand Down Expand Up @@ -115,23 +125,6 @@ public abstract interface class app/revanced/patcher/PatchesConsumer {
public abstract fun acceptPatches (Ljava/util/List;)V
}

public abstract interface annotation class app/revanced/patcher/annotation/Compatibility : java/lang/annotation/Annotation {
public abstract fun compatiblePackages ()[Lapp/revanced/patcher/annotation/Package;
}

public abstract interface annotation class app/revanced/patcher/annotation/Description : java/lang/annotation/Annotation {
public abstract fun description ()Ljava/lang/String;
}

public abstract interface annotation class app/revanced/patcher/annotation/Name : java/lang/annotation/Annotation {
public abstract fun name ()Ljava/lang/String;
}

public abstract interface annotation class app/revanced/patcher/annotation/Package : java/lang/annotation/Annotation {
public abstract fun name ()Ljava/lang/String;
public abstract fun versions ()[Ljava/lang/String;
}

public final class app/revanced/patcher/data/BytecodeContext : app/revanced/patcher/data/Context {
public final fun findClass (Ljava/lang/String;)Lapp/revanced/patcher/util/proxy/ClassProxy;
public final fun findClass (Lkotlin/jvm/functions/Function1;)Lapp/revanced/patcher/util/proxy/ClassProxy;
Expand Down Expand Up @@ -199,17 +192,6 @@ public final class app/revanced/patcher/extensions/InstructionExtensions {
public final class app/revanced/patcher/extensions/MethodFingerprintExtensions {
public static final field INSTANCE Lapp/revanced/patcher/extensions/MethodFingerprintExtensions;
public final fun getFuzzyPatternScanMethod (Lapp/revanced/patcher/fingerprint/method/impl/MethodFingerprint;)Lapp/revanced/patcher/fingerprint/method/annotation/FuzzyPatternScanMethod;
public final fun getName (Lapp/revanced/patcher/fingerprint/method/impl/MethodFingerprint;)Ljava/lang/String;
}

public final class app/revanced/patcher/extensions/PatchExtensions {
public static final field INSTANCE Lapp/revanced/patcher/extensions/PatchExtensions;
public final fun getCompatiblePackages (Ljava/lang/Class;)[Lapp/revanced/patcher/annotation/Package;
public final fun getDependencies (Ljava/lang/Class;)[Lkotlin/reflect/KClass;
public final fun getDescription (Ljava/lang/Class;)Ljava/lang/String;
public final fun getInclude (Ljava/lang/Class;)Z
public final fun getOptions (Ljava/lang/Class;)Lapp/revanced/patcher/patch/PatchOptions;
public final fun getPatchName (Ljava/lang/Class;)Ljava/lang/String;
}

public abstract interface class app/revanced/patcher/fingerprint/Fingerprint {
Expand Down Expand Up @@ -345,9 +327,7 @@ public final class app/revanced/patcher/logging/impl/NopLogger : app/revanced/pa
}

public abstract class app/revanced/patcher/patch/BytecodePatch : app/revanced/patcher/patch/Patch {
public fun <init> ()V
public fun <init> (Ljava/lang/Iterable;)V
public synthetic fun <init> (Ljava/lang/Iterable;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun <init> (Lapp/revanced/patcher/patch/Patch$Manifest;[Lapp/revanced/patcher/fingerprint/method/impl/MethodFingerprint;)V
}

public final class app/revanced/patcher/patch/IllegalValueException : java/lang/Exception {
Expand All @@ -372,8 +352,34 @@ public abstract class app/revanced/patcher/patch/OptionsContainer {
protected final fun option (Lapp/revanced/patcher/patch/PatchOption;)Lapp/revanced/patcher/patch/PatchOption;
}

public abstract interface class app/revanced/patcher/patch/Patch {
public abstract class app/revanced/patcher/patch/Patch {
public synthetic fun <init> (Lapp/revanced/patcher/patch/Patch$Manifest;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun equals (Ljava/lang/Object;)Z
public abstract fun execute (Lapp/revanced/patcher/data/Context;)V
public final fun getManifest ()Lapp/revanced/patcher/patch/Patch$Manifest;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}

public final class app/revanced/patcher/patch/Patch$Manifest {
public fun <init> (Ljava/lang/String;Ljava/lang/String;ZLjava/util/Set;Ljava/util/Set;ZLapp/revanced/patcher/patch/PatchOptions;)V
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/String;ZLjava/util/Set;Ljava/util/Set;ZLapp/revanced/patcher/patch/PatchOptions;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun equals (Ljava/lang/Object;)Z
public final fun getCompatiblePackages ()Ljava/util/Set;
public final fun getDependencies ()Ljava/util/Set;
public final fun getDescription ()Ljava/lang/String;
public final fun getName ()Ljava/lang/String;
public final fun getOptions ()Lapp/revanced/patcher/patch/PatchOptions;
public final fun getRequiresIntegrations ()Z
public final fun getUse ()Z
public fun hashCode ()I
}

public final class app/revanced/patcher/patch/Patch$Manifest$CompatiblePackage {
public fun <init> (Ljava/lang/String;Ljava/util/Set;)V
public synthetic fun <init> (Ljava/lang/String;Ljava/util/Set;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun getName ()Ljava/lang/String;
public final fun getVersions ()Ljava/util/Set;
}

public final class app/revanced/patcher/patch/PatchException : java/lang/Exception {
Expand Down Expand Up @@ -429,26 +435,21 @@ public final class app/revanced/patcher/patch/PatchOptions : java/lang/Iterable,
}

public final class app/revanced/patcher/patch/PatchResult {
public fun equals (Ljava/lang/Object;)Z
public final fun getException ()Lapp/revanced/patcher/patch/PatchException;
public final fun getPatchName ()Ljava/lang/String;
public final fun getPatch ()Lapp/revanced/patcher/patch/Patch;
public fun hashCode ()I
}

public final class app/revanced/patcher/patch/RequirementNotMetException : java/lang/Exception {
public static final field INSTANCE Lapp/revanced/patcher/patch/RequirementNotMetException;
}

public abstract interface class app/revanced/patcher/patch/ResourcePatch : app/revanced/patcher/patch/Patch {
}

public abstract interface annotation class app/revanced/patcher/patch/annotations/DependsOn : java/lang/annotation/Annotation {
public abstract fun dependencies ()[Ljava/lang/Class;
public abstract class app/revanced/patcher/patch/ResourcePatch : app/revanced/patcher/patch/Patch {
public fun <init> (Lapp/revanced/patcher/patch/Patch$Manifest;)V
}

public abstract interface annotation class app/revanced/patcher/patch/annotations/Patch : java/lang/annotation/Annotation {
public abstract fun include ()Z
}

public abstract interface annotation class app/revanced/patcher/patch/annotations/RequiresIntegrations : java/lang/annotation/Annotation {
}

public final class app/revanced/patcher/util/DomFileEditor : java/io/Closeable {
Expand Down
115 changes: 79 additions & 36 deletions src/main/kotlin/app/revanced/patcher/PatchBundleLoader.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,36 +3,85 @@
package app.revanced.patcher

import app.revanced.patcher.extensions.AnnotationExtensions.findAnnotationRecursively
import app.revanced.patcher.extensions.PatchExtensions.patchName
import app.revanced.patcher.patch.Patch
import app.revanced.patcher.patch.PatchClass
import dalvik.system.DexClassLoader
import lanchon.multidexlib2.BasicDexFileNamer
import lanchon.multidexlib2.MultiDexIO
import java.io.File
import java.net.URLClassLoader
import java.util.jar.JarFile
import java.util.logging.Logger
import kotlin.reflect.KClass

/**
* A patch bundle.
*
* [Patch]es mapped by their name.
*/
typealias PatchMap = Map<String, Patch<*>>

/**
* A [Patch] class.
*/
typealias PatchClass = KClass<out Patch<*>>

/**
* A loader of [Patch]es from patch bundles.
* This will load all [Patch]es from the given patch bundles.
*
* @param fromClasses The classes to get [Patch]es from.
* @param getBinaryClassNames A function that returns the binary names of all classes in a patch bundle.
* @param classLoader The [ClassLoader] to use for loading the classes.
*/
sealed class PatchBundleLoader private constructor(
fromClasses: Iterable<Class<*>>
) : MutableList<PatchClass> by mutableListOf() {
classLoader: ClassLoader,
patchBundles: Array<out File>,
getBinaryClassNames: (patchBundle: File) -> List<String>,
) : PatchMap by mutableMapOf() {
private val logger = Logger.getLogger(PatchBundleLoader::class.java.name)

init {
fromClasses.filter {
patchBundles.flatMap(getBinaryClassNames).map {
classLoader.loadClass(it)
}.filter {
if (it.isAnnotation) return@filter false

it.findAnnotationRecursively(app.revanced.patcher.patch.annotations.Patch::class) != null
}.map {
}.mapNotNull { patchClass ->
patchClass.getInstance(logger)
}.associateBy { it.manifest.name }
let { patches ->
@Suppress("UNCHECKED_CAST")
it as PatchClass
}.sortedBy {
it.patchName
}.let { addAll(it) }
(this as MutableMap<String, Patch<*>>).putAll(patches)
}
}


internal companion object Utils {
/**
* Instantiates a [Patch]. If the class is a singleton, the INSTANCE field will be used.
*
* @param logger The [Logger] to use for logging.
* @return The instantiated [Patch] or `null` if the [Patch] could not be instantiated.
*/
internal fun Class<*>.getInstance(logger: Logger): Patch<*>? {
return try {
getField("INSTANCE").get(null)
} catch (exception: NoSuchFileException) {
logger.fine(
"Patch class '${name}' has no INSTANCE field, therefor not a singleton. " +
"Will try to instantiate it."
)

try {
getDeclaredConstructor().newInstance()
} catch (exception: Exception) {
logger.severe(
"Patch class '${name}' is not singleton and has no suitable constructor, " +
"therefor cannot be instantiated and will be ignored."
)

return null
}
} as Patch<*>
}
}

/**
Expand All @@ -41,18 +90,13 @@ sealed class PatchBundleLoader private constructor(
* @param patchBundles The path to patch bundles of JAR format.
*/
class Jar(vararg patchBundles: File) : PatchBundleLoader(
with(
URLClassLoader(patchBundles.map { it.toURI().toURL() }.toTypedArray())
) {
patchBundles.flatMap { patchBundle ->
// Get the names of all classes in the DEX file.

JarFile(patchBundle).entries().asSequence()
.filter { it.name.endsWith(".class") }
.map { it.name.replace('/', '.').replace(".class", "") }
.map { loadClass(it) }
}
})
URLClassLoader(patchBundles.map { it.toURI().toURL() }.toTypedArray()),
patchBundles,
{ patchBundle ->
JarFile(patchBundle).entries().toList().filter { it.name.endsWith(".class") }
.map { it.name.replace('/', '.').replace(".class", "") }
}
)

/**
* A [PatchBundleLoader] for [Dex] files.
Expand All @@ -62,20 +106,19 @@ sealed class PatchBundleLoader private constructor(
* This parameter is deprecated and has no effect since API level 26.
*/
class Dex(vararg patchBundles: File, optimizedDexDirectory: File? = null) : PatchBundleLoader(
with(
DexClassLoader(
DexClassLoader(
patchBundles.joinToString(File.pathSeparator) { it.absolutePath }, optimizedDexDirectory?.absolutePath,
null,
PatchBundleLoader::class.java.classLoader
)
) {
patchBundles
.flatMap {
MultiDexIO.readDexFile(true, it, BasicDexFileNamer(), null, null).classes
}
.map { classDef -> classDef.type.substring(1, classDef.length - 1) }
.map { loadClass(it) }
}) {
),
patchBundles,
{ patchBundle ->
MultiDexIO.readDexFile(true, patchBundle, BasicDexFileNamer(), null, null).classes
.map { classDef ->
classDef.type.substring(1, classDef.length - 1)
}
}
) {
@Deprecated("This constructor is deprecated. Use the constructor with the second parameter instead.")
constructor(vararg patchBundles: File) : this(*patchBundles, optimizedDexDirectory = null)
}
Expand Down
Loading

0 comments on commit 3b4db3d

Please sign in to comment.