feat: properly make use of logging facade

This deprecates the primary constructor of `PatcherOptions` with the `logger` parameter
This commit is contained in:
oSumAtrIX 2023-08-24 04:43:16 +02:00
parent ccccf5b1d2
commit ba56a6a2ee
No known key found for this signature in database
GPG key ID: A9B3094ACDB604B4
7 changed files with 72 additions and 43 deletions

View file

@ -15,6 +15,7 @@ import java.io.File
import java.util.function.Supplier import java.util.function.Supplier
import java.util.logging.Level import java.util.logging.Level
import java.util.logging.LogManager import java.util.logging.LogManager
import java.util.logging.Logger
/** /**
* ReVanced Patcher. * ReVanced Patcher.
@ -24,6 +25,8 @@ import java.util.logging.LogManager
class Patcher( class Patcher(
private val options: PatcherOptions private val options: PatcherOptions
) : PatchExecutorFunction, PatchesConsumer, IntegrationsConsumer, Supplier<PatcherResult>, Closeable { ) : PatchExecutorFunction, PatchesConsumer, IntegrationsConsumer, Supplier<PatcherResult>, Closeable {
private val logger = Logger.getLogger(Patcher::class.java.name)
/** /**
* The context of ReVanced [Patcher]. * The context of ReVanced [Patcher].
* This holds the current state of the patcher. * This holds the current state of the patcher.
@ -159,7 +162,7 @@ class Patcher(
if (options.resourceDecodingMode == ResourceContext.ResourceDecodingMode.FULL) if (options.resourceDecodingMode == ResourceContext.ResourceDecodingMode.FULL)
context.resourceContext.decodeResources(ResourceContext.ResourceDecodingMode.FULL) context.resourceContext.decodeResources(ResourceContext.ResourceDecodingMode.FULL)
options.logger.info("Executing patches") logger.info("Executing patches")
val executedPatches = LinkedHashMap<String, ExecutedPatch>() // Key is name. val executedPatches = LinkedHashMap<String, ExecutedPatch>() // Key is name.

View file

@ -1,10 +1,10 @@
package app.revanced.patcher package app.revanced.patcher
import app.revanced.patcher.data.ResourceContext import app.revanced.patcher.data.ResourceContext
import app.revanced.patcher.logging.Logger
import app.revanced.patcher.logging.impl.NopLogger import app.revanced.patcher.logging.impl.NopLogger
import brut.androlib.Config import brut.androlib.Config
import java.io.File import java.io.File
import java.util.logging.Logger
/** /**
* Options for ReVanced [Patcher]. * Options for ReVanced [Patcher].
@ -12,15 +12,19 @@ import java.io.File
* @param resourceCachePath The path to the directory to use for caching resources. * @param resourceCachePath The path to the directory to use for caching resources.
* @param aaptBinaryPath The path to a custom aapt binary. * @param aaptBinaryPath The path to a custom aapt binary.
* @param frameworkFileDirectory The path to the directory to cache the framework file in. * @param frameworkFileDirectory The path to the directory to cache the framework file in.
* @param logger A [Logger]. * @param unusedLogger The logger to use for logging.
*/ */
data class PatcherOptions( data class PatcherOptions
@Deprecated("Use the constructor without the logger parameter instead")
constructor(
internal val inputFile: File, internal val inputFile: File,
internal val resourceCachePath: File = File("revanced-resource-cache"), internal val resourceCachePath: File = File("revanced-resource-cache"),
internal val aaptBinaryPath: String? = null, internal val aaptBinaryPath: String? = null,
internal val frameworkFileDirectory: String? = null, internal val frameworkFileDirectory: String? = null,
internal val logger: Logger = NopLogger internal val unusedLogger: app.revanced.patcher.logging.Logger = NopLogger
) { ) {
private val logger = Logger.getLogger(PatcherOptions::class.java.name)
/** /**
* The mode to use for resource decoding. * The mode to use for resource decoding.
* @see ResourceContext.ResourceDecodingMode * @see ResourceContext.ResourceDecodingMode
@ -36,12 +40,32 @@ data class PatcherOptions(
frameworkDirectory = frameworkFileDirectory frameworkDirectory = frameworkFileDirectory
} }
/**
* Options for ReVanced [Patcher].
* @param inputFile The input file to patch.
* @param resourceCachePath The path to the directory to use for caching resources.
* @param aaptBinaryPath The path to a custom aapt binary.
* @param frameworkFileDirectory The path to the directory to cache the framework file in.
*/
constructor(
inputFile: File,
resourceCachePath: File = File("revanced-resource-cache"),
aaptBinaryPath: String? = null,
frameworkFileDirectory: String? = null,
) : this(
inputFile,
resourceCachePath,
aaptBinaryPath,
frameworkFileDirectory,
NopLogger
)
fun recreateResourceCacheDirectory() = resourceCachePath.also { fun recreateResourceCacheDirectory() = resourceCachePath.also {
if (it.exists()) { if (it.exists()) {
logger.info("Deleting existing resource cache directory") logger.info("Deleting existing resource cache directory")
if (!it.deleteRecursively()) if (!it.deleteRecursively())
logger.error("Failed to delete existing resource cache directory") logger.severe("Failed to delete existing resource cache directory")
} }
it.mkdirs() it.mkdirs()

View file

@ -1,8 +1,10 @@
package app.revanced.patcher.data package app.revanced.patcher.data
import app.revanced.patcher.PatcherContext
import app.revanced.patcher.PatcherOptions import app.revanced.patcher.PatcherOptions
import app.revanced.patcher.PatcherResult import app.revanced.patcher.PatcherResult
import app.revanced.patcher.logging.Logger import app.revanced.patcher.patch.Patch
import app.revanced.patcher.patch.annotations.RequiresIntegrations
import app.revanced.patcher.util.ClassMerger.merge import app.revanced.patcher.util.ClassMerger.merge
import app.revanced.patcher.util.ProxyClassList import app.revanced.patcher.util.ProxyClassList
import app.revanced.patcher.util.method.MethodWalker import app.revanced.patcher.util.method.MethodWalker
@ -17,6 +19,7 @@ import lanchon.multidexlib2.DexIO
import lanchon.multidexlib2.MultiDexIO import lanchon.multidexlib2.MultiDexIO
import java.io.File import java.io.File
import java.io.Flushable import java.io.Flushable
import java.util.logging.Logger
/** /**
* A context for bytecode. * A context for bytecode.
@ -26,6 +29,8 @@ import java.io.Flushable
*/ */
class BytecodeContext internal constructor(private val options: PatcherOptions) : class BytecodeContext internal constructor(private val options: PatcherOptions) :
Context<List<PatcherResult.PatchedDexFile>> { Context<List<PatcherResult.PatchedDexFile>> {
private val logger = Logger.getLogger(BytecodeContext::class.java.name)
/** /**
* [Opcodes] of the supplied [PatcherOptions.inputFile]. * [Opcodes] of the supplied [PatcherOptions.inputFile].
*/ */
@ -45,7 +50,7 @@ class BytecodeContext internal constructor(private val options: PatcherOptions)
/** /**
* The [Integrations] of this [PatcherContext]. * The [Integrations] of this [PatcherContext].
*/ */
internal val integrations = Integrations(options.logger) internal val integrations = Integrations()
/** /**
* Find a class by a given class name. * Find a class by a given class name.
@ -88,10 +93,8 @@ class BytecodeContext internal constructor(private val options: PatcherOptions)
/** /**
* The integrations of a [PatcherContext]. * The integrations of a [PatcherContext].
*
* @param logger The logger to use.
*/ */
internal inner class Integrations(private val logger: Logger) : MutableList<File> by mutableListOf(), Flushable { internal inner class Integrations : MutableList<File> by mutableListOf(), Flushable {
/** /**
* Whether to merge integrations. * Whether to merge integrations.
* True when any supplied [Patch] is annotated with [RequiresIntegrations]. * True when any supplied [Patch] is annotated with [RequiresIntegrations].
@ -112,14 +115,14 @@ class BytecodeContext internal constructor(private val options: PatcherOptions)
null null
).classes.forEach classDef@{ classDef -> ).classes.forEach classDef@{ classDef ->
val existingClass = classes.find { it == classDef } ?: run { val existingClass = classes.find { it == classDef } ?: run {
logger.trace("Merging $classDef") logger.fine("Merging $classDef")
classes.add(classDef) classes.add(classDef)
return@classDef return@classDef
} }
logger.trace("$classDef exists. Adding missing methods and fields.") logger.fine("$classDef exists. Adding missing methods and fields.")
existingClass.merge(classDef, this@BytecodeContext, logger).let { mergedClass -> existingClass.merge(classDef, this@BytecodeContext).let { mergedClass ->
// If the class was merged, replace the original class with the merged class. // If the class was merged, replace the original class with the merged class.
if (mergedClass === existingClass) return@let if (mergedClass === existingClass) return@let
classes.apply { remove(existingClass); add(mergedClass) } classes.apply { remove(existingClass); add(mergedClass) }
@ -137,7 +140,7 @@ class BytecodeContext internal constructor(private val options: PatcherOptions)
* @return The compiled bytecode. * @return The compiled bytecode.
*/ */
override fun get(): List<PatcherResult.PatchedDexFile> { override fun get(): List<PatcherResult.PatchedDexFile> {
options.logger.info("Compiling modified dex files") logger.info("Compiling modified dex files")
return mutableMapOf<String, MemoryDataStore>().apply { return mutableMapOf<String, MemoryDataStore>().apply {
MultiDexIO.writeDexFile( MultiDexIO.writeDexFile(

View file

@ -16,6 +16,7 @@ import java.io.File
import java.io.InputStream import java.io.InputStream
import java.io.OutputStream import java.io.OutputStream
import java.nio.file.Files import java.nio.file.Files
import java.util.logging.Logger
/** /**
* A context for resources. * A context for resources.
@ -27,6 +28,8 @@ class ResourceContext internal constructor(
private val context: PatcherContext, private val context: PatcherContext,
private val options: PatcherOptions private val options: PatcherOptions
) : Context<File?>, Iterable<File> { ) : Context<File?>, Iterable<File> {
private val logger = Logger.getLogger(ResourceContext::class.java.name)
val xmlEditor = XmlFileHolder() val xmlEditor = XmlFileHolder()
/** /**
@ -42,7 +45,7 @@ class ResourceContext internal constructor(
ResourceDecodingMode.FULL -> { ResourceDecodingMode.FULL -> {
val outDir = options.recreateResourceCacheDirectory() val outDir = options.recreateResourceCacheDirectory()
options.logger.info("Decoding resources") logger.info("Decoding resources")
resourcesDecoder.decodeResources(outDir) resourcesDecoder.decodeResources(outDir)
resourcesDecoder.decodeManifest(outDir) resourcesDecoder.decodeManifest(outDir)
@ -57,7 +60,7 @@ class ResourceContext internal constructor(
} }
ResourceDecodingMode.MANIFEST_ONLY -> { ResourceDecodingMode.MANIFEST_ONLY -> {
options.logger.info("Decoding app manifest") logger.info("Decoding app manifest")
// Decode manually instead of using resourceDecoder.decodeManifest // Decode manually instead of using resourceDecoder.decodeManifest
// because it does not support decoding to an OutputStream. // because it does not support decoding to an OutputStream.
@ -100,7 +103,7 @@ class ResourceContext internal constructor(
var resourceFile: File? = null var resourceFile: File? = null
if (options.resourceDecodingMode == ResourceDecodingMode.FULL) { if (options.resourceDecodingMode == ResourceDecodingMode.FULL) {
options.logger.info("Compiling modified resources") logger.info("Compiling modified resources")
val cacheDirectory = ExtFile(options.resourceCachePath) val cacheDirectory = ExtFile(options.resourceCachePath)
val aaptFile = cacheDirectory.resolve("aapt_temp_file").also { val aaptFile = cacheDirectory.resolve("aapt_temp_file").also {

View file

@ -1,5 +1,6 @@
package app.revanced.patcher.logging package app.revanced.patcher.logging
@Deprecated("This will be removed in a future release")
interface Logger { interface Logger {
fun error(msg: String) {} fun error(msg: String) {}
fun warn(msg: String) {} fun warn(msg: String) {}

View file

@ -2,4 +2,5 @@ package app.revanced.patcher.logging.impl
import app.revanced.patcher.logging.Logger import app.revanced.patcher.logging.Logger
@Deprecated("This will be removed in a future release")
object NopLogger : Logger object NopLogger : Logger

View file

@ -2,7 +2,6 @@ package app.revanced.patcher.util
import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.or import app.revanced.patcher.extensions.or
import app.revanced.patcher.logging.Logger
import app.revanced.patcher.util.ClassMerger.Utils.asMutableClass import app.revanced.patcher.util.ClassMerger.Utils.asMutableClass
import app.revanced.patcher.util.ClassMerger.Utils.filterAny import app.revanced.patcher.util.ClassMerger.Utils.filterAny
import app.revanced.patcher.util.ClassMerger.Utils.filterNotAny import app.revanced.patcher.util.ClassMerger.Utils.filterNotAny
@ -18,6 +17,7 @@ import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMu
import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.iface.ClassDef import com.android.tools.smali.dexlib2.iface.ClassDef
import com.android.tools.smali.dexlib2.util.MethodUtil import com.android.tools.smali.dexlib2.util.MethodUtil
import java.util.logging.Logger
import kotlin.reflect.KFunction2 import kotlin.reflect.KFunction2
/** /**
@ -25,28 +25,28 @@ import kotlin.reflect.KFunction2
* Note: This will not consider method implementations or if the class is missing a superclass or interfaces. * Note: This will not consider method implementations or if the class is missing a superclass or interfaces.
*/ */
internal object ClassMerger { internal object ClassMerger {
private val logger = Logger.getLogger(ClassMerger::class.java.name)
/** /**
* Merge a class with [otherClass]. * Merge a class with [otherClass].
* *
* @param otherClass The class to merge with * @param otherClass The class to merge with
* @param context The context to traverse the class hierarchy in. * @param context The context to traverse the class hierarchy in.
* @param logger A logger.
* @return The merged class or the original class if no merge was needed. * @return The merged class or the original class if no merge was needed.
*/ */
fun ClassDef.merge(otherClass: ClassDef, context: BytecodeContext, logger: Logger? = null) = this fun ClassDef.merge(otherClass: ClassDef, context: BytecodeContext) = this
//.fixFieldAccess(otherClass, logger) //.fixFieldAccess(otherClass)
//.fixMethodAccess(otherClass, logger) //.fixMethodAccess(otherClass)
.addMissingFields(otherClass, logger) .addMissingFields(otherClass)
.addMissingMethods(otherClass, logger) .addMissingMethods(otherClass)
.publicize(otherClass, context, logger) .publicize(otherClass, context)
/** /**
* Add methods which are missing but existing in [fromClass]. * Add methods which are missing but existing in [fromClass].
* *
* @param fromClass The class to add missing methods from. * @param fromClass The class to add missing methods from.
* @param logger A logger.
*/ */
private fun ClassDef.addMissingMethods(fromClass: ClassDef, logger: Logger? = null): ClassDef { private fun ClassDef.addMissingMethods(fromClass: ClassDef): ClassDef {
val missingMethods = fromClass.methods.let { fromMethods -> val missingMethods = fromClass.methods.let { fromMethods ->
methods.filterNot { method -> methods.filterNot { method ->
fromMethods.any { fromMethod -> fromMethods.any { fromMethod ->
@ -57,7 +57,7 @@ internal object ClassMerger {
if (missingMethods.isEmpty()) return this if (missingMethods.isEmpty()) return this
logger?.trace("Found ${missingMethods.size} missing methods") logger.fine("Found ${missingMethods.size} missing methods")
return asMutableClass().apply { return asMutableClass().apply {
methods.addAll(missingMethods.map { it.toMutable() }) methods.addAll(missingMethods.map { it.toMutable() })
@ -68,16 +68,15 @@ internal object ClassMerger {
* Add fields which are missing but existing in [fromClass]. * Add fields which are missing but existing in [fromClass].
* *
* @param fromClass The class to add missing fields from. * @param fromClass The class to add missing fields from.
* @param logger A logger.
*/ */
private fun ClassDef.addMissingFields(fromClass: ClassDef, logger: Logger? = null): ClassDef { private fun ClassDef.addMissingFields(fromClass: ClassDef): ClassDef {
val missingFields = fields.filterNotAny(fromClass.fields) { field, fromField -> val missingFields = fields.filterNotAny(fromClass.fields) { field, fromField ->
fromField.name == field.name fromField.name == field.name
} }
if (missingFields.isEmpty()) return this if (missingFields.isEmpty()) return this
logger?.trace("Found ${missingFields.size} missing fields") logger.fine("Found ${missingFields.size} missing fields")
return asMutableClass().apply { return asMutableClass().apply {
fields.addAll(missingFields.map { it.toMutable() }) fields.addAll(missingFields.map { it.toMutable() })
@ -88,15 +87,14 @@ internal object ClassMerger {
* Make a class and its super class public recursively. * Make a class and its super class public recursively.
* @param reference The class to check the [AccessFlags] of. * @param reference The class to check the [AccessFlags] of.
* @param context The context to traverse the class hierarchy in. * @param context The context to traverse the class hierarchy in.
* @param logger A logger.
*/ */
private fun ClassDef.publicize(reference: ClassDef, context: BytecodeContext, logger: Logger? = null) = private fun ClassDef.publicize(reference: ClassDef, context: BytecodeContext) =
if (reference.accessFlags.isPublic() && !accessFlags.isPublic()) if (reference.accessFlags.isPublic() && !accessFlags.isPublic())
this.asMutableClass().apply { this.asMutableClass().apply {
context.traverseClassHierarchy(this) { context.traverseClassHierarchy(this) {
if (accessFlags.isPublic()) return@traverseClassHierarchy if (accessFlags.isPublic()) return@traverseClassHierarchy
logger?.trace("Publicizing ${this.type}") logger.fine("Publicizing ${this.type}")
accessFlags = accessFlags.toPublic() accessFlags = accessFlags.toPublic()
} }
@ -107,9 +105,8 @@ internal object ClassMerger {
* Publicize fields if they are public in [reference]. * Publicize fields if they are public in [reference].
* *
* @param reference The class to check the [AccessFlags] of the fields in. * @param reference The class to check the [AccessFlags] of the fields in.
* @param logger A logger.
*/ */
private fun ClassDef.fixFieldAccess(reference: ClassDef, logger: Logger? = null): ClassDef { private fun ClassDef.fixFieldAccess(reference: ClassDef): ClassDef {
val brokenFields = fields.filterAny(reference.fields) { field, referenceField -> val brokenFields = fields.filterAny(reference.fields) { field, referenceField ->
if (field.name != referenceField.name) return@filterAny false if (field.name != referenceField.name) return@filterAny false
@ -118,7 +115,7 @@ internal object ClassMerger {
if (brokenFields.isEmpty()) return this if (brokenFields.isEmpty()) return this
logger?.trace("Found ${brokenFields.size} broken fields") logger.fine("Found ${brokenFields.size} broken fields")
/** /**
* Make a field public. * Make a field public.
@ -136,9 +133,8 @@ internal object ClassMerger {
* Publicize methods if they are public in [reference]. * Publicize methods if they are public in [reference].
* *
* @param reference The class to check the [AccessFlags] of the methods in. * @param reference The class to check the [AccessFlags] of the methods in.
* @param logger A logger.
*/ */
private fun ClassDef.fixMethodAccess(reference: ClassDef, logger: Logger? = null): ClassDef { private fun ClassDef.fixMethodAccess(reference: ClassDef): ClassDef {
val brokenMethods = methods.filterAny(reference.methods) { method, referenceMethod -> val brokenMethods = methods.filterAny(reference.methods) { method, referenceMethod ->
if (!MethodUtil.methodSignaturesMatch(method, referenceMethod)) return@filterAny false if (!MethodUtil.methodSignaturesMatch(method, referenceMethod)) return@filterAny false
@ -147,7 +143,7 @@ internal object ClassMerger {
if (brokenMethods.isEmpty()) return this if (brokenMethods.isEmpty()) return this
logger?.trace("Found ${brokenMethods.size} methods") logger.fine("Found ${brokenMethods.size} methods")
/** /**
* Make a method public. * Make a method public.
@ -194,7 +190,6 @@ internal object ClassMerger {
/** /**
* Filter [this] on [needles] matching the given [predicate]. * Filter [this] on [needles] matching the given [predicate].
* *
* @param this The hay to filter for [needles].
* @param needles The needles to filter [this] with. * @param needles The needles to filter [this] with.
* @param predicate The filter. * @param predicate The filter.
* @return The [this] filtered on [needles] matching the given [predicate]. * @return The [this] filtered on [needles] matching the given [predicate].
@ -206,7 +201,6 @@ internal object ClassMerger {
/** /**
* Filter [this] on [needles] not matching the given [predicate]. * Filter [this] on [needles] not matching the given [predicate].
* *
* @param this The hay to filter for [needles].
* @param needles The needles to filter [this] with. * @param needles The needles to filter [this] with.
* @param predicate The filter. * @param predicate The filter.
* @return The [this] filtered on [needles] not matching the given [predicate]. * @return The [this] filtered on [needles] not matching the given [predicate].