Skip to content

Commit

Permalink
fix: Merge extension only when patch executes (#315)
Browse files Browse the repository at this point in the history
  • Loading branch information
oSumAtrIX authored Oct 27, 2024
1 parent ab624f0 commit aa472eb
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 37 deletions.
12 changes: 4 additions & 8 deletions src/main/kotlin/app/revanced/patcher/Patcher.kt
Original file line number Diff line number Diff line change
Expand Up @@ -91,19 +91,15 @@ class Patcher(private val config: PatcherConfig) : Closeable {
}.also { executedPatches[this] = it }
}

// Prevent from decoding the app manifest twice if it is not needed.
// Prevent decoding the app manifest twice if it is not needed.
if (config.resourceMode != ResourcePatchContext.ResourceMode.NONE) {
context.resourceContext.decodeResources(config.resourceMode)
}

logger.info("Merging extensions")
logger.info("Initializing lookup maps")

with(context.bytecodeContext) {
context.executablePatches.mergeExtensions()

// Initialize lookup maps.
lookupMaps
}
// Accessing the lazy lookup maps to initialize them.
context.bytecodeContext.lookupMaps

logger.info("Executing patches")

Expand Down
51 changes: 24 additions & 27 deletions src/main/kotlin/app/revanced/patcher/patch/BytecodePatchContext.kt
Original file line number Diff line number Diff line change
Expand Up @@ -59,42 +59,33 @@ class BytecodePatchContext internal constructor(private val config: PatcherConfi
internal val lookupMaps by lazy { LookupMaps(classes) }

/**
* Merge the extensions for this set of patches.
* Merge the extension of this patch.
*/
internal fun Set<Patch<*>>.mergeExtensions() {
// Lookup map to check if a class exists by its type quickly.
val classesByType = mutableMapOf<String, ClassDef>().apply {
classes.forEach { classDef -> put(classDef.type, classDef) }
}
internal fun BytecodePatch.mergeExtension() {
extension?.use { extensionStream ->
RawDexIO.readRawDexFile(extensionStream, 0, null).classes.forEach { classDef ->
val existingClass = lookupMaps.classesByType[classDef.type] ?: run {
logger.fine("Adding class \"$classDef\"")

forEachRecursively { patch ->
if (patch !is BytecodePatch) return@forEachRecursively
classes += classDef
lookupMaps.classesByType[classDef.type] = classDef

patch.extension?.use { extensionStream ->
RawDexIO.readRawDexFile(extensionStream, 0, null).classes.forEach { classDef ->
val existingClass = classesByType[classDef.type] ?: run {
logger.fine("Adding class \"$classDef\"")
return@forEach
}

classes += classDef
classesByType[classDef.type] = classDef
logger.fine("Class \"$classDef\" exists already. Adding missing methods and fields.")

return@forEach
existingClass.merge(classDef, this@BytecodePatchContext).let { mergedClass ->
// If the class was merged, replace the original class with the merged class.
if (mergedClass === existingClass) {
return@let
}

logger.fine("Class \"$classDef\" exists already. Adding missing methods and fields.")

existingClass.merge(classDef, this@BytecodePatchContext).let { mergedClass ->
// If the class was merged, replace the original class with the merged class.
if (mergedClass === existingClass) {
return@let
}

classes -= existingClass
classes += mergedClass
}
classes -= existingClass
classes += mergedClass
}
}
}
} ?: return logger.fine("No extension to merge")
}

/**
Expand Down Expand Up @@ -185,6 +176,11 @@ class BytecodePatchContext internal constructor(private val config: PatcherConfi
*/
internal val methodsByStrings = MethodClassPairsLookupMap()

// Lookup map for fast checking if a class exists by its type.
val classesByType = mutableMapOf<String, ClassDef>().apply {
classes.forEach { classDef -> put(classDef.type, classDef) }
}

init {
classes.forEach { classDef ->
classDef.methods.forEach { method ->
Expand Down Expand Up @@ -231,6 +227,7 @@ class BytecodePatchContext internal constructor(private val config: PatcherConfi

override fun close() {
methodsByStrings.clear()
classesByType.clear()
}
}

Expand Down
8 changes: 7 additions & 1 deletion src/main/kotlin/app/revanced/patcher/patch/Patch.kt
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,13 @@ class BytecodePatch internal constructor(
finalizeBlock,
) {
override fun execute(context: PatcherContext) = with(context.bytecodeContext) {
fingerprints.forEach { it.match(this) }
with(context.bytecodeContext) {
mergeExtension()
}

fingerprints.forEach {
it.match(this)
}

execute(this)
}
Expand Down
2 changes: 1 addition & 1 deletion src/test/kotlin/app/revanced/patcher/PatcherTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ internal object PatcherTest {
private operator fun Set<Patch<*>>.invoke(): List<PatchResult> {
every { patcher.context.executablePatches } returns toMutableSet()
every { patcher.context.bytecodeContext.lookupMaps } returns LookupMaps(patcher.context.bytecodeContext.classes)
every { with(patcher.context.bytecodeContext) { any<Set<Patch<*>>>().mergeExtensions() } } just runs
every { with(patcher.context.bytecodeContext) { any<BytecodePatch>().mergeExtension() } } just runs

return runBlocking { patcher().toList() }
}
Expand Down

0 comments on commit aa472eb

Please sign in to comment.