Skip to content

Commit aa472eb

Browse files
authored
fix: Merge extension only when patch executes (#315)
1 parent ab624f0 commit aa472eb

File tree

4 files changed

+36
-37
lines changed

4 files changed

+36
-37
lines changed

src/main/kotlin/app/revanced/patcher/Patcher.kt

+4-8
Original file line numberDiff line numberDiff line change
@@ -91,19 +91,15 @@ class Patcher(private val config: PatcherConfig) : Closeable {
9191
}.also { executedPatches[this] = it }
9292
}
9393

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

99-
logger.info("Merging extensions")
99+
logger.info("Initializing lookup maps")
100100

101-
with(context.bytecodeContext) {
102-
context.executablePatches.mergeExtensions()
103-
104-
// Initialize lookup maps.
105-
lookupMaps
106-
}
101+
// Accessing the lazy lookup maps to initialize them.
102+
context.bytecodeContext.lookupMaps
107103

108104
logger.info("Executing patches")
109105

src/main/kotlin/app/revanced/patcher/patch/BytecodePatchContext.kt

+24-27
Original file line numberDiff line numberDiff line change
@@ -59,42 +59,33 @@ class BytecodePatchContext internal constructor(private val config: PatcherConfi
5959
internal val lookupMaps by lazy { LookupMaps(classes) }
6060

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

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

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

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

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

84-
logger.fine("Class \"$classDef\" exists already. Adding missing methods and fields.")
85-
86-
existingClass.merge(classDef, this@BytecodePatchContext).let { mergedClass ->
87-
// If the class was merged, replace the original class with the merged class.
88-
if (mergedClass === existingClass) {
89-
return@let
90-
}
91-
92-
classes -= existingClass
93-
classes += mergedClass
94-
}
84+
classes -= existingClass
85+
classes += mergedClass
9586
}
9687
}
97-
}
88+
} ?: return logger.fine("No extension to merge")
9889
}
9990

10091
/**
@@ -185,6 +176,11 @@ class BytecodePatchContext internal constructor(private val config: PatcherConfi
185176
*/
186177
internal val methodsByStrings = MethodClassPairsLookupMap()
187178

179+
// Lookup map for fast checking if a class exists by its type.
180+
val classesByType = mutableMapOf<String, ClassDef>().apply {
181+
classes.forEach { classDef -> put(classDef.type, classDef) }
182+
}
183+
188184
init {
189185
classes.forEach { classDef ->
190186
classDef.methods.forEach { method ->
@@ -231,6 +227,7 @@ class BytecodePatchContext internal constructor(private val config: PatcherConfi
231227

232228
override fun close() {
233229
methodsByStrings.clear()
230+
classesByType.clear()
234231
}
235232
}
236233

src/main/kotlin/app/revanced/patcher/patch/Patch.kt

+7-1
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,13 @@ class BytecodePatch internal constructor(
158158
finalizeBlock,
159159
) {
160160
override fun execute(context: PatcherContext) = with(context.bytecodeContext) {
161-
fingerprints.forEach { it.match(this) }
161+
with(context.bytecodeContext) {
162+
mergeExtension()
163+
}
164+
165+
fingerprints.forEach {
166+
it.match(this)
167+
}
162168

163169
execute(this)
164170
}

src/test/kotlin/app/revanced/patcher/PatcherTest.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ internal object PatcherTest {
195195
private operator fun Set<Patch<*>>.invoke(): List<PatchResult> {
196196
every { patcher.context.executablePatches } returns toMutableSet()
197197
every { patcher.context.bytecodeContext.lookupMaps } returns LookupMaps(patcher.context.bytecodeContext.classes)
198-
every { with(patcher.context.bytecodeContext) { any<Set<Patch<*>>>().mergeExtensions() } } just runs
198+
every { with(patcher.context.bytecodeContext) { any<BytecodePatch>().mergeExtension() } } just runs
199199

200200
return runBlocking { patcher().toList() }
201201
}

0 commit comments

Comments
 (0)