mirror of
https://github.com/ReVanced/revanced-patcher.git
synced 2024-11-10 01:02:22 +01:00
fix: Merge all extensions before initializing lookup maps
This commit is contained in:
parent
736b3eebbf
commit
8c4dd5b3a3
3 changed files with 102 additions and 54 deletions
|
@ -39,9 +39,6 @@ class Patcher(private val config: PatcherConfig) : Closeable {
|
||||||
patch.addRecursively()
|
patch.addRecursively()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Patch<*>.anyRecursively(predicate: (Patch<*>) -> Boolean): Boolean =
|
|
||||||
predicate(this) || dependencies.any { dependency -> dependency.anyRecursively(predicate) }
|
|
||||||
|
|
||||||
context.allPatches.let { allPatches ->
|
context.allPatches.let { allPatches ->
|
||||||
// Check, if what kind of resource mode is required.
|
// Check, if what kind of resource mode is required.
|
||||||
config.resourceMode = if (allPatches.any { patch -> patch.anyRecursively { it is ResourcePatch } }) {
|
config.resourceMode = if (allPatches.any { patch -> patch.anyRecursively { it is ResourcePatch } }) {
|
||||||
|
@ -99,6 +96,17 @@ class Patcher(private val config: PatcherConfig) : Closeable {
|
||||||
context.resourceContext.decodeResources(config.resourceMode)
|
context.resourceContext.decodeResources(config.resourceMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger.info("Merging extensions")
|
||||||
|
|
||||||
|
context.executablePatches.forEachRecursively { patch ->
|
||||||
|
if (patch is BytecodePatch && patch.extension != null) {
|
||||||
|
context.bytecodeContext.merge(patch.extension)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize lookup maps.
|
||||||
|
context.bytecodeContext.lookupMaps
|
||||||
|
|
||||||
logger.info("Executing patches")
|
logger.info("Executing patches")
|
||||||
|
|
||||||
val executedPatches = LinkedHashMap<Patch<*>, PatchResult>()
|
val executedPatches = LinkedHashMap<Patch<*>, PatchResult>()
|
||||||
|
@ -146,7 +154,7 @@ class Patcher(private val config: PatcherConfig) : Closeable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun close() = context.bytecodeContext.lookupMaps.close()
|
override fun close() = context.bytecodeContext.close()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compile and save patched APK files.
|
* Compile and save patched APK files.
|
||||||
|
|
|
@ -31,7 +31,9 @@ import java.util.logging.Logger
|
||||||
* @param config The [PatcherConfig] used to create this context.
|
* @param config The [PatcherConfig] used to create this context.
|
||||||
*/
|
*/
|
||||||
@Suppress("MemberVisibilityCanBePrivate")
|
@Suppress("MemberVisibilityCanBePrivate")
|
||||||
class BytecodePatchContext internal constructor(private val config: PatcherConfig) : PatchContext<Set<PatcherResult.PatchedDexFile>> {
|
class BytecodePatchContext internal constructor(private val config: PatcherConfig) :
|
||||||
|
PatchContext<Set<PatcherResult.PatchedDexFile>>,
|
||||||
|
Closeable {
|
||||||
private val logger = Logger.getLogger(BytecodePatchContext::class.java.name)
|
private val logger = Logger.getLogger(BytecodePatchContext::class.java.name)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -57,6 +59,13 @@ class BytecodePatchContext internal constructor(private val config: PatcherConfi
|
||||||
*/
|
*/
|
||||||
internal val lookupMaps by lazy { LookupMaps(classes) }
|
internal val lookupMaps by lazy { LookupMaps(classes) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A map for lookup by [merge].
|
||||||
|
*/
|
||||||
|
internal val classesByType = mutableMapOf<String, ClassDef>().apply {
|
||||||
|
classes.forEach { classDef -> put(classDef.type, classDef) }
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Merge an extension to [classes].
|
* Merge an extension to [classes].
|
||||||
*
|
*
|
||||||
|
@ -66,11 +75,11 @@ class BytecodePatchContext internal constructor(private val config: PatcherConfi
|
||||||
val extension = extensionInputStream.readAllBytes()
|
val extension = extensionInputStream.readAllBytes()
|
||||||
|
|
||||||
RawDexIO.readRawDexFile(extension, 0, null).classes.forEach { classDef ->
|
RawDexIO.readRawDexFile(extension, 0, null).classes.forEach { classDef ->
|
||||||
val existingClass = lookupMaps.classesByType[classDef.type] ?: run {
|
val existingClass = classesByType[classDef.type] ?: run {
|
||||||
logger.fine("Adding class \"$classDef\"")
|
logger.fine("Adding class \"$classDef\"")
|
||||||
|
|
||||||
lookupMaps.classesByType[classDef.type] = classDef
|
|
||||||
classes += classDef
|
classes += classDef
|
||||||
|
classesByType[classDef.type] = classDef
|
||||||
|
|
||||||
return@forEach
|
return@forEach
|
||||||
}
|
}
|
||||||
|
@ -254,6 +263,12 @@ class BytecodePatchContext internal constructor(private val config: PatcherConfi
|
||||||
methodsByStrings.clear()
|
methodsByStrings.clear()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun close() {
|
||||||
|
lookupMaps.close()
|
||||||
|
classesByType.clear()
|
||||||
|
classes.clear()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -85,6 +85,31 @@ sealed class Patch<C : PatchContext<*>>(
|
||||||
override fun toString() = name ?: "Patch"
|
override fun toString() = name ?: "Patch"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal fun Patch<*>.anyRecursively(
|
||||||
|
visited: MutableSet<Patch<*>> = mutableSetOf(),
|
||||||
|
predicate: (Patch<*>) -> Boolean,
|
||||||
|
): Boolean {
|
||||||
|
if (this in visited) return false
|
||||||
|
|
||||||
|
if (predicate(this)) return true
|
||||||
|
|
||||||
|
visited += this
|
||||||
|
|
||||||
|
return dependencies.any { it.anyRecursively(visited, predicate) }
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun Iterable<Patch<*>>.forEachRecursively(
|
||||||
|
visited: MutableSet<Patch<*>> = mutableSetOf(),
|
||||||
|
action: (Patch<*>) -> Unit,
|
||||||
|
): Unit = forEach {
|
||||||
|
if (it in visited) return@forEach
|
||||||
|
|
||||||
|
visited += it
|
||||||
|
action(it)
|
||||||
|
|
||||||
|
it.dependencies.forEachRecursively(visited, action)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A bytecode patch.
|
* A bytecode patch.
|
||||||
*
|
*
|
||||||
|
@ -127,7 +152,6 @@ class BytecodePatch internal constructor(
|
||||||
finalizeBlock,
|
finalizeBlock,
|
||||||
) {
|
) {
|
||||||
override fun execute(context: PatcherContext) = with(context.bytecodeContext) {
|
override fun execute(context: PatcherContext) = with(context.bytecodeContext) {
|
||||||
extension?.let(::merge)
|
|
||||||
fingerprints.forEach { it.match(this) }
|
fingerprints.forEach { it.match(this) }
|
||||||
|
|
||||||
execute(this)
|
execute(this)
|
||||||
|
@ -332,6 +356,16 @@ sealed class PatchBuilder<C : PatchContext<*>>(
|
||||||
internal abstract fun build(): Patch<C>
|
internal abstract fun build(): Patch<C>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds a [Patch].
|
||||||
|
*
|
||||||
|
* @param B The [PatchBuilder] to build the patch with.
|
||||||
|
* @param block The block to build the patch.
|
||||||
|
*
|
||||||
|
* @return The built [Patch].
|
||||||
|
*/
|
||||||
|
private fun <B : PatchBuilder<*>> B.buildPatch(block: B.() -> Unit = {}) = apply(block).build()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A [BytecodePatchBuilder] builder.
|
* A [BytecodePatchBuilder] builder.
|
||||||
*
|
*
|
||||||
|
@ -379,9 +413,10 @@ class BytecodePatchBuilder internal constructor(
|
||||||
*
|
*
|
||||||
* @param extension The name of the extension resource.
|
* @param extension The name of the extension resource.
|
||||||
*/
|
*/
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
inline fun extendWith(extension: String) = apply {
|
inline fun extendWith(extension: String) = apply {
|
||||||
this.extension = object {}.javaClass.classLoader.getResourceAsStream(extension)
|
this.extension = object {}.javaClass.classLoader.getResourceAsStream(extension)
|
||||||
?: throw PatchException("Extension resource \"$extension\" not found")
|
?: throw PatchException("Extension \"$extension\" not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun build() = BytecodePatch(
|
override fun build() = BytecodePatch(
|
||||||
|
@ -398,6 +433,24 @@ class BytecodePatchBuilder internal constructor(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new [BytecodePatch].
|
||||||
|
*
|
||||||
|
* @param name The name of the patch.
|
||||||
|
* If null, the patch is named "Patch" and will not be loaded by [PatchLoader].
|
||||||
|
* @param description The description of the patch.
|
||||||
|
* @param use Weather or not the patch should be used.
|
||||||
|
* @param block The block to build the patch.
|
||||||
|
*
|
||||||
|
* @return The created [BytecodePatch].
|
||||||
|
*/
|
||||||
|
fun bytecodePatch(
|
||||||
|
name: String? = null,
|
||||||
|
description: String? = null,
|
||||||
|
use: Boolean = true,
|
||||||
|
block: BytecodePatchBuilder.() -> Unit = {},
|
||||||
|
) = BytecodePatchBuilder(name, description, use).buildPatch(block) as BytecodePatch
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A [RawResourcePatch] builder.
|
* A [RawResourcePatch] builder.
|
||||||
*
|
*
|
||||||
|
@ -425,6 +478,23 @@ class RawResourcePatchBuilder internal constructor(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new [RawResourcePatch].
|
||||||
|
*
|
||||||
|
* @param name The name of the patch.
|
||||||
|
* If null, the patch is named "Patch" and will not be loaded by [PatchLoader].
|
||||||
|
* @param description The description of the patch.
|
||||||
|
* @param use Weather or not the patch should be used.
|
||||||
|
* @param block The block to build the patch.
|
||||||
|
* @return The created [RawResourcePatch].
|
||||||
|
*/
|
||||||
|
fun rawResourcePatch(
|
||||||
|
name: String? = null,
|
||||||
|
description: String? = null,
|
||||||
|
use: Boolean = true,
|
||||||
|
block: RawResourcePatchBuilder.() -> Unit = {},
|
||||||
|
) = RawResourcePatchBuilder(name, description, use).buildPatch(block) as RawResourcePatch
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A [ResourcePatch] builder.
|
* A [ResourcePatch] builder.
|
||||||
*
|
*
|
||||||
|
@ -452,51 +522,6 @@ class ResourcePatchBuilder internal constructor(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds a [Patch].
|
|
||||||
*
|
|
||||||
* @param B The [PatchBuilder] to build the patch with.
|
|
||||||
* @param block The block to build the patch.
|
|
||||||
*
|
|
||||||
* @return The built [Patch].
|
|
||||||
*/
|
|
||||||
private fun <B : PatchBuilder<*>> B.buildPatch(block: B.() -> Unit = {}) = apply(block).build()
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new [BytecodePatch].
|
|
||||||
*
|
|
||||||
* @param name The name of the patch.
|
|
||||||
* If null, the patch is named "Patch" and will not be loaded by [PatchLoader].
|
|
||||||
* @param description The description of the patch.
|
|
||||||
* @param use Weather or not the patch should be used.
|
|
||||||
* @param block The block to build the patch.
|
|
||||||
*
|
|
||||||
* @return The created [BytecodePatch].
|
|
||||||
*/
|
|
||||||
fun bytecodePatch(
|
|
||||||
name: String? = null,
|
|
||||||
description: String? = null,
|
|
||||||
use: Boolean = true,
|
|
||||||
block: BytecodePatchBuilder.() -> Unit = {},
|
|
||||||
) = BytecodePatchBuilder(name, description, use).buildPatch(block) as BytecodePatch
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new [RawResourcePatch].
|
|
||||||
*
|
|
||||||
* @param name The name of the patch.
|
|
||||||
* If null, the patch is named "Patch" and will not be loaded by [PatchLoader].
|
|
||||||
* @param description The description of the patch.
|
|
||||||
* @param use Weather or not the patch should be used.
|
|
||||||
* @param block The block to build the patch.
|
|
||||||
* @return The created [RawResourcePatch].
|
|
||||||
*/
|
|
||||||
fun rawResourcePatch(
|
|
||||||
name: String? = null,
|
|
||||||
description: String? = null,
|
|
||||||
use: Boolean = true,
|
|
||||||
block: RawResourcePatchBuilder.() -> Unit = {},
|
|
||||||
) = RawResourcePatchBuilder(name, description, use).buildPatch(block) as RawResourcePatch
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new [ResourcePatch].
|
* Create a new [ResourcePatch].
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in a new issue